dplayx: Code to forward player creation
[wine/gsoc_dplay.git] / dlls / winecoreaudio.drv / audiounit.c
blob27f8f60d22808e6c1f267638c2ac2d481e89af0a
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 #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>
30 #undef ULONG
31 #undef HRESULT
33 #undef DPRINTF
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,
43 UInt32 inBusNumber,
44 UInt32 inNumberFrames,
45 AudioBufferList *ioData);
47 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
48 AudioUnitRenderActionFlags *ioActionFlags,
49 const AudioTimeStamp *inTimeStamp,
50 UInt32 inBusNumber,
51 UInt32 inNumberFrames,
52 AudioBufferList *ioData);
54 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
56 OSStatus err;
57 Component comp;
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);
68 if (comp == NULL)
69 return 0;
71 err = OpenAComponent(comp, au);
72 if (comp == NULL)
73 return 0;
75 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
76 callbackStruct.inputProcRefCon = wwo;
78 err = AudioUnitSetProperty( *au,
79 kAudioUnitProperty_SetRenderCallback,
80 kAudioUnitScope_Input,
81 0,
82 &callbackStruct,
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)
95 OSStatus err = noErr;
97 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
98 0, stream, sizeof(*stream));
100 if (err != noErr)
102 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
103 return 0;
106 err = AudioUnitInitialize(au);
107 if (err != noErr)
109 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
110 return 0;
112 return 1;
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);
121 if (err != noErr)
123 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
124 return 0;
126 return 1;
129 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
131 OSStatus err = noErr;
133 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
134 if (err != noErr)
136 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
137 return 0;
139 *right = *left;
140 return 1;
144 /* FIXME: implement sample rate conversion on input */
145 int AudioUnit_GetInputDeviceSampleRate(void)
147 AudioDeviceID defaultInputDevice;
148 UInt32 param;
149 Float64 sampleRate;
150 OSStatus err;
152 param = sizeof(defaultInputDevice);
153 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
154 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
156 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
157 return 0;
160 param = sizeof(sampleRate);
161 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
162 if (err != noErr)
164 ERR("Couldn't get the device sample rate: %08lx\n", err);
165 return 0;
168 return sampleRate;
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;
178 Component component;
179 AudioUnit au;
180 UInt32 param;
181 AURenderCallbackStruct callback;
182 AudioDeviceID defaultInputDevice;
183 AudioStreamBasicDescription desiredFormat;
186 if (!outFrameCount)
188 ERR("Invalid parameter\n");
189 return 0;
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);
200 if (!component)
202 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
203 return 0;
206 err = OpenAComponent(component, &au);
207 if (err != noErr || au == NULL)
209 ERR("OpenAComponent failed: %08lx\n", err);
210 return 0;
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 */
227 param = 1;
228 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
229 if (err != noErr)
231 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
232 goto error;
235 /* Disable Output on the AUHAL */
236 param = 0;
237 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
238 if (err != noErr)
240 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
241 goto error;
244 /* Find the default input device */
245 param = sizeof(defaultInputDevice);
246 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
247 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
249 ERR("Couldn't get the default audio device ID: %08lx\n", err);
250 goto error;
253 /* Set the current device to the default input device. */
254 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
255 if (err != noErr)
257 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
258 goto error;
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));
267 if (err != noErr)
269 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
270 goto error;
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));
291 if (err != noErr)
293 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
294 goto error;
297 /* Get the number of frames in the IO buffer(s) */
298 param = sizeof(*outFrameCount);
299 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
300 if (err != noErr)
302 ERR("Failed to get audio sample size: %08lx\n", err);
303 goto error;
306 TRACE("Frame count: %lu\n", *outFrameCount);
308 /* Initialize the AU */
309 err = AudioUnitInitialize(au);
310 if (err != noErr)
312 ERR("Failed to initialize AU: %08lx\n", err);
313 goto error;
316 *out_au = au;
318 return 1;
320 error:
321 if (au)
322 CloseComponent(au);
323 return 0;
327 * MIDI Synth Unit
329 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
331 OSStatus err;
332 ComponentDescription desc;
333 AUNode synthNode;
334 AUNode outNode;
336 err = NewAUGraph(graph);
337 if (err != noErr)
339 ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
340 return 0;
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);
352 if (err != noErr)
354 ERR_(midi)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
355 return 0;
358 /* create out node */
359 desc.componentType = kAudioUnitType_Output;
360 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
362 err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
363 if (err != noErr)
365 ERR_(midi)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
366 return 0;
369 err = AUGraphOpen(*graph);
370 if (err != noErr)
372 ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
373 return 0;
376 /* connecting the nodes */
377 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
378 if (err != noErr)
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);
381 return 0;
384 /* Get the synth unit */
385 err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
386 if (err != noErr)
388 ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
389 return 0;
392 return 1;
395 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
397 OSStatus err = noErr;
399 err = AUGraphInitialize(graph);
400 if (err != noErr)
402 ERR_(midi)("AUGraphInitialize(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
403 return 0;
406 err = AUGraphStart(graph);
407 if (err != noErr)
409 ERR_(midi)("AUGraphStart(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
410 return 0;
413 return 1;
416 int SynthUnit_Close(AUGraph graph)
418 OSStatus err = noErr;
420 err = AUGraphStop(graph);
421 if (err != noErr)
423 ERR_(midi)("AUGraphStop(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
424 return 0;
427 err = DisposeAUGraph(graph);
428 if (err != noErr)
430 ERR_(midi)("DisposeAUGraph(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
431 return 0;
434 return 1;
437 #endif