quartz: Fix string buffer overflow.
[wine.git] / dlls / winecoreaudio.drv / audiounit.c
blob08fd5ec91e577454e6ac3161c7dc89249b0dc12a
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"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(wave);
26 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
27 #include <AudioUnit/AudioUnit.h>
28 #include <AudioToolbox/AudioToolbox.h>
30 WINE_DECLARE_DEBUG_CHANNEL(midi);
32 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
33 AudioUnitRenderActionFlags *ioActionFlags,
34 const AudioTimeStamp *inTimeStamp,
35 UInt32 inBusNumber,
36 UInt32 inNumberFrames,
37 AudioBufferList *ioData);
39 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
40 AudioUnitRenderActionFlags *ioActionFlags,
41 const AudioTimeStamp *inTimeStamp,
42 UInt32 inBusNumber,
43 UInt32 inNumberFrames,
44 AudioBufferList *ioData);
46 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
48 OSStatus err;
49 Component comp;
50 ComponentDescription desc;
51 AURenderCallbackStruct callbackStruct;
53 desc.componentType = kAudioUnitType_Output;
54 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
55 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
56 desc.componentFlags = 0;
57 desc.componentFlagsMask = 0;
59 comp = FindNextComponent(NULL, &desc);
60 if (comp == NULL)
61 return 0;
63 err = OpenAComponent(comp, au);
64 if (comp == NULL)
65 return 0;
67 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
68 callbackStruct.inputProcRefCon = wwo;
70 err = AudioUnitSetProperty( *au,
71 kAudioUnitProperty_SetRenderCallback,
72 kAudioUnitScope_Input,
73 0,
74 &callbackStruct,
75 sizeof(callbackStruct));
76 return (err == noErr);
79 int AudioUnit_CloseAudioUnit(AudioUnit au)
81 OSStatus err = CloseComponent(au);
82 return (err == noErr);
85 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
87 OSStatus err = noErr;
89 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
90 0, stream, sizeof(*stream));
92 if (err != noErr)
94 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
95 return 0;
98 err = AudioUnitInitialize(au);
99 if (err != noErr)
101 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
102 return 0;
104 return 1;
107 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
109 OSStatus err = noErr;
111 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
113 if (err != noErr)
115 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
116 return 0;
118 return 1;
121 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
123 OSStatus err = noErr;
125 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
126 if (err != noErr)
128 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
129 return 0;
131 *right = *left;
132 return 1;
136 /* FIXME: implement sample rate conversion on input */
137 int AudioUnit_GetInputDeviceSampleRate(void)
139 AudioDeviceID defaultInputDevice;
140 UInt32 param;
141 Float64 sampleRate;
142 OSStatus err;
144 param = sizeof(defaultInputDevice);
145 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
146 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
148 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
149 return 0;
152 param = sizeof(sampleRate);
153 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
154 if (err != noErr)
156 ERR("Couldn't get the device sample rate: %08lx\n", err);
157 return 0;
160 return sampleRate;
164 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
165 WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
166 UInt32* outFrameCount)
168 OSStatus err = noErr;
169 ComponentDescription description;
170 Component component;
171 AudioUnit au;
172 UInt32 param;
173 AURenderCallbackStruct callback;
174 AudioDeviceID defaultInputDevice;
175 AudioStreamBasicDescription desiredFormat;
178 if (!outFrameCount)
180 ERR("Invalid parameter\n");
181 return 0;
184 /* Open the AudioOutputUnit */
185 description.componentType = kAudioUnitType_Output;
186 description.componentSubType = kAudioUnitSubType_HALOutput;
187 description.componentManufacturer = kAudioUnitManufacturer_Apple;
188 description.componentFlags = 0;
189 description.componentFlagsMask = 0;
191 component = FindNextComponent(NULL, &description);
192 if (!component)
194 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
195 return 0;
198 err = OpenAComponent(component, &au);
199 if (err != noErr || au == NULL)
201 ERR("OpenAComponent failed: %08lx\n", err);
202 return 0;
205 /* Configure the AudioOutputUnit */
206 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
207 * to the device. Bus 1 is input from the device to the app. Each bus
208 * has two ends (AKA scopes). Data goes from the input scope to the
209 * output scope. The terminology is somewhat confusing because the terms
210 * "input" and "output" have two meanings. Here's a summary:
212 * Bus 0, input scope: refers to the source of data to be output as sound
213 * Bus 0, output scope: refers to the actual sound output device
214 * Bus 1, input scope: refers to the actual sound input device
215 * Bus 1, output scope: refers to the destination of data received by the input device
218 /* Enable input on the AUHAL */
219 param = 1;
220 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
221 if (err != noErr)
223 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
224 goto error;
227 /* Disable Output on the AUHAL */
228 param = 0;
229 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
230 if (err != noErr)
232 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
233 goto error;
236 /* Find the default input device */
237 param = sizeof(defaultInputDevice);
238 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
239 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
241 ERR("Couldn't get the default audio device ID: %08lx\n", err);
242 goto error;
245 /* Set the current device to the default input device. */
246 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
247 if (err != noErr)
249 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
250 goto error;
253 /* Setup render callback */
254 /* This will be called when the AUHAL has input data. However, it won't
255 * be passed the data itself. The callback will have to all AudioUnitRender. */
256 callback.inputProc = CoreAudio_wiAudioUnitIOProc;
257 callback.inputProcRefCon = wwi;
258 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
259 if (err != noErr)
261 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
262 goto error;
265 /* Setup the desired data format. */
266 /* FIXME: implement sample rate conversion on input. We shouldn't set
267 * the mSampleRate of this to the desired sample rate. We need to query
268 * the input device and use that. If they don't match, we need to set up
269 * an AUConverter to do the sample rate conversion on a separate thread. */
270 desiredFormat.mFormatID = kAudioFormatLinearPCM;
271 desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
272 if (wBitsPerSample != 8)
273 desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
274 desiredFormat.mSampleRate = nSamplesPerSec;
275 desiredFormat.mChannelsPerFrame = nChannels;
276 desiredFormat.mFramesPerPacket = 1;
277 desiredFormat.mBitsPerChannel = wBitsPerSample;
278 desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
279 desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
281 /* Set the AudioOutputUnit output data format */
282 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
283 if (err != noErr)
285 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
286 goto error;
289 /* Get the number of frames in the IO buffer(s) */
290 param = sizeof(*outFrameCount);
291 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
292 if (err != noErr)
294 ERR("Failed to get audio sample size: %08lx\n", err);
295 goto error;
298 TRACE("Frame count: %lu\n", *outFrameCount);
300 /* Initialize the AU */
301 err = AudioUnitInitialize(au);
302 if (err != noErr)
304 ERR("Failed to initialize AU: %08lx\n", err);
305 goto error;
308 *out_au = au;
310 return 1;
312 error:
313 if (au)
314 CloseComponent(au);
315 return 0;
319 * MIDI Synth Unit
321 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
323 OSStatus err;
324 ComponentDescription desc;
325 AUNode synthNode;
326 AUNode outNode;
328 err = NewAUGraph(graph);
329 if (err != noErr)
331 ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
332 return 0;
335 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
336 desc.componentFlags = 0;
337 desc.componentFlagsMask = 0;
339 /* create synth node */
340 desc.componentType = kAudioUnitType_MusicDevice;
341 desc.componentSubType = kAudioUnitSubType_DLSSynth;
343 err = AUGraphNewNode(*graph, &desc, 0, NULL, &synthNode);
344 if (err != noErr)
346 ERR_(midi)("AUGraphNewNode cannot create synthNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
347 return 0;
350 /* create out node */
351 desc.componentType = kAudioUnitType_Output;
352 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
354 err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
355 if (err != noErr)
357 ERR_(midi)("AUGraphNewNode cannot create outNode %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
358 return 0;
361 err = AUGraphOpen(*graph);
362 if (err != noErr)
364 ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
365 return 0;
368 /* connecting the nodes */
369 err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
370 if (err != noErr)
372 ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
373 return 0;
376 /* Get the synth unit */
377 err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
378 if (err != noErr)
380 ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
381 return 0;
384 return 1;
387 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
389 OSStatus err = noErr;
391 err = AUGraphInitialize(graph);
392 if (err != noErr)
394 ERR_(midi)("AUGraphInitialize(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
395 return 0;
398 err = AUGraphStart(graph);
399 if (err != noErr)
401 ERR_(midi)("AUGraphStart(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
402 return 0;
405 return 1;
408 int SynthUnit_Close(AUGraph graph)
410 OSStatus err = noErr;
412 err = AUGraphStop(graph);
413 if (err != noErr)
415 ERR_(midi)("AUGraphStop(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
416 return 0;
419 err = DisposeAUGraph(graph);
420 if (err != noErr)
422 ERR_(midi)("DisposeAUGraph(%p) return %c%c%c%c\n", graph, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
423 return 0;
426 return 1;
429 #endif