ddraw: Do not create implicit depth buffer.
[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
23 #define ULONG CoreFoundation_ULONG
24 #define HRESULT CoreFoundation_HRESULT
25 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
26 #include <CoreServices/CoreServices.h>
27 #endif
28 #include <AudioUnit/AudioUnit.h>
29 #include <AudioToolbox/AudioToolbox.h>
30 #undef ULONG
31 #undef HRESULT
32
33 #undef DPRINTF
34 #undef STDMETHODCALLTYPE
35 #include "coreaudio.h"
36 #include "wine/debug.h"
37
38 #ifndef HAVE_AUDIOUNIT_AUDIOCOMPONENT_H
39 /* Define new AudioComponent Manager functions for compatibility's sake */
40 typedef Component AudioComponent;
41 typedef ComponentDescription AudioComponentDescription;
42 typedef ComponentInstance AudioComponentInstance;
43
44 static inline AudioComponent AudioComponentFindNext(AudioComponent ac, AudioComponentDescription *desc)
45 {
46     return FindNextComponent(ac, desc);
47 }
48
49 static inline OSStatus AudioComponentInstanceNew(AudioComponent ac, AudioComponentInstance *aci)
50 {
51     return OpenAComponent(ac, aci);
52 }
53
54 static inline OSStatus AudioComponentInstanceDispose(AudioComponentInstance aci)
55 {
56     return CloseComponent(aci);
57 }
58 #endif
59
60 #ifndef HAVE_AUGRAPHADDNODE
61 static inline OSStatus AUGraphAddNode(AUGraph graph, const AudioComponentDescription *desc, AUNode *node)
62 {
63     return AUGraphNewNode(graph, desc, 0, NULL, node);
64 }
65
66 static inline OSStatus AUGraphNodeInfo(AUGraph graph, AUNode node, AudioComponentDescription *desc, AudioUnit *au)
67 {
68     return AUGraphGetNodeInfo(graph, node, desc, 0, NULL, au);
69 }
70 #endif
71
72 WINE_DEFAULT_DEBUG_CHANNEL(wave);
73 WINE_DECLARE_DEBUG_CHANNEL(midi);
74
75 static const char *streamDescription(const AudioStreamBasicDescription* stream)
76 {
77     return wine_dbg_sprintf("\n mSampleRate : %f\n mFormatID : %s\n mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
78         stream->mSampleRate,
79         wine_dbgstr_fourcc(stream->mFormatID),
80         stream->mFormatFlags,
81         stream->mBytesPerPacket,
82         stream->mFramesPerPacket,
83         stream->mBytesPerFrame,
84         stream->mChannelsPerFrame,
85         stream->mBitsPerChannel);
86 }
87
88 extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
89                                 AudioUnitRenderActionFlags *ioActionFlags, 
90                                 const AudioTimeStamp *inTimeStamp, 
91                                 UInt32 inBusNumber, 
92                                 UInt32 inNumberFrames, 
93                                 AudioBufferList *ioData);
94
95 extern OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
96                                 AudioUnitRenderActionFlags *ioActionFlags,
97                                 const AudioTimeStamp *inTimeStamp,
98                                 UInt32 inBusNumber,
99                                 UInt32 inNumberFrames,
100                                 AudioBufferList *ioData);
101
102 int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
103 {
104     OSStatus err;
105     AudioComponent comp;
106     AudioComponentDescription desc;
107     AURenderCallbackStruct callbackStruct;
108
109     TRACE("\n");
110     
111     desc.componentType = kAudioUnitType_Output;
112     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
113     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
114     desc.componentFlags = 0;
115     desc.componentFlagsMask = 0;
116
117     comp = AudioComponentFindNext(NULL, &desc);
118     if (comp == NULL)
119         return 0;
120     
121     err = AudioComponentInstanceNew(comp, au);
122     if (err != noErr || *au == NULL)
123         return 0;
124         
125     callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
126     callbackStruct.inputProcRefCon = wwo;
127
128     err = AudioUnitSetProperty( *au, 
129                                 kAudioUnitProperty_SetRenderCallback, 
130                                 kAudioUnitScope_Input,
131                                 0, 
132                                 &callbackStruct, 
133                                 sizeof(callbackStruct));
134     return (err == noErr);
135 }
136
137 int AudioUnit_CloseAudioUnit(AudioUnit au)
138 {
139     OSStatus err = AudioComponentInstanceDispose(au);
140     return (err == noErr);
141 }
142
143 int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *stream)
144 {
145     OSStatus err = noErr;
146         
147     TRACE("input format: %s\n", streamDescription(stream));
148
149     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
150                                 0, stream, sizeof(*stream));
151
152     if (err != noErr)
153     {
154         ERR("AudioUnitSetProperty return an error %s\n", wine_dbgstr_fourcc(err));
155         return 0;
156     }
157     
158     err = AudioUnitInitialize(au);
159     if (err != noErr)
160     {
161         ERR("AudioUnitInitialize return an error %s\n", wine_dbgstr_fourcc(err));
162         return 0;
163     }
164     return 1;
165 }
166
167 int AudioUnit_SetVolume(AudioUnit au, float left, float right)
168 {
169     OSStatus err = noErr;
170     static int once;
171
172     if (!once++) FIXME("independent left/right volume not implemented (%f, %f)\n", left, right);
173    
174     err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
175                                 
176     if (err != noErr)
177     {
178         ERR("AudioUnitSetParameter return an error %s\n", wine_dbgstr_fourcc(err));
179         return 0;
180     }
181     return 1;
182 }
183
184 int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
185 {
186     OSStatus err = noErr;
187     static int once;
188
189     if (!once++) FIXME("independent left/right volume not implemented\n");
190     
191     err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
192     if (err != noErr)
193     {
194         ERR("AudioUnitGetParameter return an error %s\n", wine_dbgstr_fourcc(err));
195         return 0;
196     }
197     *right = *left;
198     return 1;
199 }
200
201
202 /* FIXME: implement sample rate conversion on input */
203 int AudioUnit_GetInputDeviceSampleRate(void)
204 {
205     AudioDeviceID               defaultInputDevice;
206     UInt32                      param;
207     AudioObjectPropertyAddress  propertyAddress;
208     Float64                     sampleRate;
209     OSStatus                    err;
210
211     param = sizeof(defaultInputDevice);
212     propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
213     propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
214     propertyAddress.mElement = kAudioObjectPropertyElementMaster;
215     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &param, &defaultInputDevice);
216     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
217     {
218         ERR("Couldn't get the default audio input device ID: %08lx\n", err);
219         return 0;
220     }
221
222     param = sizeof(sampleRate);
223     propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
224     propertyAddress.mScope = kAudioDevicePropertyScopeInput;
225     err = AudioObjectGetPropertyData(defaultInputDevice, &propertyAddress, 0, NULL, &param, &sampleRate);
226     if (err != noErr)
227     {
228         ERR("Couldn't get the device sample rate: %08lx\n", err);
229         return 0;
230     }
231
232     return sampleRate;
233 }
234
235
236 int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
237         WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
238         UInt32* outFrameCount)
239 {
240     OSStatus                    err = noErr;
241     AudioComponentDescription   description;
242     AudioComponent              component;
243     AudioUnit                   au;
244     UInt32                      param;
245     AudioObjectPropertyAddress  propertyAddress;
246     AURenderCallbackStruct      callback;
247     AudioDeviceID               defaultInputDevice;
248     AudioStreamBasicDescription desiredFormat;
249
250
251     if (!outFrameCount)
252     {
253         ERR("Invalid parameter\n");
254         return 0;
255     }
256
257     /* Open the AudioOutputUnit */
258     description.componentType           = kAudioUnitType_Output;
259     description.componentSubType        = kAudioUnitSubType_HALOutput;
260     description.componentManufacturer   = kAudioUnitManufacturer_Apple;
261     description.componentFlags          = 0;
262     description.componentFlagsMask      = 0;
263
264     component = AudioComponentFindNext(NULL, &description);
265     if (!component)
266     {
267         ERR("AudioComponentFindNext(kAudioUnitSubType_HALOutput) failed\n");
268         return 0;
269     }
270
271     err = AudioComponentInstanceNew(component, &au);
272     if (err != noErr || au == NULL)
273     {
274         ERR("AudioComponentInstanceNew failed: %08lx\n", err);
275         return 0;
276     }
277
278     /* Configure the AudioOutputUnit */
279     /* The AUHAL has two buses (AKA elements).  Bus 0 is output from the app
280      * to the device.  Bus 1 is input from the device to the app.  Each bus
281      * has two ends (AKA scopes).  Data goes from the input scope to the
282      * output scope.  The terminology is somewhat confusing because the terms
283      * "input" and "output" have two meanings.  Here's a summary:
284      *
285      *      Bus 0, input scope: refers to the source of data to be output as sound
286      *      Bus 0, output scope: refers to the actual sound output device
287      *      Bus 1, input scope: refers to the actual sound input device
288      *      Bus 1, output scope: refers to the destination of data received by the input device
289      */
290
291     /* Enable input on the AUHAL */
292     param = 1;
293     err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(param));
294     if (err != noErr)
295     {
296         ERR("Couldn't enable input on AUHAL: %08lx\n", err);
297         goto error;
298     }
299
300     /* Disable Output on the AUHAL */
301     param = 0;
302     err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &param, sizeof(param));
303     if (err != noErr)
304     {
305         ERR("Couldn't disable output on AUHAL: %08lx\n", err);
306         goto error;
307     }
308
309     /* Find the default input device */
310     param = sizeof(defaultInputDevice);
311     propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
312     propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
313     propertyAddress.mElement = kAudioObjectPropertyElementMaster;
314     err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &param, &defaultInputDevice);
315     if (err != noErr || defaultInputDevice == kAudioDeviceUnknown)
316     {
317         ERR("Couldn't get the default audio device ID: %08lx\n", err);
318         goto error;
319     }
320
321     /* Set the current device to the default input device. */
322     err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &defaultInputDevice, sizeof(defaultInputDevice));
323     if (err != noErr)
324     {
325         ERR("Couldn't set current device of AUHAL to default input device: %08lx\n", err);
326         goto error;
327     }
328
329     /* Setup render callback */
330     /* This will be called when the AUHAL has input data.  However, it won't
331      * be passed the data itself.  The callback will have to all AudioUnitRender. */
332     callback.inputProc = CoreAudio_wiAudioUnitIOProc;
333     callback.inputProcRefCon = wwi;
334     err = AudioUnitSetProperty(au, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
335     if (err != noErr)
336     {
337         ERR("Couldn't set input callback of AUHAL: %08lx\n", err);
338         goto error;
339     }
340
341     /* Setup the desired data format. */
342     /* FIXME: implement sample rate conversion on input.  We shouldn't set
343      * the mSampleRate of this to the desired sample rate.  We need to query
344      * the input device and use that.  If they don't match, we need to set up
345      * an AUConverter to do the sample rate conversion on a separate thread. */
346     desiredFormat.mFormatID         = kAudioFormatLinearPCM;
347     desiredFormat.mFormatFlags      = kLinearPCMFormatFlagIsPacked;
348     if (wBitsPerSample != 8)
349         desiredFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
350     desiredFormat.mSampleRate       = nSamplesPerSec;
351     desiredFormat.mChannelsPerFrame = nChannels;
352     desiredFormat.mFramesPerPacket  = 1;
353     desiredFormat.mBitsPerChannel   = wBitsPerSample;
354     desiredFormat.mBytesPerFrame    = desiredFormat.mBitsPerChannel * desiredFormat.mChannelsPerFrame / 8;
355     desiredFormat.mBytesPerPacket   = desiredFormat.mBytesPerFrame * desiredFormat.mFramesPerPacket;
356
357     /* Set the AudioOutputUnit output data format */
358     err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desiredFormat, sizeof(desiredFormat));
359     if (err != noErr)
360     {
361         ERR("Couldn't set desired input format of AUHAL: %08lx\n", err);
362         goto error;
363     }
364
365     /* Get the number of frames in the IO buffer(s) */
366     param = sizeof(*outFrameCount);
367     err = AudioUnitGetProperty(au, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, outFrameCount, &param);
368     if (err != noErr)
369     {
370         ERR("Failed to get audio sample size: %08lx\n", err);
371         goto error;
372     }
373
374     TRACE("Frame count: %lu\n", *outFrameCount);
375
376     /* Initialize the AU */
377     err = AudioUnitInitialize(au);
378     if (err != noErr)
379     {
380         ERR("Failed to initialize AU: %08lx\n", err);
381         goto error;
382     }
383
384     *out_au = au;
385
386     return 1;
387
388 error:
389     if (au)
390         AudioComponentInstanceDispose(au);
391     return 0;
392 }
393
394 /*
395  *  MIDI Synth Unit
396  */
397 int SynthUnit_CreateDefaultSynthUnit(AUGraph *graph, AudioUnit *synth)
398 {
399     OSStatus err;
400     AudioComponentDescription desc;
401     AUNode synthNode;
402     AUNode outNode;
403
404     err = NewAUGraph(graph);
405     if (err != noErr)
406     {
407         ERR_(midi)("NewAUGraph return %s\n", wine_dbgstr_fourcc(err));
408         return 0;
409     }
410
411     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
412     desc.componentFlags = 0;
413     desc.componentFlagsMask = 0;
414
415     /* create synth node */
416     desc.componentType = kAudioUnitType_MusicDevice;
417     desc.componentSubType = kAudioUnitSubType_DLSSynth;
418
419     err = AUGraphAddNode(*graph, &desc, &synthNode);
420     if (err != noErr)
421     {
422         ERR_(midi)("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(err));
423         return 0;
424     }
425
426     /* create out node */
427     desc.componentType = kAudioUnitType_Output;
428     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
429
430     err = AUGraphAddNode(*graph, &desc, &outNode);
431     if (err != noErr)
432     {
433         ERR_(midi)("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(err));
434         return 0;
435     }
436
437     err = AUGraphOpen(*graph);
438     if (err != noErr)
439     {
440         ERR_(midi)("AUGraphOpen return %s\n", wine_dbgstr_fourcc(err));
441         return 0;
442     }
443
444     /* connecting the nodes */
445     err = AUGraphConnectNodeInput(*graph, synthNode, 0, outNode, 0);
446     if (err != noErr)
447     {
448         ERR_(midi)("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", wine_dbgstr_fourcc(err));
449         return 0;
450     }
451
452     /* Get the synth unit */
453     err = AUGraphNodeInfo(*graph, synthNode, 0, synth);
454     if (err != noErr)
455     {
456         ERR_(midi)("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(err));
457         return 0;
458     }
459
460     return 1;
461 }
462
463 int SynthUnit_Initialize(AudioUnit synth, AUGraph graph)
464 {
465     OSStatus err = noErr;
466
467     err = AUGraphInitialize(graph);
468     if (err != noErr)
469     {
470         ERR_(midi)("AUGraphInitialize(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
471         return 0;
472     }
473
474     err = AUGraphStart(graph);
475     if (err != noErr)
476     {
477         ERR_(midi)("AUGraphStart(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
478         return 0;
479     }
480
481     return 1;
482 }
483
484 int SynthUnit_Close(AUGraph graph)
485 {
486     OSStatus err = noErr;
487
488     err = AUGraphStop(graph);
489     if (err != noErr)
490     {
491         ERR_(midi)("AUGraphStop(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
492         return 0;
493     }
494
495     err = DisposeAUGraph(graph);
496     if (err != noErr)
497     {
498         ERR_(midi)("DisposeAUGraph(%p) return %s\n", graph, wine_dbgstr_fourcc(err));
499         return 0;
500     }
501
502     return 1;
503 }