mmdevapi: Reimplement using a driver system.
[wine/multimedia.git] / dlls / winecoreaudio.drv / audiounit.c
blobbbe565f8d083d735e749662bc660a71cec50f103
1 /*
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
21 #include "config.h"
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
25 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
26 #include <CoreServices/CoreServices.h>
27 #endif
28 #include <AudioUnit/AudioUnit.h>
29 #include <AudioToolbox/AudioToolbox.h>
30 #undef ULONG
31 #undef HRESULT
33 #undef DPRINTF
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);
58 #endif
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);
70 #endif
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",
78 stream->mSampleRate,
79 wine_dbgstr_fourcc(stream->mFormatID),
80 stream->mFormatFlags,
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,
91 UInt32 inBusNumber,
92 UInt32 inNumberFrames,
93 AudioBufferList *ioData);
95 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
96 AudioUnitRenderActionFlags *ioActionFlags,
97 const AudioTimeStamp *inTimeStamp,
98 UInt32 inBusNumber,
99 UInt32 inNumberFrames,
100 AudioBufferList *ioData);
102 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
104 OSStatus err;
105 AudioComponent comp;
106 AudioComponentDescription desc;
107 AURenderCallbackStruct callbackStruct;
109 TRACE("\n");
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);
118 if (comp == NULL)
119 return 0;
121 err = AudioComponentInstanceNew(comp, au);
122 if (err != noErr || *au == NULL)
123 return 0;
125 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
126 callbackStruct.inputProcRefCon = wwo;
128 err = AudioUnitSetProperty( *au,
129 kAudioUnitProperty_SetRenderCallback,
130 kAudioUnitScope_Input,
132 &callbackStruct,
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));
152 if (err != noErr)
154 ERR("AudioUnitSetProperty return an error %s\n", wine_dbgstr_fourcc(err));
155 return 0;
158 err = AudioUnitInitialize(au);
159 if (err != noErr)
161 ERR("AudioUnitInitialize return an error %s\n", wine_dbgstr_fourcc(err));
162 return 0;
164 return 1;
167 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
169 OSStatus err = noErr;
170 static int once;
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);
176 if (err != noErr)
178 ERR("AudioUnitSetParameter return an error %s\n", wine_dbgstr_fourcc(err));
179 return 0;
181 return 1;
184 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
186 OSStatus err = noErr;
187 static int once;
189 if (!once++) FIXME("independent left/right volume not implemented\n");
191 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
192 if (err != noErr)
194 ERR("AudioUnitGetParameter return an error %s\n", wine_dbgstr_fourcc(err));
195 return 0;
197 *right = *left;
198 return 1;
202 /* FIXME: implement sample rate conversion on input */
203 int AudioUnit_GetInputDeviceSampleRate(void)
205 AudioDeviceID defaultInputDevice;
206 UInt32 param;
207 AudioObjectPropertyAddress propertyAddress;
208 Float64 sampleRate;
209 OSStatus err;
211 param = sizeof(defaultInputDevice);
212 propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
213 propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
214 propertyAddress.mElement = kAudioObjectPropertyElementMaster;
215 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &param, &defaultInputDevice);
216 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
218 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
219 return 0;
222 param = sizeof(sampleRate);
223 propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
224 propertyAddress.mScope = kAudioDevicePropertyScopeInput;
225 err = AudioObjectGetPropertyData(defaultInputDevice, &propertyAddress, 0, NULL, &param, &sampleRate);
226 if (err != noErr)
228 ERR("Couldn't get the device sample rate: %08lx\n", err);
229 return 0;
232 return sampleRate;
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;
243 AudioUnit au;
244 UInt32 param;
245 AudioObjectPropertyAddress propertyAddress;
246 AURenderCallbackStruct callback;
247 AudioDeviceID defaultInputDevice;
248 AudioStreamBasicDescription desiredFormat;
251 if (!outFrameCount)
253 ERR("Invalid parameter\n");
254 return 0;
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);
265 if (!component)
267 ERR("AudioComponentFindNext(kAudioUnitSubType_HALOutput) failed\n");
268 return 0;
271 err = AudioComponentInstanceNew(component, &au);
272 if (err != noErr || au == NULL)
274 ERR("AudioComponentInstanceNew failed: %08lx\n", err);
275 return 0;
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 */
292 param = 1;
293 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
294 if (err != noErr)
296 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
297 goto error;
300 /* Disable Output on the AUHAL */
301 param = 0;
302 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
303 if (err != noErr)
305 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
306 goto error;
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, &param, &defaultInputDevice);
315 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
317 ERR("Couldn't get the default audio device ID: %08lx\n", err);
318 goto error;
321 /* Set the current device to the default input device. */
322 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
323 if (err != noErr)
325 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
326 goto error;
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));
335 if (err != noErr)
337 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
338 goto error;
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));
359 if (err != noErr)
361 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
362 goto error;
365 /* Get the number of frames in the IO buffer(s) */
366 param = sizeof(*outFrameCount);
367 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
368 if (err != noErr)
370 ERR("Failed to get audio sample size: %08lx\n", err);
371 goto error;
374 TRACE("Frame count: %lu\n", *outFrameCount);
376 /* Initialize the AU */
377 err = AudioUnitInitialize(au);
378 if (err != noErr)
380 ERR("Failed to initialize AU: %08lx\n", err);
381 goto error;
384 *out_au = au;
386 return 1;
388 error:
389 if (au)
390 AudioComponentInstanceDispose(au);
391 return 0;
395 * MIDI Synth Unit
397 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
399 OSStatus err;
400 AudioComponentDescription desc;
401 AUNode synthNode;
402 AUNode outNode;
404 err = NewAUGraph(graph);
405 if (err != noErr)
407 ERR_(midi)("NewAUGraph return %s\n", wine_dbgstr_fourcc(err));
408 return 0;
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);
420 if (err != noErr)
422 ERR_(midi)("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(err));
423 return 0;
426 /* create out node */
427 desc.componentType = kAudioUnitType_Output;
428 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
430 err = AUGraphAddNode(*graph, &desc, &outNode);
431 if (err != noErr)
433 ERR_(midi)("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(err));
434 return 0;
437 err = AUGraphOpen(*graph);
438 if (err != noErr)
440 ERR_(midi)("AUGraphOpen return %s\n", wine_dbgstr_fourcc(err));
441 return 0;
444 /* connecting the nodes */
445 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
446 if (err != noErr)
448 ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", wine_dbgstr_fourcc(err));
449 return 0;
452 /* Get the synth unit */
453 err = AUGraphNodeInfo(*graph, synthNode, 0, synth);
454 if (err != noErr)
456 ERR_(midi)("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(err));
457 return 0;
460 return 1;
463 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
465 OSStatus err = noErr;
467 err = AUGraphInitialize(graph);
468 if (err != noErr)
470 ERR_(midi)("AUGraphInitialize(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
471 return 0;
474 err = AUGraphStart(graph);
475 if (err != noErr)
477 ERR_(midi)("AUGraphStart(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
478 return 0;
481 return 1;
484 int SynthUnit_Close(AUGraph graph)
486 OSStatus err = noErr;
488 err = AUGraphStop(graph);
489 if (err != noErr)
491 ERR_(midi)("AUGraphStop(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
492 return 0;
495 err = DisposeAUGraph(graph);
496 if (err != noErr)
498 ERR_(midi)("DisposeAUGraph(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
499 return 0;
502 return 1;