kernel32: GlobalMemoryStatusEx: return the size of physical memory + swapsize in...
[wine] / dlls / winecoreaudio.drv / audiounit.c
1 /*
2  * Wine Driver for CoreAudio / AudioUnit
3  *
4  * Copyright 2005, 2006 Emmanuel Maillard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(wave);
25
26 #ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
27 #include <AudioUnit/AudioUnit.h>
28
29 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
30                                 AudioUnitRenderActionFlags *ioActionFlags, 
31                                 const AudioTimeStamp *inTimeStamp, 
32                                 UInt32 inBusNumber, 
33                                 UInt32 inNumberFrames, 
34                                 AudioBufferList *ioData);
35
36 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
37                                 AudioUnitRenderActionFlags *ioActionFlags,
38                                 const AudioTimeStamp *inTimeStamp,
39                                 UInt32 inBusNumber,
40                                 UInt32 inNumberFrames,
41                                 AudioBufferList *ioData);
42
43 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
44 {
45     OSStatus err;
46     Component comp;
47     ComponentDescription desc;
48     AURenderCallbackStruct callbackStruct;
49     
50     desc.componentType = kAudioUnitType_Output;
51     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
52     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
53     desc.componentFlags = 0;
54     desc.componentFlagsMask = 0;
55
56     comp = FindNextComponent(NULL, &desc);
57     if (comp == NULL)
58         return 0;
59     
60     err = OpenAComponent(comp, au);
61     if (comp == NULL)
62         return 0;
63         
64     callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
65     callbackStruct.inputProcRefCon = wwo;
66
67     err = AudioUnitSetProperty( *au, 
68                                 kAudioUnitProperty_SetRenderCallback, 
69                                 kAudioUnitScope_Input,
70                                 0, 
71                                 &callbackStruct, 
72                                 sizeof(callbackStruct));
73     return (err == noErr);
74 }
75
76 int AudioUnit_CloseAudioUnit(AudioUnit au)
77 {
78     OSStatus err = CloseComponent(au);
79     return (err == noErr);
80 }
81
82 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
83 {
84     OSStatus err = noErr;
85         
86     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
87                                 0, stream, sizeof(*stream));
88
89     if (err != noErr)
90     {
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;
93     }
94     
95     err = AudioUnitInitialize(au);
96     if (err != noErr)
97     {
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;
100     }
101     return 1;
102 }
103
104 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
105 {
106     OSStatus err = noErr;
107    
108     err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
109                                 
110     if (err != noErr)
111     {
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;
114     }
115     return 1;
116 }
117
118 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
119 {
120     OSStatus err = noErr;
121     
122     err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
123     if (err != noErr)
124     {
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;
127     }
128     *right = *left;
129     return 1;
130 }
131
132
133 /* FIXME: implement sample rate conversion on input */
134 int AudioUnit_GetInputDeviceSampleRate(void)
135 {
136     AudioDeviceID               defaultInputDevice;
137     UInt32                      param;
138     Float64                     sampleRate;
139     OSStatus                    err;
140
141     param = sizeof(defaultInputDevice);
142     err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
143     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
144     {
145         ERR("Couldn't get the default audio input device ID: %08lx\n", err);
146         return 0;
147     }
148
149     param = sizeof(sampleRate);
150     err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
151     if (err != noErr)
152     {
153         ERR("Couldn't get the device sample rate: %08lx\n", err);
154         return 0;
155     }
156
157     return sampleRate;
158 }
159
160
161 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
162         WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
163         UInt32* outFrameCount)
164 {
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;
173
174
175     if (!outFrameCount)
176     {
177         ERR("Invalid parameter\n");
178         return 0;
179     }
180
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;
187
188     component = FindNextComponent(NULL, &description);
189     if (!component)
190     {
191         ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
192         return 0;
193     }
194
195     err = OpenAComponent(component, &au);
196     if (err != noErr || au == NULL)
197     {
198         ERR("OpenAComponent failed: %08lx\n", err);
199         return 0;
200     }
201
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:
208      *
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
213      */
214
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)
219     {
220         ERR("Couldn't enable input on AUHAL: %08lx\n", err);
221         goto error;
222     }
223
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)
228     {
229         ERR("Couldn't disable output on AUHAL: %08lx\n", err);
230         goto error;
231     }
232
233     /* Find the default input device */
234     param = sizeof(defaultInputDevice);
235     err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
236     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
237     {
238         ERR("Couldn't get the default audio device ID: %08lx\n", err);
239         goto error;
240     }
241
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)
245     {
246         ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
247         goto error;
248     }
249
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)
257     {
258         ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
259         goto error;
260     }
261
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;
277
278     /* Set the AudioOutputUnit output data format */
279     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
280     if (err != noErr)
281     {
282         ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
283         goto error;
284     }
285
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)
290     {
291         ERR("Failed to get audio sample size: %08lx\n", err);
292         goto error;
293     }
294
295     TRACE("Frame count: %lu\n", *outFrameCount);
296
297     /* Initialize the AU */
298     err = AudioUnitInitialize(au);
299     if (err != noErr)
300     {
301         ERR("Failed to initialize AU: %08lx\n", err);
302         goto error;
303     }
304
305     *out_au = au;
306
307     return 1;
308
309 error:
310     if (au)
311         CloseComponent(au);
312     return 0;
313 }
314
315 #endif