richedit: Moved optional message loop in tests to its own function.
[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 #include <AudioToolbox/AudioToolbox.h>
29
30 WINE_DECLARE_DEBUG_CHANNEL(midi);
31
32 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
33                                 AudioUnitRenderActionFlags *ioActionFlags, 
34                                 const AudioTimeStamp *inTimeStamp, 
35                                 UInt32 inBusNumber, 
36                                 UInt32 inNumberFrames, 
37                                 AudioBufferList *ioData);
38
39 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
40                                 AudioUnitRenderActionFlags *ioActionFlags,
41                                 const AudioTimeStamp *inTimeStamp,
42                                 UInt32 inBusNumber,
43                                 UInt32 inNumberFrames,
44                                 AudioBufferList *ioData);
45
46 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
47 {
48     OSStatus err;
49     Component comp;
50     ComponentDescription desc;
51     AURenderCallbackStruct callbackStruct;
52     
53     desc.componentType = kAudioUnitType_Output;
54     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
55     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
56     desc.componentFlags = 0;
57     desc.componentFlagsMask = 0;
58
59     comp = FindNextComponent(NULL, &desc);
60     if (comp == NULL)
61         return 0;
62     
63     err = OpenAComponent(comp, au);
64     if (comp == NULL)
65         return 0;
66         
67     callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
68     callbackStruct.inputProcRefCon = wwo;
69
70     err = AudioUnitSetProperty( *au, 
71                                 kAudioUnitProperty_SetRenderCallback, 
72                                 kAudioUnitScope_Input,
73                                 0, 
74                                 &callbackStruct, 
75                                 sizeof(callbackStruct));
76     return (err == noErr);
77 }
78
79 int AudioUnit_CloseAudioUnit(AudioUnit au)
80 {
81     OSStatus err = CloseComponent(au);
82     return (err == noErr);
83 }
84
85 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
86 {
87     OSStatus err = noErr;
88         
89     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
90                                 0, stream, sizeof(*stream));
91
92     if (err != noErr)
93     {
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;
96     }
97     
98     err = AudioUnitInitialize(au);
99     if (err != noErr)
100     {
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;
103     }
104     return 1;
105 }
106
107 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
108 {
109     OSStatus err = noErr;
110    
111     err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
112                                 
113     if (err != noErr)
114     {
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;
117     }
118     return 1;
119 }
120
121 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
122 {
123     OSStatus err = noErr;
124     
125     err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
126     if (err != noErr)
127     {
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;
130     }
131     *right = *left;
132     return 1;
133 }
134
135
136 /* FIXME: implement sample rate conversion on input */
137 int AudioUnit_GetInputDeviceSampleRate(void)
138 {
139     AudioDeviceID               defaultInputDevice;
140     UInt32                      param;
141     Float64                     sampleRate;
142     OSStatus                    err;
143
144     param = sizeof(defaultInputDevice);
145     err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
146     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
147     {
148         ERR("Couldn't get the default audio input device ID: %08lx\n", err);
149         return 0;
150     }
151
152     param = sizeof(sampleRate);
153     err = AudioDeviceGetProperty(defaultInputDevice, 0, 1, kAudioDevicePropertyNominalSampleRate, &param, &sampleRate);
154     if (err != noErr)
155     {
156         ERR("Couldn't get the device sample rate: %08lx\n", err);
157         return 0;
158     }
159
160     return sampleRate;
161 }
162
163
164 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
165         WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
166         UInt32* outFrameCount)
167 {
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;
176
177
178     if (!outFrameCount)
179     {
180         ERR("Invalid parameter\n");
181         return 0;
182     }
183
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;
190
191     component = FindNextComponent(NULL, &description);
192     if (!component)
193     {
194         ERR("FindNextComponent(kAudioUnitSubType_HALOutput) failed\n");
195         return 0;
196     }
197
198     err = OpenAComponent(component, &au);
199     if (err != noErr || au == NULL)
200     {
201         ERR("OpenAComponent failed: %08lx\n", err);
202         return 0;
203     }
204
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:
211      *
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
216      */
217
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)
222     {
223         ERR("Couldn't enable input on AUHAL: %08lx\n", err);
224         goto error;
225     }
226
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)
231     {
232         ERR("Couldn't disable output on AUHAL: %08lx\n", err);
233         goto error;
234     }
235
236     /* Find the default input device */
237     param = sizeof(defaultInputDevice);
238     err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &param, &defaultInputDevice);
239     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
240     {
241         ERR("Couldn't get the default audio device ID: %08lx\n", err);
242         goto error;
243     }
244
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)
248     {
249         ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
250         goto error;
251     }
252
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)
260     {
261         ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
262         goto error;
263     }
264
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;
280
281     /* Set the AudioOutputUnit output data format */
282     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
283     if (err != noErr)
284     {
285         ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
286         goto error;
287     }
288
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)
293     {
294         ERR("Failed to get audio sample size: %08lx\n", err);
295         goto error;
296     }
297
298     TRACE("Frame count: %lu\n", *outFrameCount);
299
300     /* Initialize the AU */
301     err = AudioUnitInitialize(au);
302     if (err != noErr)
303     {
304         ERR("Failed to initialize AU: %08lx\n", err);
305         goto error;
306     }
307
308     *out_au = au;
309
310     return 1;
311
312 error:
313     if (au)
314         CloseComponent(au);
315     return 0;
316 }
317
318 /*
319  *  MIDI Synth Unit
320  */
321 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
322 {
323     OSStatus err;
324     ComponentDescription desc;
325     AUNode synthNode;
326     AUNode outNode;
327
328     err = NewAUGraph(graph);
329     if (err != noErr)
330     {
331         ERR_(midi)("NewAUGraph return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
332         return 0;
333     }
334
335     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
336     desc.componentFlags = 0;
337     desc.componentFlagsMask = 0;
338
339     /* create synth node */
340     desc.componentType = kAudioUnitType_MusicDevice;
341     desc.componentSubType = kAudioUnitSubType_DLSSynth;
342
343     err = AUGraphNewNode(*graph, &desc, 0, NULL, &synthNode);
344     if (err != noErr)
345     {
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;
348     }
349
350     /* create out node */
351     desc.componentType = kAudioUnitType_Output;
352     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
353
354     err = AUGraphNewNode(*graph, &desc, 0, NULL, &outNode);
355     if (err != noErr)
356     {
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;
359     }
360
361     err = AUGraphOpen(*graph);
362     if (err != noErr)
363     {
364         ERR_(midi)("AUGraphOpen return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
365         return 0;
366     }
367
368     /* connecting the nodes */
369     err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
370     if (err != noErr)
371     {
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;
374     }
375
376     /* Get the synth unit */
377     err = AUGraphGetNodeInfo(*graph, synthNode, 0, 0, 0, synth);
378     if (err != noErr)
379     {
380         ERR_(midi)("AUGraphGetNodeInfo return %c%c%c%c\n", (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
381         return 0;
382     }
383
384     return 1;
385 }
386
387 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
388 {
389     OSStatus err = noErr;
390
391     err = AUGraphInitialize(graph);
392     if (err != noErr)
393     {
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;
396     }
397
398     err = AUGraphStart(graph);
399     if (err != noErr)
400     {
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;
403     }
404
405     return 1;
406 }
407
408 int SynthUnit_Close(AUGraph graph)
409 {
410     OSStatus err = noErr;
411
412     err = AUGraphStop(graph);
413     if (err != noErr)
414     {
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;
417     }
418
419     err = DisposeAUGraph(graph);
420     if (err != noErr)
421     {
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;
424     }
425
426     return 1;
427 }
428
429 #endif