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 #define ULONG CoreFoundation_ULONG
26 #define HRESULT CoreFoundation_HRESULT
27 #include <CoreServices/CoreServices.h>
28 #include <AudioUnit/AudioUnit.h>
29 #include <AudioToolbox/AudioToolbox.h>
34 #undef STDMETHODCALLTYPE
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
38 WINE_DECLARE_DEBUG_CHANNEL(midi
);
40 extern OSStatus
CoreAudio_woAudioUnitIOProc(void *inRefCon
,
41 AudioUnitRenderActionFlags
*ioActionFlags
,
42 const AudioTimeStamp
*inTimeStamp
,
44 UInt32 inNumberFrames
,
45 AudioBufferList
*ioData
);
47 extern OSStatus
CoreAudio_wiAudioUnitIOProc(void *inRefCon
,
48 AudioUnitRenderActionFlags
*ioActionFlags
,
49 const AudioTimeStamp
*inTimeStamp
,
51 UInt32 inNumberFrames
,
52 AudioBufferList
*ioData
);
54 int AudioUnit_CreateDefaultAudioUnit(void *wwo
, AudioUnit
*au
)
58 ComponentDescription desc
;
59 AURenderCallbackStruct callbackStruct
;
61 desc
.componentType
= kAudioUnitType_Output
;
62 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
63 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
64 desc
.componentFlags
= 0;
65 desc
.componentFlagsMask
= 0;
67 comp
= FindNextComponent(NULL
, &desc
);
71 err
= OpenAComponent(comp
, au
);
75 callbackStruct
.inputProc
= CoreAudio_woAudioUnitIOProc
;
76 callbackStruct
.inputProcRefCon
= wwo
;
78 err
= AudioUnitSetProperty( *au
,
79 kAudioUnitProperty_SetRenderCallback
,
80 kAudioUnitScope_Input
,
83 sizeof(callbackStruct
));
84 return (err
== noErr
);
87 int AudioUnit_CloseAudioUnit(AudioUnit au
)
89 OSStatus err
= CloseComponent(au
);
90 return (err
== noErr
);
93 int AudioUnit_InitializeWithStreamDescription(AudioUnit au
, AudioStreamBasicDescription
*stream
)
97 err
= AudioUnitSetProperty(au
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
,
98 0, stream
, sizeof(*stream
));
102 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
106 err
= AudioUnitInitialize(au
);
109 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
115 int AudioUnit_SetVolume(AudioUnit au
, float left
, float right
)
117 OSStatus err
= noErr
;
119 err
= AudioUnitSetParameter(au
, kHALOutputParam_Volume
, kAudioUnitParameterFlag_Output
, 0, left
, 0);
123 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
129 int AudioUnit_GetVolume(AudioUnit au
, float *left
, float *right
)
131 OSStatus err
= noErr
;
133 err
= AudioUnitGetParameter(au
, kHALOutputParam_Volume
, kAudioUnitParameterFlag_Output
, 0, left
);
136 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
144 /* FIXME: implement sample rate conversion on input */
145 int AudioUnit_GetInputDeviceSampleRate(void)
147 AudioDeviceID defaultInputDevice
;
152 param
= sizeof(defaultInputDevice
);
153 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, ¶m
, &defaultInputDevice
);
154 if (err
!= noErr
|| defaultInputDevice
== kAudioDeviceUnknown
)
156 ERR("Couldn't get the default audio input device ID: %08lx\n", err
);
160 param
= sizeof(sampleRate
);
161 err
= AudioDeviceGetProperty(defaultInputDevice
, 0, 1, kAudioDevicePropertyNominalSampleRate
, ¶m
, &sampleRate
);
164 ERR("Couldn't get the device sample rate: %08lx\n", err
);
172 int AudioUnit_CreateInputUnit(void* wwi
, AudioUnit
* out_au
,
173 WORD nChannels
, DWORD nSamplesPerSec
, WORD wBitsPerSample
,
174 UInt32
* outFrameCount
)
176 OSStatus err
= noErr
;
177 ComponentDescription description
;
181 AURenderCallbackStruct callback
;
182 AudioDeviceID defaultInputDevice
;
183 AudioStreamBasicDescription desiredFormat
;
188 ERR("Invalid parameter\n");
192 /* Open the AudioOutputUnit */
193 description
.componentType
= kAudioUnitType_Output
;
194 description
.componentSubType
= kAudioUnitSubType_HALOutput
;
195 description
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
196 description
.componentFlags
= 0;
197 description
.componentFlagsMask
= 0;
199 component
= FindNextComponent(NULL
, &description
);
202 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
206 err
= OpenAComponent(component
, &au
);
207 if (err
!= noErr
|| au
== NULL
)
209 ERR("OpenAComponent failed: %08lx\n", err
);
213 /* Configure the AudioOutputUnit */
214 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
215 * to the device. Bus 1 is input from the device to the app. Each bus
216 * has two ends (AKA scopes). Data goes from the input scope to the
217 * output scope. The terminology is somewhat confusing because the terms
218 * "input" and "output" have two meanings. Here's a summary:
220 * Bus 0, input scope: refers to the source of data to be output as sound
221 * Bus 0, output scope: refers to the actual sound output device
222 * Bus 1, input scope: refers to the actual sound input device
223 * Bus 1, output scope: refers to the destination of data received by the input device
226 /* Enable input on the AUHAL */
228 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, ¶m
, sizeof(param
));
231 ERR("Couldn't enable input on AUHAL: %08lx\n", err
);
235 /* Disable Output on the AUHAL */
237 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, ¶m
, sizeof(param
));
240 ERR("Couldn't disable output on AUHAL: %08lx\n", err
);
244 /* Find the default input device */
245 param
= sizeof(defaultInputDevice
);
246 err
= AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice
, ¶m
, &defaultInputDevice
);
247 if (err
!= noErr
|| defaultInputDevice
== kAudioDeviceUnknown
)
249 ERR("Couldn't get the default audio device ID: %08lx\n", err
);
253 /* Set the current device to the default input device. */
254 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &defaultInputDevice
, sizeof(defaultInputDevice
));
257 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err
);
261 /* Setup render callback */
262 /* This will be called when the AUHAL has input data. However, it won't
263 * be passed the data itself. The callback will have to all AudioUnitRender. */
264 callback
.inputProc
= CoreAudio_wiAudioUnitIOProc
;
265 callback
.inputProcRefCon
= wwi
;
266 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &callback
, sizeof(callback
));
269 ERR("Couldn't set input callback of AUHAL: %08lx\n", err
);
273 /* Setup the desired data format. */
274 /* FIXME: implement sample rate conversion on input. We shouldn't set
275 * the mSampleRate of this to the desired sample rate. We need to query
276 * the input device and use that. If they don't match, we need to set up
277 * an AUConverter to do the sample rate conversion on a separate thread. */
278 desiredFormat
.mFormatID
= kAudioFormatLinearPCM
;
279 desiredFormat
.mFormatFlags
= kLinearPCMFormatFlagIsPacked
;
280 if (wBitsPerSample
!= 8)
281 desiredFormat
.mFormatFlags
|= kLinearPCMFormatFlagIsSignedInteger
;
282 desiredFormat
.mSampleRate
= nSamplesPerSec
;
283 desiredFormat
.mChannelsPerFrame
= nChannels
;
284 desiredFormat
.mFramesPerPacket
= 1;
285 desiredFormat
.mBitsPerChannel
= wBitsPerSample
;
286 desiredFormat
.mBytesPerFrame
= desiredFormat
.mBitsPerChannel
* desiredFormat
.mChannelsPerFrame
/ 8;
287 desiredFormat
.mBytesPerPacket
= desiredFormat
.mBytesPerFrame
* desiredFormat
.mFramesPerPacket
;
289 /* Set the AudioOutputUnit output data format */
290 err
= AudioUnitSetProperty(au
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &desiredFormat
, sizeof(desiredFormat
));
293 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err
);
297 /* Get the number of frames in the IO buffer(s) */
298 param
= sizeof(*outFrameCount
);
299 err
= AudioUnitGetProperty(au
, kAudioDevicePropertyBufferFrameSize
, kAudioUnitScope_Global
, 0, outFrameCount
, ¶m
);
302 ERR("Failed to get audio sample size: %08lx\n", err
);
306 TRACE("Frame count: %lu\n", *outFrameCount
);
308 /* Initialize the AU */
309 err
= AudioUnitInitialize(au
);
312 ERR("Failed to initialize AU: %08lx\n", err
);
329 int SynthUnit_CreateDefaultSynthUnit(AUGraph
*graph
, AudioUnit
*synth
)
332 ComponentDescription desc
;
336 err
= NewAUGraph(graph
);
339 ERR_(midi
)("NewAUGraph return %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
343 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
344 desc
.componentFlags
= 0;
345 desc
.componentFlagsMask
= 0;
347 /* create synth node */
348 desc
.componentType
= kAudioUnitType_MusicDevice
;
349 desc
.componentSubType
= kAudioUnitSubType_DLSSynth
;
351 err
= AUGraphNewNode(*graph
, &desc
, 0, NULL
, &synthNode
);
354 ERR_(midi
)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
358 /* create out node */
359 desc
.componentType
= kAudioUnitType_Output
;
360 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
362 err
= AUGraphNewNode(*graph
, &desc
, 0, NULL
, &outNode
);
365 ERR_(midi
)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
369 err
= AUGraphOpen(*graph
);
372 ERR_(midi
)("AUGraphOpen return %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
376 /* connecting the nodes */
377 err
= AUGraphConnectNodeInput(*graph
, synthNode
, 0, outNode
, 0);
380 ERR_(midi
)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
384 /* Get the synth unit */
385 err
= AUGraphGetNodeInfo(*graph
, synthNode
, 0, 0, 0, synth
);
388 ERR_(midi
)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
395 int SynthUnit_Initialize(AudioUnit synth
, AUGraph graph
)
397 OSStatus err
= noErr
;
399 err
= AUGraphInitialize(graph
);
402 ERR_(midi
)("AUGraphInitialize(%p) return %c%c%c%c\n", graph
, (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
406 err
= AUGraphStart(graph
);
409 ERR_(midi
)("AUGraphStart(%p) return %c%c%c%c\n", graph
, (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
416 int SynthUnit_Close(AUGraph graph
)
418 OSStatus err
= noErr
;
420 err
= AUGraphStop(graph
);
423 ERR_(midi
)("AUGraphStop(%p) return %c%c%c%c\n", graph
, (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);
427 err
= DisposeAUGraph(graph
);
430 ERR_(midi
)("DisposeAUGraph(%p) return %c%c%c%c\n", graph
, (char) (err
>> 24), (char) (err
>> 16), (char) (err
>> 8), (char) err
);