wineaudioio: Renamed the dlls/winmm/wineaudioio directory to dlls/wineaudioio.drv.
[wine/wine64.git] / dlls / winmm / winecoreaudio / audiounit.c
blobb6da953129577dcf8b853ccc86736bd63efc9983
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>
29 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon,
30 AudioUnitRenderActionFlags *ioActionFlags,
31 const AudioTimeStamp *inTimeStamp,
32 UInt32 inBusNumber,
33 UInt32 inNumberFrames,
34 AudioBufferList *ioData);
36 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
37 AudioUnitRenderActionFlags *ioActionFlags,
38 const AudioTimeStamp *inTimeStamp,
39 UInt32 inBusNumber,
40 UInt32 inNumberFrames,
41 AudioBufferList *ioData);
43 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
45 OSStatus err;
46 Component comp;
47 ComponentDescription desc;
48 AURenderCallbackStruct callbackStruct;
50 desc.componentType = kAudioUnitType_Output;
51 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
52 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
53 desc.componentFlags = 0;
54 desc.componentFlagsMask = 0;
56 comp = FindNextComponent(NULL, &desc);
57 if (comp == NULL)
58 return 0;
60 err = OpenAComponent(comp, au);
61 if (comp == NULL)
62 return 0;
64 callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
65 callbackStruct.inputProcRefCon = wwo;
67 err = AudioUnitSetProperty( *au,
68 kAudioUnitProperty_SetRenderCallback,
69 kAudioUnitScope_Input,
70 0,
71 &callbackStruct,
72 sizeof(callbackStruct));
73 return (err == noErr);
76 int AudioUnit_CloseAudioUnit(AudioUnit au)
78 OSStatus err = CloseComponent(au);
79 return (err == noErr);
82 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
84 OSStatus err = noErr;
86 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
87 0, stream, sizeof(*stream));
89 if (err != noErr)
91 ERR("AudioUnitSetProperty return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
92 return 0;
95 err = AudioUnitInitialize(au);
96 if (err != noErr)
98 ERR("AudioUnitInitialize return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
99 return 0;
101 return 1;
104 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
106 OSStatus err = noErr;
108 err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
110 if (err != noErr)
112 ERR("AudioUnitSetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
113 return 0;
115 return 1;
118 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
120 OSStatus err = noErr;
122 err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
123 if (err != noErr)
125 ERR("AudioUnitGetParameter return an error %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
126 return 0;
128 *right = *left;
129 return 1;
133 /* FIXME: implement sample rate conversion on input */
134 int AudioUnit_GetInputDeviceSampleRate(void)
136 AudioDeviceID defaultInputDevice;
137 UInt32 param;
138 Float64 sampleRate;
139 OSStatus err;
141 param = sizeof(defaultInputDevice);
142 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
143 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
145 ERR("Couldn't get the default audio input device ID: %08lx\n", err);
146 return 0;
149 param = sizeof(sampleRate);
150 err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
151 if (err != noErr)
153 ERR("Couldn't get the device sample rate: %08lx\n", err);
154 return 0;
157 return sampleRate;
161 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
162 WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
163 UInt32* outFrameCount)
165 OSStatus err = noErr;
166 ComponentDescription description;
167 Component component;
168 AudioUnit au;
169 UInt32 param;
170 AURenderCallbackStruct callback;
171 AudioDeviceID defaultInputDevice;
172 AudioStreamBasicDescription desiredFormat;
175 if (!outFrameCount)
177 ERR("Invalid parameter\n");
178 return 0;
181 /* Open the AudioOutputUnit */
182 description.componentType = kAudioUnitType_Output;
183 description.componentSubType = kAudioUnitSubType_HALOutput;
184 description.componentManufacturer = kAudioUnitManufacturer_Apple;
185 description.componentFlags = 0;
186 description.componentFlagsMask = 0;
188 component = FindNextComponent(NULL, &description);
189 if (!component)
191 ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
192 return 0;
195 err = OpenAComponent(component, &au);
196 if (err != noErr || au == NULL)
198 ERR("OpenAComponent failed: %08lx\n", err);
199 return 0;
202 /* Configure the AudioOutputUnit */
203 /* The AUHAL has two buses (AKA elements). Bus 0 is output from the app
204 * to the device. Bus 1 is input from the device to the app. Each bus
205 * has two ends (AKA scopes). Data goes from the input scope to the
206 * output scope. The terminology is somewhat confusing because the terms
207 * "input" and "output" have two meanings. Here's a summary:
209 * Bus 0, input scope: refers to the source of data to be output as sound
210 * Bus 0, output scope: refers to the actual sound output device
211 * Bus 1, input scope: refers to the actual sound input device
212 * Bus 1, output scope: refers to the destination of data received by the input device
215 /* Enable input on the AUHAL */
216 param = 1;
217 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
218 if (err != noErr)
220 ERR("Couldn't enable input on AUHAL: %08lx\n", err);
221 goto error;
224 /* Disable Output on the AUHAL */
225 param = 0;
226 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
227 if (err != noErr)
229 ERR("Couldn't disable output on AUHAL: %08lx\n", err);
230 goto error;
233 /* Find the default input device */
234 param = sizeof(defaultInputDevice);
235 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
236 if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
238 ERR("Couldn't get the default audio device ID: %08lx\n", err);
239 goto error;
242 /* Set the current device to the default input device. */
243 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
244 if (err != noErr)
246 ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
247 goto error;
250 /* Setup render callback */
251 /* This will be called when the AUHAL has input data. However, it won't
252 * be passed the data itself. The callback will have to all AudioUnitRender. */
253 callback.inputProc = CoreAudio_wiAudioUnitIOProc;
254 callback.inputProcRefCon = wwi;
255 err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
256 if (err != noErr)
258 ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
259 goto error;
262 /* Setup the desired data format. */
263 /* FIXME: implement sample rate conversion on input. We shouldn't set
264 * the mSampleRate of this to the desired sample rate. We need to query
265 * the input device and use that. If they don't match, we need to set up
266 * an AUConverter to do the sample rate conversion on a separate thread. */
267 desiredFormat.mFormatID = kAudioFormatLinearPCM;
268 desiredFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
269 if (wBitsPerSample != 8)
270 desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
271 desiredFormat.mSampleRate = nSamplesPerSec;
272 desiredFormat.mChannelsPerFrame = nChannels;
273 desiredFormat.mFramesPerPacket = 1;
274 desiredFormat.mBitsPerChannel = wBitsPerSample;
275 desiredFormat.mBytesPerFrame = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
276 desiredFormat.mBytesPerPacket = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
278 /* Set the AudioOutputUnit output data format */
279 err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
280 if (err != noErr)
282 ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
283 goto error;
286 /* Get the number of frames in the IO buffer(s) */
287 param = sizeof(*outFrameCount);
288 err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
289 if (err != noErr)
291 ERR("Failed to get audio sample size: %08lx\n", err);
292 goto error;
295 TRACE("Frame count: %lu\n", *outFrameCount);
297 /* Initialize the AU */
298 err = AudioUnitInitialize(au);
299 if (err != noErr)
301 ERR("Failed to initialize AU: %08lx\n", err);
302 goto error;
305 *out_au = au;
307 return 1;
309 error:
310 if (au)
311 CloseComponent(au);
312 return 0;
315 #endif