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