Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / winecoreaudio.drv / audiounit.c
blob3fc24b039b0f4277ca615c168b5126599169360f
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(coreaudio);
26 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
27 #include <AudioUnit/AudioUnit.h>
29 static const char *streamDescription(const AudioStreamBasicDescription* stream)
31 return wine_dbg_sprintf("\n mSampleRate : %f\n mFormatID : %c%c%c%c\n mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
32 stream->mSampleRate,
33 (char) (stream->mFormatID >> 24),
34 (char) (stream->mFormatID >> 16),
35 (char) (stream->mFormatID >> 8),
36 (char) stream->mFormatID,
37 stream->mFormatFlags,
38 stream->mBytesPerPacket,
39 stream->mFramesPerPacket,
40 stream->mBytesPerFrame,
41 stream->mChannelsPerFrame,
42 stream->mBitsPerChannel);
45 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
46 AudioUnitRenderActionFlags *ioActionFlags,
47 const AudioTimeStamp *inTimeStamp,
48 UInt32 inBusNumber,
49 UInt32 inNumberFrames,
50 AudioBufferList *ioData);
52 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
53 AudioUnitRenderActionFlags *ioActionFlags,
54 const AudioTimeStamp *inTimeStamp,
55 UInt32 inBusNumber,
56 UInt32 inNumberFrames,
57 AudioBufferList *ioData);
59 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
61 OSStatus err;
62 Component comp;
63 ComponentDescription desc;
64 AURenderCallbackStruct callbackStruct;
66 TRACE("\n");
68 desc.componentType = kAudioUnitType_Output;
69 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
70 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
71 desc.componentFlags = 0;
72 desc.componentFlagsMask = 0;
74 comp = FindNextComponent(NULL, &desc);
75 if (comp == NULL)
76 return 0;
78 err = OpenAComponent(comp, au);
79 if (comp == NULL)
80 return 0;
82 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
83 callbackStruct.inputProcRefCon = wwo;
85 err = AudioUnitSetProperty( *au,
86 kAudioUnitProperty_SetRenderCallback,
87 kAudioUnitScope_Input,
88 0,
89 &callbackStruct,
90 sizeof(callbackStruct));
91 return (err == noErr);
94 int AudioUnit_CloseAudioUnit(AudioUnit au)
96 OSStatus err = CloseComponent(au);
97 return (err == noErr);
100 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
102 OSStatus err = noErr;
104 TRACE("%s\n", streamDescription(stream));
106 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
107 0, stream, sizeof(*stream));
109 if (err != noErr)
111 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
112 return 0;
115 err = AudioUnitInitialize(au);
116 if (err != noErr)
118 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
119 return 0;
121 return 1;
124 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
126 OSStatus err = noErr;
127 FIXME("independent left/right volume not implemented (%f, %f)\n", left, right);
129 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
131 if (err != noErr)
133 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
134 return 0;
136 return 1;
139 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
141 OSStatus err = noErr;
142 FIXME("independent left/right volume not implemented\n");
144 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
145 if (err != noErr)
147 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
148 return 0;
150 *right = *left;
151 return 1;
155 /* FIXME: implement sample rate conversion on input */
156 int AudioUnit_GetInputDeviceSampleRate(void)
158 AudioDeviceID defaultInputDevice;
159 UInt32 param;
160 Float64 sampleRate;
161 OSStatus err;
163 param = sizeof(defaultInputDevice);
164 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
165 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
167 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
168 return 0;
171 param = sizeof(sampleRate);
172 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
173 if (err != noErr)
175 ERR("Couldn't get the device sample rate: %08lx\n", err);
176 return 0;
179 return sampleRate;
183 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
184 WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
185 UInt32* outFrameCount)
187 OSStatus err = noErr;
188 ComponentDescription description;
189 Component component;
190 AudioUnit au;
191 UInt32 param;
192 AURenderCallbackStruct callback;
193 AudioDeviceID defaultInputDevice;
194 AudioStreamBasicDescription desiredFormat;
197 if (!outFrameCount)
199 ERR("Invalid parameter\n");
200 return 0;
203 /* Open the AudioOutputUnit */
204 description.componentType = kAudioUnitType_Output;
205 description.componentSubType = kAudioUnitSubType_HALOutput;
206 description.componentManufacturer = kAudioUnitManufacturer_Apple;
207 description.componentFlags = 0;
208 description.componentFlagsMask = 0;
210 component = FindNextComponent(NULL, &description);
211 if (!component)
213 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
214 return 0;
217 err = OpenAComponent(component, &au);
218 if (err != noErr || au == NULL)
220 ERR("OpenAComponent failed: %08lx\n", err);
221 return 0;
224 /* Configure the AudioOutputUnit */
225 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
226 * to the device. Bus 1 is input from the device to the app. Each bus
227 * has two ends (AKA scopes). Data goes from the input scope to the
228 * output scope. The terminology is somewhat confusing because the terms
229 * "input" and "output" have two meanings. Here's a summary:
231 * Bus 0, input scope: refers to the source of data to be output as sound
232 * Bus 0, output scope: refers to the actual sound output device
233 * Bus 1, input scope: refers to the actual sound input device
234 * Bus 1, output scope: refers to the destination of data received by the input device
237 /* Enable input on the AUHAL */
238 param = 1;
239 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
240 if (err != noErr)
242 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
243 goto error;
246 /* Disable Output on the AUHAL */
247 param = 0;
248 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
249 if (err != noErr)
251 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
252 goto error;
255 /* Find the default input device */
256 param = sizeof(defaultInputDevice);
257 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
258 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
260 ERR("Couldn't get the default audio device ID: %08lx\n", err);
261 goto error;
264 /* Set the current device to the default input device. */
265 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
266 if (err != noErr)
268 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
269 goto error;
272 /* Setup render callback */
273 /* This will be called when the AUHAL has input data. However, it won't
274 * be passed the data itself. The callback will have to all AudioUnitRender. */
275 callback.inputProc = CoreAudio_wiAudioUnitIOProc;
276 callback.inputProcRefCon = wwi;
277 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
278 if (err != noErr)
280 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
281 goto error;
284 /* Setup the desired data format. */
285 /* FIXME: implement sample rate conversion on input. We shouldn't set
286 * the mSampleRate of this to the desired sample rate. We need to query
287 * the input device and use that. If they don't match, we need to set up
288 * an AUConverter to do the sample rate conversion on a separate thread. */
289 desiredFormat.mFormatID = kAudioFormatLinearPCM;
290 desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
291 if (wBitsPerSample != 8)
292 desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
293 desiredFormat.mSampleRate = nSamplesPerSec;
294 desiredFormat.mChannelsPerFrame = nChannels;
295 desiredFormat.mFramesPerPacket = 1;
296 desiredFormat.mBitsPerChannel = wBitsPerSample;
297 desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
298 desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
300 /* Set the AudioOutputUnit output data format */
301 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
302 if (err != noErr)
304 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
305 goto error;
308 /* Get the number of frames in the IO buffer(s) */
309 param = sizeof(*outFrameCount);
310 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
311 if (err != noErr)
313 ERR("Failed to get audio sample size: %08lx\n", err);
314 goto error;
317 TRACE("Frame count: %lu\n", *outFrameCount);
319 /* Initialize the AU */
320 err = AudioUnitInitialize(au);
321 if (err != noErr)
323 ERR("Failed to initialize AU: %08lx\n", err);
324 goto error;
327 *out_au = au;
329 return 1;
331 error:
332 if (au)
333 CloseComponent(au);
334 return 0;
337 #endif