2 * Wine Driver for CoreAudio / AudioUnit
4 * Copyright 2005, 2006 Emmanuel Maillard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
25 #include <AudioUnit/AudioUnit.h>
26 #include <AudioToolbox/AudioToolbox.h>
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(wave);
31 WINE_DECLARE_DEBUG_CHANNEL(midi);
33 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
34 AudioUnitRenderActionFlags *ioActionFlags,
35 const AudioTimeStamp *inTimeStamp,
37 UInt32 inNumberFrames,
38 AudioBufferList *ioData);
40 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
41 AudioUnitRenderActionFlags *ioActionFlags,
42 const AudioTimeStamp *inTimeStamp,
44 UInt32 inNumberFrames,
45 AudioBufferList *ioData);
47 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
51 ComponentDescription desc;
52 AURenderCallbackStruct callbackStruct;
54 desc.componentType = kAudioUnitType_Output;
55 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
56 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
57 desc.componentFlags = 0;
58 desc.componentFlagsMask = 0;
60 comp = FindNextComponent(NULL, &desc);
64 err = OpenAComponent(comp, au);
68 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
69 callbackStruct.inputProcRefCon = wwo;
71 err = AudioUnitSetProperty( *au,
72 kAudioUnitProperty_SetRenderCallback,
73 kAudioUnitScope_Input,
76 sizeof(callbackStruct));
77 return (err == noErr);
80 int AudioUnit_CloseAudioUnit(AudioUnit au)
82 OSStatus err = CloseComponent(au);
83 return (err == noErr);
86 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
90 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
91 0, stream, sizeof(*stream));
95 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
99 err = AudioUnitInitialize(au);
102 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
108 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
110 OSStatus err = noErr;
112 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
116 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
122 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
124 OSStatus err = noErr;
126 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
129 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
137 /* FIXME: implement sample rate conversion on input */
138 int AudioUnit_GetInputDeviceSampleRate(void)
140 AudioDeviceID defaultInputDevice;
145 param = sizeof(defaultInputDevice);
146 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &defaultInputDevice);
147 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
149 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
153 param = sizeof(sampleRate);
154 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, ¶m, &sampleRate);
157 ERR("Couldn't get the device sample rate: %08lx\n", err);
165 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
166 WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
167 UInt32* outFrameCount)
169 OSStatus err = noErr;
170 ComponentDescription description;
174 AURenderCallbackStruct callback;
175 AudioDeviceID defaultInputDevice;
176 AudioStreamBasicDescription desiredFormat;
181 ERR("Invalid parameter\n");
185 /* Open the AudioOutputUnit */
186 description.componentType = kAudioUnitType_Output;
187 description.componentSubType = kAudioUnitSubType_HALOutput;
188 description.componentManufacturer = kAudioUnitManufacturer_Apple;
189 description.componentFlags = 0;
190 description.componentFlagsMask = 0;
192 component = FindNextComponent(NULL, &description);
195 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
199 err = OpenAComponent(component, &au);
200 if (err != noErr || au == NULL)
202 ERR("OpenAComponent failed: %08lx\n", err);
206 /* Configure the AudioOutputUnit */
207 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
208 * to the device. Bus 1 is input from the device to the app. Each bus
209 * has two ends (AKA scopes). Data goes from the input scope to the
210 * output scope. The terminology is somewhat confusing because the terms
211 * "input" and "output" have two meanings. Here's a summary:
213 * Bus 0, input scope: refers to the source of data to be output as sound
214 * Bus 0, output scope: refers to the actual sound output device
215 * Bus 1, input scope: refers to the actual sound input device
216 * Bus 1, output scope: refers to the destination of data received by the input device
219 /* Enable input on the AUHAL */
221 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(param));
224 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
228 /* Disable Output on the AUHAL */
230 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, ¶m, sizeof(param));
233 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
237 /* Find the default input device */
238 param = sizeof(defaultInputDevice);
239 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &defaultInputDevice);
240 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
242 ERR("Couldn't get the default audio device ID: %08lx\n", err);
246 /* Set the current device to the default input device. */
247 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
250 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
254 /* Setup render callback */
255 /* This will be called when the AUHAL has input data. However, it won't
256 * be passed the data itself. The callback will have to all AudioUnitRender. */
257 callback.inputProc = CoreAudio_wiAudioUnitIOProc;
258 callback.inputProcRefCon = wwi;
259 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
262 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
266 /* Setup the desired data format. */
267 /* FIXME: implement sample rate conversion on input. We shouldn't set
268 * the mSampleRate of this to the desired sample rate. We need to query
269 * the input device and use that. If they don't match, we need to set up
270 * an AUConverter to do the sample rate conversion on a separate thread. */
271 desiredFormat.mFormatID = kAudioFormatLinearPCM;
272 desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
273 if (wBitsPerSample != 8)
274 desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
275 desiredFormat.mSampleRate = nSamplesPerSec;
276 desiredFormat.mChannelsPerFrame = nChannels;
277 desiredFormat.mFramesPerPacket = 1;
278 desiredFormat.mBitsPerChannel = wBitsPerSample;
279 desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
280 desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
282 /* Set the AudioOutputUnit output data format */
283 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
286 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
290 /* Get the number of frames in the IO buffer(s) */
291 param = sizeof(*outFrameCount);
292 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, ¶m);
295 ERR("Failed to get audio sample size: %08lx\n", err);
299 TRACE("Frame count: %lu\n", *outFrameCount);
301 /* Initialize the AU */
302 err = AudioUnitInitialize(au);
305 ERR("Failed to initialize AU: %08lx\n", err);
322 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
325 ComponentDescription desc;
329 err = NewAUGraph(graph);
332 ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
336 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
337 desc.componentFlags = 0;
338 desc.componentFlagsMask = 0;
340 /* create synth node */
341 desc.componentType = kAudioUnitType_MusicDevice;
342 desc.componentSubType = kAudioUnitSubType_DLSSynth;
344 err = AUGraphNewNode(*graph, &desc, 0, NULL, &synthNode);
347 ERR_(midi)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
351 /* create out node */
352 desc.componentType = kAudioUnitType_Output;
353 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
355 err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
358 ERR_(midi)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
362 err = AUGraphOpen(*graph);
365 ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
369 /* connecting the nodes */
370 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
373 ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
377 /* Get the synth unit */
378 err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
381 ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
388 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
390 OSStatus err = noErr;
392 err = AUGraphInitialize(graph);
395 ERR_(midi)("AUGraphInitialize(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
399 err = AUGraphStart(graph);
402 ERR_(midi)("AUGraphStart(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
409 int SynthUnit_Close(AUGraph graph)
411 OSStatus err = noErr;
413 err = AUGraphStop(graph);
416 ERR_(midi)("AUGraphStop(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
420 err = DisposeAUGraph(graph);
423 ERR_(midi)("DisposeAUGraph(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);