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 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
25 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
26 #include <CoreServices/CoreServices.h>
28 #include <AudioUnit/AudioUnit.h>
29 #include <AudioToolbox/AudioToolbox.h>
34 #undef STDMETHODCALLTYPE
35 #include "coreaudio.h"
36 #include "wine/debug.h"
38 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
39 /* Define new AudioComponent Manager functions for compatibility's sake */
40 typedef Component AudioComponent
;
41 typedef ComponentDescription AudioComponentDescription
;
42 typedef ComponentInstance AudioComponentInstance
;
44 static inline AudioComponent
AudioComponentFindNext(AudioComponent ac
, AudioComponentDescription
*desc
)
46 return FindNextComponent(ac
, desc
);
49 static inline OSStatus
AudioComponentInstanceNew(AudioComponent ac
, AudioComponentInstance
*aci
)
51 return OpenAComponent(ac
, aci
);
54 static inline OSStatus
AudioComponentInstanceDispose(AudioComponentInstance aci
)
56 return CloseComponent(aci
);
60 #ifndef HAVE_AUGRAPHADDNODE
61 static inline OSStatus
AUGraphAddNode(AUGraph graph
, const AudioComponentDescription
*desc
, AUNode
*node
)
63 return AUGraphNewNode(graph
, desc
, 0, NULL
, node
);
66 static inline OSStatus
AUGraphNodeInfo(AUGraph graph
, AUNode node
, AudioComponentDescription
*desc
, AudioUnit
*au
)
68 return AUGraphGetNodeInfo(graph
, node
, desc
, 0, NULL
, au
);
72 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
73 WINE_DECLARE_DEBUG_CHANNEL(midi
);
75 static const char *streamDescription(const AudioStreamBasicDescription
* stream
)
77 return wine_dbg_sprintf("\n mSampleRate : %f\n mFormatID : %s\n mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
79 wine_dbgstr_fourcc(stream
->mFormatID
),
81 stream
->mBytesPerPacket
,
82 stream
->mFramesPerPacket
,
83 stream
->mBytesPerFrame
,
84 stream
->mChannelsPerFrame
,
85 stream
->mBitsPerChannel
);
88 extern OSStatus
CoreAudio_woAudioUnitIOProc(void *inRefCon
,
89 AudioUnitRenderActionFlags
*ioActionFlags
,
90 const AudioTimeStamp
*inTimeStamp
,
92 UInt32 inNumberFrames
,
93 AudioBufferList
*ioData
);
95 extern OSStatus
CoreAudio_wiAudioUnitIOProc(void *inRefCon
,
96 AudioUnitRenderActionFlags
*ioActionFlags
,
97 const AudioTimeStamp
*inTimeStamp
,
99 UInt32 inNumberFrames
,
100 AudioBufferList
*ioData
);
102 int AudioUnit_CreateDefaultAudioUnit(void *wwo
, AudioUnit
*au
)
106 AudioComponentDescription desc
;
107 AURenderCallbackStruct callbackStruct
;
111 desc
.componentType
= kAudioUnitType_Output
;
112 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
113 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
114 desc
.componentFlags
= 0;
115 desc
.componentFlagsMask
= 0;
117 comp
= AudioComponentFindNext(NULL
, &desc
);
121 err
= AudioComponentInstanceNew(comp
, au
);
122 if (err
!= noErr
|| *au
== NULL
)
125 callbackStruct
.inputProc
= CoreAudio_woAudioUnitIOProc
;
126 callbackStruct
.inputProcRefCon
= wwo
;
128 err
= AudioUnitSetProperty( *au
,
129 kAudioUnitProperty_SetRenderCallback
,
130 kAudioUnitScope_Input
,
133 sizeof(callbackStruct
));
134 return (err
== noErr
);
137 int AudioUnit_CloseAudioUnit(AudioUnit au
)
139 OSStatus err
= AudioComponentInstanceDispose(au
);
140 return (err
== noErr
);
143 int AudioUnit_InitializeWithStreamDescription(AudioUnit au
, AudioStreamBasicDescription
*stream
)
145 OSStatus err
= noErr
;
147 TRACE("input format: %s\n", streamDescription(stream
));
149 err
= AudioUnitSetProperty(au
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Input
,
150 0, stream
, sizeof(*stream
));
154 ERR("AudioUnitSetProperty return an error %s\n", wine_dbgstr_fourcc(err
));
158 err
= AudioUnitInitialize(au
);
161 ERR("AudioUnitInitialize return an error %s\n", wine_dbgstr_fourcc(err
));
167 int AudioUnit_SetVolume(AudioUnit au
, float left
, float right
)
169 OSStatus err
= noErr
;
172 if (!once
++) FIXME("independent left/right volume not implemented (%f, %f)\n", left
, right
);
174 err
= AudioUnitSetParameter(au
, kHALOutputParam_Volume
, kAudioUnitParameterFlag_Output
, 0, left
, 0);
178 ERR("AudioUnitSetParameter return an error %s\n", wine_dbgstr_fourcc(err
));
184 int AudioUnit_GetVolume(AudioUnit au
, float *left
, float *right
)
186 OSStatus err
= noErr
;
189 if (!once
++) FIXME("independent left/right volume not implemented\n");
191 err
= AudioUnitGetParameter(au
, kHALOutputParam_Volume
, kAudioUnitParameterFlag_Output
, 0, left
);
194 ERR("AudioUnitGetParameter return an error %s\n", wine_dbgstr_fourcc(err
));
202 /* FIXME: implement sample rate conversion on input */
203 int AudioUnit_GetInputDeviceSampleRate(void)
205 AudioDeviceID defaultInputDevice
;
207 AudioObjectPropertyAddress propertyAddress
;
211 param
= sizeof(defaultInputDevice
);
212 propertyAddress
.mSelector
= kAudioHardwarePropertyDefaultInputDevice
;
213 propertyAddress
.mScope
= kAudioObjectPropertyScopeGlobal
;
214 propertyAddress
.mElement
= kAudioObjectPropertyElementMaster
;
215 err
= AudioObjectGetPropertyData(kAudioObjectSystemObject
, &propertyAddress
, 0, NULL
, ¶m
, &defaultInputDevice
);
216 if (err
!= noErr
|| defaultInputDevice
== kAudioDeviceUnknown
)
218 ERR("Couldn't get the default audio input device ID: %08lx\n", err
);
222 param
= sizeof(sampleRate
);
223 propertyAddress
.mSelector
= kAudioDevicePropertyNominalSampleRate
;
224 propertyAddress
.mScope
= kAudioDevicePropertyScopeInput
;
225 err
= AudioObjectGetPropertyData(defaultInputDevice
, &propertyAddress
, 0, NULL
, ¶m
, &sampleRate
);
228 ERR("Couldn't get the device sample rate: %08lx\n", err
);
236 int AudioUnit_CreateInputUnit(void* wwi
, AudioUnit
* out_au
,
237 WORD nChannels
, DWORD nSamplesPerSec
, WORD wBitsPerSample
,
238 UInt32
* outFrameCount
)
240 OSStatus err
= noErr
;
241 AudioComponentDescription description
;
242 AudioComponent component
;
245 AudioObjectPropertyAddress propertyAddress
;
246 AURenderCallbackStruct callback
;
247 AudioDeviceID defaultInputDevice
;
248 AudioStreamBasicDescription desiredFormat
;
253 ERR("Invalid parameter\n");
257 /* Open the AudioOutputUnit */
258 description
.componentType
= kAudioUnitType_Output
;
259 description
.componentSubType
= kAudioUnitSubType_HALOutput
;
260 description
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
261 description
.componentFlags
= 0;
262 description
.componentFlagsMask
= 0;
264 component
= AudioComponentFindNext(NULL
, &description
);
267 ERR("AudioComponentFindNext(kAudioUnitSubType_HALOutput) failed\n");
271 err
= AudioComponentInstanceNew(component
, &au
);
272 if (err
!= noErr
|| au
== NULL
)
274 ERR("AudioComponentInstanceNew failed: %08lx\n", err
);
278 /* Configure the AudioOutputUnit */
279 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
280 * to the device. Bus 1 is input from the device to the app. Each bus
281 * has two ends (AKA scopes). Data goes from the input scope to the
282 * output scope. The terminology is somewhat confusing because the terms
283 * "input" and "output" have two meanings. Here's a summary:
285 * Bus 0, input scope: refers to the source of data to be output as sound
286 * Bus 0, output scope: refers to the actual sound output device
287 * Bus 1, input scope: refers to the actual sound input device
288 * Bus 1, output scope: refers to the destination of data received by the input device
291 /* Enable input on the AUHAL */
293 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Input
, 1, ¶m
, sizeof(param
));
296 ERR("Couldn't enable input on AUHAL: %08lx\n", err
);
300 /* Disable Output on the AUHAL */
302 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_EnableIO
, kAudioUnitScope_Output
, 0, ¶m
, sizeof(param
));
305 ERR("Couldn't disable output on AUHAL: %08lx\n", err
);
309 /* Find the default input device */
310 param
= sizeof(defaultInputDevice
);
311 propertyAddress
.mSelector
= kAudioHardwarePropertyDefaultInputDevice
;
312 propertyAddress
.mScope
= kAudioObjectPropertyScopeGlobal
;
313 propertyAddress
.mElement
= kAudioObjectPropertyElementMaster
;
314 err
= AudioObjectGetPropertyData(kAudioObjectSystemObject
, &propertyAddress
, 0, NULL
, ¶m
, &defaultInputDevice
);
315 if (err
!= noErr
|| defaultInputDevice
== kAudioDeviceUnknown
)
317 ERR("Couldn't get the default audio device ID: %08lx\n", err
);
321 /* Set the current device to the default input device. */
322 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_CurrentDevice
, kAudioUnitScope_Global
, 0, &defaultInputDevice
, sizeof(defaultInputDevice
));
325 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err
);
329 /* Setup render callback */
330 /* This will be called when the AUHAL has input data. However, it won't
331 * be passed the data itself. The callback will have to all AudioUnitRender. */
332 callback
.inputProc
= CoreAudio_wiAudioUnitIOProc
;
333 callback
.inputProcRefCon
= wwi
;
334 err
= AudioUnitSetProperty(au
, kAudioOutputUnitProperty_SetInputCallback
, kAudioUnitScope_Global
, 0, &callback
, sizeof(callback
));
337 ERR("Couldn't set input callback of AUHAL: %08lx\n", err
);
341 /* Setup the desired data format. */
342 /* FIXME: implement sample rate conversion on input. We shouldn't set
343 * the mSampleRate of this to the desired sample rate. We need to query
344 * the input device and use that. If they don't match, we need to set up
345 * an AUConverter to do the sample rate conversion on a separate thread. */
346 desiredFormat
.mFormatID
= kAudioFormatLinearPCM
;
347 desiredFormat
.mFormatFlags
= kLinearPCMFormatFlagIsPacked
;
348 if (wBitsPerSample
!= 8)
349 desiredFormat
.mFormatFlags
|= kLinearPCMFormatFlagIsSignedInteger
;
350 desiredFormat
.mSampleRate
= nSamplesPerSec
;
351 desiredFormat
.mChannelsPerFrame
= nChannels
;
352 desiredFormat
.mFramesPerPacket
= 1;
353 desiredFormat
.mBitsPerChannel
= wBitsPerSample
;
354 desiredFormat
.mBytesPerFrame
= desiredFormat
.mBitsPerChannel
* desiredFormat
.mChannelsPerFrame
/ 8;
355 desiredFormat
.mBytesPerPacket
= desiredFormat
.mBytesPerFrame
* desiredFormat
.mFramesPerPacket
;
357 /* Set the AudioOutputUnit output data format */
358 err
= AudioUnitSetProperty(au
, kAudioUnitProperty_StreamFormat
, kAudioUnitScope_Output
, 1, &desiredFormat
, sizeof(desiredFormat
));
361 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err
);
365 /* Get the number of frames in the IO buffer(s) */
366 param
= sizeof(*outFrameCount
);
367 err
= AudioUnitGetProperty(au
, kAudioDevicePropertyBufferFrameSize
, kAudioUnitScope_Global
, 0, outFrameCount
, ¶m
);
370 ERR("Failed to get audio sample size: %08lx\n", err
);
374 TRACE("Frame count: %lu\n", *outFrameCount
);
376 /* Initialize the AU */
377 err
= AudioUnitInitialize(au
);
380 ERR("Failed to initialize AU: %08lx\n", err
);
390 AudioComponentInstanceDispose(au
);
397 int SynthUnit_CreateDefaultSynthUnit(AUGraph
*graph
, AudioUnit
*synth
)
400 AudioComponentDescription desc
;
404 err
= NewAUGraph(graph
);
407 ERR_(midi
)("NewAUGraph return %s\n", wine_dbgstr_fourcc(err
));
411 desc
.componentManufacturer
= kAudioUnitManufacturer_Apple
;
412 desc
.componentFlags
= 0;
413 desc
.componentFlagsMask
= 0;
415 /* create synth node */
416 desc
.componentType
= kAudioUnitType_MusicDevice
;
417 desc
.componentSubType
= kAudioUnitSubType_DLSSynth
;
419 err
= AUGraphAddNode(*graph
, &desc
, &synthNode
);
422 ERR_(midi
)("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(err
));
426 /* create out node */
427 desc
.componentType
= kAudioUnitType_Output
;
428 desc
.componentSubType
= kAudioUnitSubType_DefaultOutput
;
430 err
= AUGraphAddNode(*graph
, &desc
, &outNode
);
433 ERR_(midi
)("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(err
));
437 err
= AUGraphOpen(*graph
);
440 ERR_(midi
)("AUGraphOpen return %s\n", wine_dbgstr_fourcc(err
));
444 /* connecting the nodes */
445 err
= AUGraphConnectNodeInput(*graph
, synthNode
, 0, outNode
, 0);
448 ERR_(midi
)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", wine_dbgstr_fourcc(err
));
452 /* Get the synth unit */
453 err
= AUGraphNodeInfo(*graph
, synthNode
, 0, synth
);
456 ERR_(midi
)("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(err
));
463 int SynthUnit_Initialize(AudioUnit synth
, AUGraph graph
)
465 OSStatus err
= noErr
;
467 err
= AUGraphInitialize(graph
);
470 ERR_(midi
)("AUGraphInitialize(%p) return %s\n", graph
, wine_dbgstr_fourcc(err
));
474 err
= AUGraphStart(graph
);
477 ERR_(midi
)("AUGraphStart(%p) return %s\n", graph
, wine_dbgstr_fourcc(err
));
484 int SynthUnit_Close(AUGraph graph
)
486 OSStatus err
= noErr
;
488 err
= AUGraphStop(graph
);
491 ERR_(midi
)("AUGraphStop(%p) return %s\n", graph
, wine_dbgstr_fourcc(err
));
495 err
= DisposeAUGraph(graph
);
498 ERR_(midi
)("DisposeAUGraph(%p) return %s\n", graph
, wine_dbgstr_fourcc(err
));