winecoreaudio: Renamed the dlls/winmm/winecoreaudio directory to dlls/winecoreaudio...
[wine] / dlls / winecoreaudio.drv / audio.c
1 /*
2  * Wine Driver for CoreAudio based on Jack Driver
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn)
6  * Copyright 2000 Eric Pouech (loops in waveOut)
7  * Copyright 2002 Chris Morgan (jack version of this file)
8  * Copyright 2005, 2006 Emmanuel Maillard
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <fcntl.h>
35
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winnls.h"
39 #include "wingdi.h"
40 #include "winerror.h"
41 #include "mmddk.h"
42 #include "dsound.h"
43 #include "dsdriver.h"
44 #include "coreaudio.h"
45 #include "wine/unicode.h"
46 #include "wine/library.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(wave);
50
51
52 #if defined(HAVE_COREAUDIO_COREAUDIO_H) && defined(HAVE_AUDIOUNIT_AUDIOUNIT_H)
53 #include <CoreAudio/CoreAudio.h>
54 #include <CoreFoundation/CoreFoundation.h>
55 #include <libkern/OSAtomic.h>
56
57 /*
58     Due to AudioUnit headers conflict define some needed types.
59 */
60
61 typedef void *AudioUnit;
62
63 /* From AudioUnit/AUComponents.h */
64 enum
65 {
66     kAudioUnitRenderAction_OutputIsSilence  = (1 << 4),
67         /* provides hint on return from Render(): if set the buffer contains all zeroes */
68 };
69 typedef UInt32 AudioUnitRenderActionFlags;
70
71 typedef long ComponentResult;
72 extern ComponentResult
73 AudioUnitRender(                    AudioUnit                       ci,
74                                     AudioUnitRenderActionFlags *    ioActionFlags,
75                                     const AudioTimeStamp *          inTimeStamp,
76                                     UInt32                          inOutputBusNumber,
77                                     UInt32                          inNumberFrames,
78                                     AudioBufferList *               ioData)         AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER;
79
80 /* only allow 10 output devices through this driver, this ought to be adequate */
81 #define MAX_WAVEOUTDRV  (1)
82 #define MAX_WAVEINDRV   (1)
83
84 /* state diagram for waveOut writing:
85 *
86 * +---------+-------------+---------------+---------------------------------+
87 * |  state  |  function   |     event     |            new state             |
88 * +---------+-------------+---------------+---------------------------------+
89 * |          | open()      |               | STOPPED                         |
90 * | PAUSED  | write()      |               | PAUSED                          |
91 * | STOPPED | write()      | <thrd create> | PLAYING                         |
92 * | PLAYING | write()      | HEADER        | PLAYING                         |
93 * | (other) | write()      | <error>       |                                 |
94 * | (any)   | pause()      | PAUSING       | PAUSED                          |
95 * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
96 * | (any)   | reset()      | RESETTING     | STOPPED                         |
97 * | (any)   | close()      | CLOSING       | CLOSED                          |
98 * +---------+-------------+---------------+---------------------------------+
99 */
100
101 /* states of the playing device */
102 #define WINE_WS_PLAYING   0
103 #define WINE_WS_PAUSED    1
104 #define WINE_WS_STOPPED   2
105 #define WINE_WS_CLOSED    3
106
107 typedef struct tagCoreAudio_Device {
108     char                        dev_name[32];
109     char                        mixer_name[32];
110     unsigned                    open_count;
111     char*                       interface_name;
112     
113     WAVEOUTCAPSW                out_caps;
114     WAVEINCAPSW                 in_caps;
115     DWORD                       in_caps_support;
116     int                         sample_rate;
117     int                         stereo;
118     int                         format;
119     unsigned                    audio_fragment;
120     BOOL                        full_duplex;
121     BOOL                        bTriggerSupport;
122     BOOL                        bOutputEnabled;
123     BOOL                        bInputEnabled;
124     DSDRIVERDESC                ds_desc;
125     DSDRIVERCAPS                ds_caps;
126     DSCDRIVERCAPS               dsc_caps;
127     GUID                        ds_guid;
128     GUID                        dsc_guid;
129     
130     AudioDeviceID outputDeviceID;
131     AudioDeviceID inputDeviceID;
132     AudioStreamBasicDescription streamDescription;
133 } CoreAudio_Device;
134
135 /* for now use the default device */
136 static CoreAudio_Device CoreAudio_DefaultDevice;
137
138 typedef struct {
139     volatile int                state;      /* one of the WINE_WS_ manifest constants */
140     CoreAudio_Device            *cadev;
141     WAVEOPENDESC                waveDesc;
142     WORD                        wFlags;
143     PCMWAVEFORMAT               format;
144     DWORD                       woID;
145     AudioUnit                   audioUnit;
146     AudioStreamBasicDescription streamDescription;
147     
148     WAVEOUTCAPSW                caps;
149     char                        interface_name[32];
150     LPWAVEHDR                   lpQueuePtr;             /* start of queued WAVEHDRs (waiting to be notified) */
151     LPWAVEHDR                   lpPlayPtr;              /* start of not yet fully played buffers */
152     DWORD                       dwPartialOffset;        /* Offset of not yet written bytes in lpPlayPtr */
153     
154     LPWAVEHDR                   lpLoopPtr;              /* pointer of first buffer in loop, if any */
155     DWORD                       dwLoops;                /* private copy of loop counter */
156     
157     DWORD                       dwPlayedTotal;          /* number of bytes actually played since opening */
158     DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
159         
160     DWORD                       tickCountMS; /* time in MS of last AudioUnit callback */
161
162     OSSpinLock                  lock;         /* synchronization stuff */
163
164     BOOL trace_on;
165     BOOL warn_on;
166     BOOL err_on;
167 } WINE_WAVEOUT;
168
169 typedef struct {
170     /* This device's device number */
171     DWORD           wiID;
172
173     /* Access to the following fields is synchronized across threads. */
174     volatile int    state;
175     LPWAVEHDR       lpQueuePtr;
176     DWORD           dwTotalRecorded;
177
178     /* Synchronization mechanism to protect above fields */
179     OSSpinLock      lock;
180
181     /* Capabilities description */
182     WAVEINCAPSW     caps;
183     char            interface_name[32];
184
185     /* Record the arguments used when opening the device. */
186     WAVEOPENDESC    waveDesc;
187     WORD            wFlags;
188     PCMWAVEFORMAT   format;
189
190     AudioUnit       audioUnit;
191     AudioBufferList*bufferList;
192
193     /* Record state of debug channels at open.  Used to control fprintf's since
194      * we can't use Wine debug channel calls in non-Wine AudioUnit threads. */
195     BOOL            trace_on;
196     BOOL            warn_on;
197     BOOL            err_on;
198
199 /* These fields aren't used. */
200 #if 0
201     CoreAudio_Device *cadev;
202
203     AudioStreamBasicDescription streamDescription;
204 #endif
205 } WINE_WAVEIN;
206
207 static WINE_WAVEOUT WOutDev   [MAX_WAVEOUTDRV];
208 static WINE_WAVEIN  WInDev    [MAX_WAVEINDRV];
209
210 static HANDLE hThread = NULL; /* Track the thread we create so we can clean it up later */
211 static CFMessagePortRef Port_SendToMessageThread;
212
213 static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
214 static void wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
215 static void widHelper_NotifyCompletions(WINE_WAVEIN* wwi);
216
217 extern int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
218 extern int AudioUnit_CloseAudioUnit(AudioUnit au);
219 extern int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *streamFormat);
220
221 extern OSStatus AudioOutputUnitStart(AudioUnit au);
222 extern OSStatus AudioOutputUnitStop(AudioUnit au);
223 extern OSStatus AudioUnitUninitialize(AudioUnit au);
224
225 extern int AudioUnit_SetVolume(AudioUnit au, float left, float right);
226 extern int AudioUnit_GetVolume(AudioUnit au, float *left, float *right);
227
228 extern int AudioUnit_GetInputDeviceSampleRate(void);
229
230 extern int AudioUnit_CreateInputUnit(void* wwi, AudioUnit* out_au,
231         WORD nChannels, DWORD nSamplesPerSec, WORD wBitsPerSample,
232         UInt32* outFrameCount);
233
234 OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
235                                      AudioUnitRenderActionFlags *ioActionFlags, 
236                                      const AudioTimeStamp *inTimeStamp, 
237                                      UInt32 inBusNumber, 
238                                      UInt32 inNumberFrames, 
239                                      AudioBufferList *ioData);
240 OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
241                                      AudioUnitRenderActionFlags *ioActionFlags,
242                                      const AudioTimeStamp *inTimeStamp,
243                                      UInt32 inBusNumber,
244                                      UInt32 inNumberFrames,
245                                      AudioBufferList *ioData);
246
247 /* These strings used only for tracing */
248
249 static const char * getMessage(UINT msg)
250 {
251     static char unknown[32];
252 #define MSG_TO_STR(x) case x: return #x
253     switch(msg) {
254         MSG_TO_STR(DRVM_INIT);
255         MSG_TO_STR(DRVM_EXIT);
256         MSG_TO_STR(DRVM_ENABLE);
257         MSG_TO_STR(DRVM_DISABLE);
258         MSG_TO_STR(WIDM_OPEN);
259         MSG_TO_STR(WIDM_CLOSE);
260         MSG_TO_STR(WIDM_ADDBUFFER);
261         MSG_TO_STR(WIDM_PREPARE);
262         MSG_TO_STR(WIDM_UNPREPARE);
263         MSG_TO_STR(WIDM_GETDEVCAPS);
264         MSG_TO_STR(WIDM_GETNUMDEVS);
265         MSG_TO_STR(WIDM_GETPOS);
266         MSG_TO_STR(WIDM_RESET);
267         MSG_TO_STR(WIDM_START);
268         MSG_TO_STR(WIDM_STOP);
269         MSG_TO_STR(WODM_OPEN);
270         MSG_TO_STR(WODM_CLOSE);
271         MSG_TO_STR(WODM_WRITE);
272         MSG_TO_STR(WODM_PAUSE);
273         MSG_TO_STR(WODM_GETPOS);
274         MSG_TO_STR(WODM_BREAKLOOP);
275         MSG_TO_STR(WODM_PREPARE);
276         MSG_TO_STR(WODM_UNPREPARE);
277         MSG_TO_STR(WODM_GETDEVCAPS);
278         MSG_TO_STR(WODM_GETNUMDEVS);
279         MSG_TO_STR(WODM_GETPITCH);
280         MSG_TO_STR(WODM_SETPITCH);
281         MSG_TO_STR(WODM_GETPLAYBACKRATE);
282         MSG_TO_STR(WODM_SETPLAYBACKRATE);
283         MSG_TO_STR(WODM_GETVOLUME);
284         MSG_TO_STR(WODM_SETVOLUME);
285         MSG_TO_STR(WODM_RESTART);
286         MSG_TO_STR(WODM_RESET);
287         MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
288         MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
289         MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
290         MSG_TO_STR(DRV_QUERYDSOUNDDESC);
291     }
292 #undef MSG_TO_STR
293     sprintf(unknown, "UNKNOWN(0x%04x)", msg);
294     return unknown;
295 }
296
297 #define kStopLoopMessage 0
298 #define kWaveOutNotifyCompletionsMessage 1
299 #define kWaveInNotifyCompletionsMessage 2
300
301 /* Mach Message Handling */
302 static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info)
303 {
304     UInt32 *buffer = NULL;
305
306     switch (msgid)
307     {
308         case kWaveOutNotifyCompletionsMessage:
309             buffer = (UInt32 *) CFDataGetBytePtr(data);
310             wodHelper_NotifyCompletions(&WOutDev[buffer[0]], FALSE);
311             break;
312         case kWaveInNotifyCompletionsMessage:
313             buffer = (UInt32 *) CFDataGetBytePtr(data);
314             widHelper_NotifyCompletions(&WInDev[buffer[0]]);
315             break;
316         default:
317             CFRunLoopStop(CFRunLoopGetCurrent());
318             break;
319     }
320     
321     return NULL;
322 }
323
324 static DWORD WINAPI messageThread(LPVOID p)
325 {
326     CFMessagePortRef port_ReceiveInMessageThread = (CFMessagePortRef) p;
327     CFRunLoopSourceRef source;
328     
329     source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port_ReceiveInMessageThread, (CFIndex)0);
330     CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
331
332     CFRunLoopRun();
333
334     CFRunLoopSourceInvalidate(source);
335     CFRelease(source);
336     CFRelease(port_ReceiveInMessageThread);
337
338     return 0;
339 }
340
341 /**************************************************************************
342 *                       wodSendNotifyCompletionsMessage                 [internal]
343 *   Call from AudioUnit IO thread can't use Wine debug channels.
344 */
345 static void wodSendNotifyCompletionsMessage(WINE_WAVEOUT* wwo)
346 {
347     CFDataRef data;
348     UInt32 buffer;
349
350     buffer = (UInt32) wwo->woID;
351
352     data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&buffer, sizeof(buffer));
353     if (!data)
354         return;
355
356     CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
357     CFRelease(data);
358 }
359
360 /**************************************************************************
361 *                       wodSendNotifyInputCompletionsMessage     [internal]
362 *   Call from AudioUnit IO thread can't use Wine debug channels.
363 */
364 static void wodSendNotifyInputCompletionsMessage(WINE_WAVEIN* wwi)
365 {
366     CFDataRef data;
367     UInt32 buffer;
368
369     buffer = (UInt32) wwi->wiID;
370
371     data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&buffer, sizeof(buffer));
372     if (!data)
373         return;
374
375     CFMessagePortSendRequest(Port_SendToMessageThread, kWaveInNotifyCompletionsMessage, data, 0.0, 0.0, NULL, NULL);
376     CFRelease(data);
377 }
378
379 static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
380                              PCMWAVEFORMAT* format)
381 {
382     TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
383           lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
384           format->wf.nChannels, format->wf.nAvgBytesPerSec);
385     TRACE("Position in bytes=%u\n", position);
386
387     switch (lpTime->wType) {
388     case TIME_SAMPLES:
389         lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
390         TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
391         break;
392     case TIME_MS:
393         lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
394         TRACE("TIME_MS=%u\n", lpTime->u.ms);
395         break;
396     case TIME_SMPTE:
397         lpTime->u.smpte.fps = 30;
398         position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
399         position += (format->wf.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
400         lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
401         position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
402         lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
403         lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
404         lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
405         lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
406         lpTime->u.smpte.fps = 30;
407         lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
408         TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
409               lpTime->u.smpte.hour, lpTime->u.smpte.min,
410               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
411         break;
412     default:
413         WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
414         lpTime->wType = TIME_BYTES;
415         /* fall through */
416     case TIME_BYTES:
417         lpTime->u.cb = position;
418         TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
419         break;
420     }
421     return MMSYSERR_NOERROR;
422 }
423
424 /**************************************************************************
425 *                       CoreAudio_GetDevCaps            [internal]
426 */
427 BOOL CoreAudio_GetDevCaps (void)
428 {
429     OSStatus status;
430     UInt32 propertySize;
431     AudioDeviceID devId = CoreAudio_DefaultDevice.outputDeviceID;
432     
433     char name[MAXPNAMELEN];
434     
435     propertySize = MAXPNAMELEN;
436     status = AudioDeviceGetProperty(devId, 0 , FALSE, kAudioDevicePropertyDeviceName, &propertySize, name);
437     if (status) {
438         ERR("AudioHardwareGetProperty for kAudioDevicePropertyDeviceName return %c%c%c%c\n", (char) (status >> 24),
439                                                                                              (char) (status >> 16),
440                                                                                              (char) (status >> 8),
441                                                                                              (char) status);
442         return FALSE;
443     }
444     
445     memcpy(CoreAudio_DefaultDevice.ds_desc.szDesc, name, sizeof(name));
446     strcpy(CoreAudio_DefaultDevice.ds_desc.szDrvname, "winecoreaudio.drv");
447     MultiByteToWideChar(CP_ACP, 0, name, sizeof(name), 
448                         CoreAudio_DefaultDevice.out_caps.szPname, 
449                         sizeof(CoreAudio_DefaultDevice.out_caps.szPname) / sizeof(WCHAR));
450     memcpy(CoreAudio_DefaultDevice.dev_name, name, 32);
451     
452     propertySize = sizeof(CoreAudio_DefaultDevice.streamDescription);
453     status = AudioDeviceGetProperty(devId, 0, FALSE , kAudioDevicePropertyStreamFormat, &propertySize, &CoreAudio_DefaultDevice.streamDescription);
454     if (status != noErr) {
455         ERR("AudioHardwareGetProperty for kAudioDevicePropertyStreamFormat return %c%c%c%c\n", (char) (status >> 24),
456                                                                                                 (char) (status >> 16),
457                                                                                                 (char) (status >> 8),
458                                                                                                 (char) status);
459         return FALSE;
460     }
461     
462     TRACE("Device Stream Description mSampleRate : %f\n mFormatID : %c%c%c%c\n"
463             "mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n"
464             "mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
465                                CoreAudio_DefaultDevice.streamDescription.mSampleRate,
466                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 24),
467                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 16),
468                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 8),
469                                (char) CoreAudio_DefaultDevice.streamDescription.mFormatID,
470                                CoreAudio_DefaultDevice.streamDescription.mFormatFlags,
471                                CoreAudio_DefaultDevice.streamDescription.mBytesPerPacket,
472                                CoreAudio_DefaultDevice.streamDescription.mFramesPerPacket,
473                                CoreAudio_DefaultDevice.streamDescription.mBytesPerFrame,
474                                CoreAudio_DefaultDevice.streamDescription.mChannelsPerFrame,
475                                CoreAudio_DefaultDevice.streamDescription.mBitsPerChannel);
476     
477     CoreAudio_DefaultDevice.out_caps.wMid = 0xcafe;
478     CoreAudio_DefaultDevice.out_caps.wPid = 0x0001;
479     
480     CoreAudio_DefaultDevice.out_caps.vDriverVersion = 0x0001;
481     CoreAudio_DefaultDevice.out_caps.dwFormats = 0x00000000;
482     CoreAudio_DefaultDevice.out_caps.wReserved1 = 0;
483     CoreAudio_DefaultDevice.out_caps.dwSupport = WAVECAPS_VOLUME;
484     CoreAudio_DefaultDevice.out_caps.dwSupport |= WAVECAPS_LRVOLUME;
485     
486     CoreAudio_DefaultDevice.out_caps.wChannels = 2;
487     CoreAudio_DefaultDevice.out_caps.dwFormats|= WAVE_FORMAT_4S16;
488     
489     return TRUE;
490 }
491
492 /******************************************************************
493 *               CoreAudio_WaveInit
494 *
495 * Initialize CoreAudio_DefaultDevice
496 */
497 LONG CoreAudio_WaveInit(void)
498 {
499     OSStatus status;
500     UInt32 propertySize;
501     CHAR szPname[MAXPNAMELEN];
502     int i;
503     CFStringRef  messageThreadPortName;
504     CFMessagePortRef port_ReceiveInMessageThread;
505     int inputSampleRate;
506
507     TRACE("()\n");
508     
509     /* number of sound cards */
510     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
511     propertySize /= sizeof(AudioDeviceID);
512     TRACE("sound cards : %lu\n", propertySize);
513     
514     /* Get the output device */
515     propertySize = sizeof(CoreAudio_DefaultDevice.outputDeviceID);
516     status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &CoreAudio_DefaultDevice.outputDeviceID);
517     if (status) {
518         ERR("AudioHardwareGetProperty return %c%c%c%c for kAudioHardwarePropertyDefaultOutputDevice\n", (char) (status >> 24),
519                                                                                                 (char) (status >> 16),
520                                                                                                 (char) (status >> 8),
521                                                                                                 (char) status);
522         return 1;
523     }
524     if (CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown) {
525         ERR("AudioHardwareGetProperty: CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown\n");
526         return 1;
527     }
528     
529     if ( ! CoreAudio_GetDevCaps() )
530         return 1;
531     
532     CoreAudio_DefaultDevice.interface_name=HeapAlloc(GetProcessHeap(),0,strlen(CoreAudio_DefaultDevice.dev_name)+1);
533     sprintf(CoreAudio_DefaultDevice.interface_name, "%s", CoreAudio_DefaultDevice.dev_name);
534     
535     for (i = 0; i < MAX_WAVEOUTDRV; ++i)
536     {
537         WOutDev[i].state = WINE_WS_CLOSED;
538         WOutDev[i].cadev = &CoreAudio_DefaultDevice; 
539         WOutDev[i].woID = i;
540         
541         memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
542         
543         WOutDev[i].caps.wMid = 0xcafe;  /* Manufac ID */
544         WOutDev[i].caps.wPid = 0x0001;  /* Product ID */
545         snprintf(szPname, sizeof(szPname), "CoreAudio WaveOut %d", i);
546         MultiByteToWideChar(CP_ACP, 0, szPname, -1, WOutDev[i].caps.szPname, sizeof(WOutDev[i].caps.szPname)/sizeof(WCHAR));
547         snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winecoreaudio: %d", i);
548         
549         WOutDev[i].caps.vDriverVersion = 0x0001;
550         WOutDev[i].caps.dwFormats = 0x00000000;
551         WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
552         
553         WOutDev[i].caps.wChannels = 2;
554       /*  WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME; */ /* FIXME */
555         
556         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96M08;
557         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96S08;
558         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96M16;
559         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_96S16;
560         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48M08;
561         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48S08;
562         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48M16;
563         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_48S16;
564         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
565         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; 
566         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
567         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
568         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
569         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; 
570         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
571         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
572         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
573         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
574         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
575         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
576
577         WOutDev[i].lock = 0; /* initialize the mutex */
578     }
579
580     /* FIXME: implement sample rate conversion on input */
581     inputSampleRate = AudioUnit_GetInputDeviceSampleRate();
582
583     for (i = 0; i < MAX_WAVEINDRV; ++i)
584     {
585         memset(&WInDev[i], 0, sizeof(WInDev[i]));
586         WInDev[i].wiID = i;
587
588         /* Establish preconditions for widOpen */
589         WInDev[i].state = WINE_WS_CLOSED;
590         WInDev[i].lock = 0; /* initialize the mutex */
591
592         /* Fill in capabilities.  widGetDevCaps can be called at any time. */
593         WInDev[i].caps.wMid = 0xcafe;   /* Manufac ID */
594         WInDev[i].caps.wPid = 0x0001;   /* Product ID */
595         WInDev[i].caps.vDriverVersion = 0x0001;
596
597         snprintf(szPname, sizeof(szPname), "CoreAudio WaveIn %d", i);
598         MultiByteToWideChar(CP_ACP, 0, szPname, -1, WInDev[i].caps.szPname, sizeof(WInDev[i].caps.szPname)/sizeof(WCHAR));
599         snprintf(WInDev[i].interface_name, sizeof(WInDev[i].interface_name), "winecoreaudio in: %d", i);
600
601         if (inputSampleRate == 96000)
602         {
603             WInDev[i].caps.dwFormats |= WAVE_FORMAT_96M08;
604             WInDev[i].caps.dwFormats |= WAVE_FORMAT_96S08;
605             WInDev[i].caps.dwFormats |= WAVE_FORMAT_96M16;
606             WInDev[i].caps.dwFormats |= WAVE_FORMAT_96S16;
607         }
608         if (inputSampleRate == 48000)
609         {
610             WInDev[i].caps.dwFormats |= WAVE_FORMAT_48M08;
611             WInDev[i].caps.dwFormats |= WAVE_FORMAT_48S08;
612             WInDev[i].caps.dwFormats |= WAVE_FORMAT_48M16;
613             WInDev[i].caps.dwFormats |= WAVE_FORMAT_48S16;
614         }
615         if (inputSampleRate == 44100)
616         {
617             WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
618             WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;
619             WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
620             WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
621         }
622         if (inputSampleRate == 22050)
623         {
624             WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
625             WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;
626             WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
627             WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
628         }
629         if (inputSampleRate == 11025)
630         {
631             WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
632             WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
633             WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
634             WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
635         }
636
637         WInDev[i].caps.wChannels = 2;
638     }
639
640     /* create mach messages handler */
641     srandomdev();
642     messageThreadPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
643         CFSTR("WaveMessagePort.%d.%lu"), getpid(), (unsigned long)random());
644     if (!messageThreadPortName)
645     {
646         ERR("Can't create message thread port name\n");
647         return 1;
648     }
649
650     port_ReceiveInMessageThread = CFMessagePortCreateLocal(kCFAllocatorDefault, messageThreadPortName,
651                                         &wodMessageHandler, NULL, NULL);
652     if (!port_ReceiveInMessageThread)
653     {
654         ERR("Can't create message thread local port\n");
655         CFRelease(messageThreadPortName);
656         return 1;
657     }
658
659     Port_SendToMessageThread = CFMessagePortCreateRemote(kCFAllocatorDefault, messageThreadPortName);
660     CFRelease(messageThreadPortName);
661     if (!Port_SendToMessageThread)
662     {
663         ERR("Can't create port for sending to message thread\n");
664         CFRelease(port_ReceiveInMessageThread);
665         return 1;
666     }
667
668     /* Cannot WAIT for any events because we are called from the loader (which has a lock on loading stuff) */
669     /* We might want to wait for this thread to be created -- but we cannot -- not here at least */
670     /* Instead track the thread so we can clean it up later */
671     if ( hThread )
672     {
673         ERR("Message thread already started -- expect problems\n");
674     }
675     hThread = CreateThread(NULL, 0, messageThread, (LPVOID)port_ReceiveInMessageThread, 0, NULL);
676     if ( !hThread )
677     {
678         ERR("Can't create message thread\n");
679         CFRelease(port_ReceiveInMessageThread);
680         CFRelease(Port_SendToMessageThread);
681         Port_SendToMessageThread = NULL;
682         return 1;
683     }
684
685     /* The message thread is responsible for releasing port_ReceiveInMessageThread. */
686
687     return 0;
688 }
689
690 void CoreAudio_WaveRelease(void)
691 {
692     /* Stop CFRunLoop in messageThread */
693     TRACE("()\n");
694
695     CFMessagePortSendRequest(Port_SendToMessageThread, kStopLoopMessage, NULL, 0.0, 0.0, NULL, NULL);
696     CFRelease(Port_SendToMessageThread);
697     Port_SendToMessageThread = NULL;
698
699     /* Wait for the thread to finish and clean it up */
700     /* This rids us of any quick start/shutdown driver crashes */
701     WaitForSingleObject(hThread, INFINITE);
702     CloseHandle(hThread);
703     hThread = NULL;
704 }
705
706 /*======================================================================*
707 *                  Low level WAVE OUT implementation                    *
708 *======================================================================*/
709
710 /**************************************************************************
711 *                       wodNotifyClient                 [internal]
712 */
713 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
714 {
715     switch (wMsg) {
716         case WOM_OPEN:
717         case WOM_CLOSE:
718         case WOM_DONE:
719             if (wwo->wFlags != DCB_NULL &&
720                 !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
721                                 (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
722                                 dwParam1, dwParam2))
723             {
724                 return MMSYSERR_ERROR;
725             }
726             break;
727         default:
728             return MMSYSERR_INVALPARAM;
729     }
730     return MMSYSERR_NOERROR;
731 }
732
733
734 /**************************************************************************
735 *                       wodGetDevCaps               [internal]
736 */
737 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
738 {
739     TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
740     
741     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
742     
743     if (wDevID >= MAX_WAVEOUTDRV)
744     {
745         TRACE("MAX_WAVOUTDRV reached !\n");
746         return MMSYSERR_BADDEVICEID;
747     }
748     
749     TRACE("dwSupport=(0x%x), dwFormats=(0x%x)\n", WOutDev[wDevID].caps.dwSupport, WOutDev[wDevID].caps.dwFormats);
750     memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
751     return MMSYSERR_NOERROR;
752 }
753
754 /**************************************************************************
755 *                               wodOpen                         [internal]
756 */
757 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
758 {
759     WINE_WAVEOUT*       wwo;
760     DWORD retval;
761     DWORD               ret;
762     AudioStreamBasicDescription streamFormat;
763
764     TRACE("(%u, %p, %08x);\n", wDevID, lpDesc, dwFlags);
765     if (lpDesc == NULL)
766     {
767         WARN("Invalid Parameter !\n");
768         return MMSYSERR_INVALPARAM;
769     }
770     if (wDevID >= MAX_WAVEOUTDRV) {
771         TRACE("MAX_WAVOUTDRV reached !\n");
772         return MMSYSERR_BADDEVICEID;
773     }
774     
775     TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
776           lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
777           lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
778     
779     if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
780         lpDesc->lpFormat->nChannels == 0 ||
781         lpDesc->lpFormat->nSamplesPerSec == 0
782          )
783     {
784         WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
785              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
786              lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
787         return WAVERR_BADFORMAT;
788     }
789     
790     if (dwFlags & WAVE_FORMAT_QUERY)
791     {
792         TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
793               lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
794               lpDesc->lpFormat->nSamplesPerSec);
795         return MMSYSERR_NOERROR;
796     }
797     
798     wwo = &WOutDev[wDevID];
799     if (!OSSpinLockTry(&wwo->lock))
800         return MMSYSERR_ALLOCATED;
801
802     if (wwo->state != WINE_WS_CLOSED)
803     {
804         OSSpinLockUnlock(&wwo->lock);
805         return MMSYSERR_ALLOCATED;
806     }
807
808     if (!AudioUnit_CreateDefaultAudioUnit((void *) wwo, &wwo->audioUnit))
809     {
810         ERR("CoreAudio_CreateDefaultAudioUnit(%p) failed\n", wwo);
811         OSSpinLockUnlock(&wwo->lock);
812         return MMSYSERR_ERROR;
813     }
814
815     if ((dwFlags & WAVE_DIRECTSOUND) && 
816         !(wwo->caps.dwSupport & WAVECAPS_DIRECTSOUND))
817         /* not supported, ignore it */
818         dwFlags &= ~WAVE_DIRECTSOUND;
819
820     streamFormat.mFormatID = kAudioFormatLinearPCM;
821     streamFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
822     /* FIXME check for 32bits float -> kLinearPCMFormatFlagIsFloat */
823     if (lpDesc->lpFormat->wBitsPerSample != 8)
824         streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
825 # ifdef WORDS_BIGENDIAN
826     streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; /* FIXME Wave format is little endian */
827 # endif
828
829     streamFormat.mSampleRate = lpDesc->lpFormat->nSamplesPerSec;
830     streamFormat.mChannelsPerFrame = lpDesc->lpFormat->nChannels;       
831     streamFormat.mFramesPerPacket = 1;  
832     streamFormat.mBitsPerChannel = lpDesc->lpFormat->wBitsPerSample;
833     streamFormat.mBytesPerFrame = streamFormat.mBitsPerChannel * streamFormat.mChannelsPerFrame / 8;    
834     streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket;         
835
836     ret = AudioUnit_InitializeWithStreamDescription(wwo->audioUnit, &streamFormat);
837     if (!ret) 
838     {
839         AudioUnit_CloseAudioUnit(wwo->audioUnit);
840         OSSpinLockUnlock(&wwo->lock);
841         return WAVERR_BADFORMAT; /* FIXME return an error based on the OSStatus */
842     }
843     wwo->streamDescription = streamFormat;
844
845     ret = AudioOutputUnitStart(wwo->audioUnit);
846     if (ret)
847     {
848         ERR("AudioOutputUnitStart failed: %08x\n", ret);
849         AudioUnitUninitialize(wwo->audioUnit);
850         AudioUnit_CloseAudioUnit(wwo->audioUnit);
851         OSSpinLockUnlock(&wwo->lock);
852         return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
853     }
854
855     wwo->state = WINE_WS_STOPPED;
856                 
857     wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
858     
859     memcpy(&wwo->waveDesc, lpDesc,           sizeof(WAVEOPENDESC));
860     memcpy(&wwo->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
861     
862     if (wwo->format.wBitsPerSample == 0) {
863         WARN("Resetting zeroed wBitsPerSample\n");
864         wwo->format.wBitsPerSample = 8 *
865             (wwo->format.wf.nAvgBytesPerSec /
866              wwo->format.wf.nSamplesPerSec) /
867             wwo->format.wf.nChannels;
868     }
869     
870     wwo->dwPlayedTotal = 0;
871     wwo->dwWrittenTotal = 0;
872
873     wwo->trace_on = TRACE_ON(wave);
874     wwo->warn_on  = WARN_ON(wave);
875     wwo->err_on   = ERR_ON(wave);
876
877     OSSpinLockUnlock(&wwo->lock);
878     
879     retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
880     
881     return retval;
882 }
883
884 /**************************************************************************
885 *                               wodClose                        [internal]
886 */
887 static DWORD wodClose(WORD wDevID)
888 {
889     DWORD               ret = MMSYSERR_NOERROR;
890     WINE_WAVEOUT*       wwo;
891     
892     TRACE("(%u);\n", wDevID);
893     
894     if (wDevID >= MAX_WAVEOUTDRV)
895     {
896         WARN("bad device ID !\n");
897         return MMSYSERR_BADDEVICEID;
898     }
899     
900     wwo = &WOutDev[wDevID];
901     OSSpinLockLock(&wwo->lock);
902     if (wwo->lpQueuePtr)
903     {
904         WARN("buffers still playing !\n");
905         OSSpinLockUnlock(&wwo->lock);
906         ret = WAVERR_STILLPLAYING;
907     } else
908     {
909         OSStatus err;
910         /* sanity check: this should not happen since the device must have been reset before */
911         if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
912         
913         wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
914         
915         OSSpinLockUnlock(&wwo->lock);
916
917         err = AudioUnitUninitialize(wwo->audioUnit);
918         if (err) {
919             ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24),
920                                                             (char) (err >> 16),
921                                                             (char) (err >> 8),
922                                                             (char) err);
923             return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
924         }
925         
926         if ( !AudioUnit_CloseAudioUnit(wwo->audioUnit) )
927         {
928             ERR("Can't close AudioUnit\n");
929             return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
930         }  
931         
932         ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
933     }
934     
935     return ret;
936 }
937
938 /**************************************************************************
939 *                               wodPrepare                      [internal]
940 */
941 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
942 {
943     TRACE("(%u, %p, %08x);\n", wDevID, lpWaveHdr, dwSize);
944     
945     if (wDevID >= MAX_WAVEOUTDRV) {
946         WARN("bad device ID !\n");
947         return MMSYSERR_BADDEVICEID;
948     }
949     
950     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
951         return WAVERR_STILLPLAYING;
952     
953     lpWaveHdr->dwFlags |= WHDR_PREPARED;
954     lpWaveHdr->dwFlags &= ~WHDR_DONE;
955
956     return MMSYSERR_NOERROR;
957 }
958
959 /**************************************************************************
960 *                               wodUnprepare                    [internal]
961 */
962 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
963 {
964     TRACE("(%u, %p, %08x);\n", wDevID, lpWaveHdr, dwSize);
965     
966     if (wDevID >= MAX_WAVEOUTDRV) {
967         WARN("bad device ID !\n");
968         return MMSYSERR_BADDEVICEID;
969     }
970     
971     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
972         return WAVERR_STILLPLAYING;
973     
974     lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
975     lpWaveHdr->dwFlags |= WHDR_DONE;
976    
977     return MMSYSERR_NOERROR;
978 }
979
980
981 /**************************************************************************
982 *                               wodHelper_CheckForLoopBegin             [internal]
983 *
984 * Check if the new waveheader is the beginning of a loop, and set up
985 * state if so.
986 * This is called with the WAVEOUT lock held.
987 * Call from AudioUnit IO thread can't use Wine debug channels.
988 */
989 static void wodHelper_CheckForLoopBegin(WINE_WAVEOUT* wwo)
990 {
991     LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
992
993     if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
994     {
995         if (wwo->lpLoopPtr)
996         {
997             if (wwo->warn_on)
998                 fprintf(stderr, "warn:winecoreaudio:wodHelper_CheckForLoopBegin Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
999         }
1000         else
1001         {
1002             if (wwo->trace_on)
1003                 fprintf(stderr, "trace:winecoreaudio:wodHelper_CheckForLoopBegin Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
1004
1005             wwo->lpLoopPtr = lpWaveHdr;
1006             /* Windows does not touch WAVEHDR.dwLoops,
1007                 * so we need to make an internal copy */
1008             wwo->dwLoops = lpWaveHdr->dwLoops;
1009         }
1010     }
1011 }
1012
1013
1014 /**************************************************************************
1015 *                               wodHelper_PlayPtrNext           [internal]
1016 *
1017 * Advance the play pointer to the next waveheader, looping if required.
1018 * This is called with the WAVEOUT lock held.
1019 * Call from AudioUnit IO thread can't use Wine debug channels.
1020 */
1021 static void wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
1022 {
1023     BOOL didLoopBack = FALSE;
1024
1025     wwo->dwPartialOffset = 0;
1026     if ((wwo->lpPlayPtr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
1027     {
1028         /* We're at the end of a loop, loop if required */
1029         if (wwo->dwLoops > 1)
1030         {
1031             wwo->dwLoops--;
1032             wwo->lpPlayPtr = wwo->lpLoopPtr;
1033             didLoopBack = TRUE;
1034         }
1035         else
1036         {
1037             wwo->lpLoopPtr = NULL;
1038         }
1039     }
1040     if (!didLoopBack)
1041     {
1042         /* We didn't loop back.  Advance to the next wave header */
1043         wwo->lpPlayPtr = wwo->lpPlayPtr->lpNext;
1044
1045         if (!wwo->lpPlayPtr)
1046             wwo->state = WINE_WS_STOPPED;
1047         else
1048             wodHelper_CheckForLoopBegin(wwo);
1049     }
1050 }
1051
1052 /* if force is TRUE then notify the client that all the headers were completed
1053  */
1054 static void wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
1055 {
1056     LPWAVEHDR           lpWaveHdr;
1057     LPWAVEHDR           lpFirstDoneWaveHdr = NULL;
1058
1059     OSSpinLockLock(&wwo->lock);
1060
1061     /* First, excise all of the done headers from the queue into
1062      * a free-standing list. */
1063     if (force)
1064     {
1065         lpFirstDoneWaveHdr = wwo->lpQueuePtr;
1066         wwo->lpQueuePtr = NULL;
1067     }
1068     else
1069     {
1070         LPWAVEHDR lpLastDoneWaveHdr = NULL;
1071
1072         /* Start from lpQueuePtr and keep notifying until:
1073             * - we hit an unwritten wavehdr
1074             * - we hit the beginning of a running loop
1075             * - we hit a wavehdr which hasn't finished playing
1076             */
1077         for (
1078             lpWaveHdr = wwo->lpQueuePtr;
1079             lpWaveHdr &&
1080                 lpWaveHdr != wwo->lpPlayPtr &&
1081                 lpWaveHdr != wwo->lpLoopPtr;
1082             lpWaveHdr = lpWaveHdr->lpNext
1083             )
1084         {
1085             if (!lpFirstDoneWaveHdr)
1086                 lpFirstDoneWaveHdr = lpWaveHdr;
1087             lpLastDoneWaveHdr = lpWaveHdr;
1088         }
1089
1090         if (lpLastDoneWaveHdr)
1091         {
1092             wwo->lpQueuePtr = lpLastDoneWaveHdr->lpNext;
1093             lpLastDoneWaveHdr->lpNext = NULL;
1094         }
1095     }
1096     
1097     OSSpinLockUnlock(&wwo->lock);
1098
1099     /* Now, send the "done" notification for each header in our list. */
1100     for (lpWaveHdr = lpFirstDoneWaveHdr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext)
1101     {
1102         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1103         lpWaveHdr->dwFlags |= WHDR_DONE;
1104
1105         wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
1106     }
1107 }
1108
1109
1110 /**************************************************************************
1111 *                               wodWrite                        [internal]
1112
1113 */
1114 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1115 {
1116     LPWAVEHDR*wh;
1117     WINE_WAVEOUT *wwo;
1118     
1119     TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
1120     
1121     /* first, do the sanity checks... */
1122     if (wDevID >= MAX_WAVEOUTDRV)
1123     {
1124         WARN("bad dev ID !\n");
1125         return MMSYSERR_BADDEVICEID;
1126     }
1127     
1128     wwo = &WOutDev[wDevID];
1129     
1130     if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1131     {
1132         TRACE("unprepared\n");
1133         return WAVERR_UNPREPARED;
1134     }
1135     
1136     if (lpWaveHdr->dwFlags & WHDR_INQUEUE) 
1137     {
1138         TRACE("still playing\n");
1139         return WAVERR_STILLPLAYING;
1140     }
1141     
1142     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1143     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1144     lpWaveHdr->lpNext = 0;
1145
1146     OSSpinLockLock(&wwo->lock);
1147     /* insert buffer at the end of queue */
1148     for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
1149         /* Do nothing */;
1150     *wh = lpWaveHdr;
1151     
1152     if (!wwo->lpPlayPtr)
1153     {
1154         wwo->lpPlayPtr = lpWaveHdr;
1155
1156         if (wwo->state == WINE_WS_STOPPED)
1157             wwo->state = WINE_WS_PLAYING;
1158
1159         wodHelper_CheckForLoopBegin(wwo);
1160
1161         wwo->dwPartialOffset = 0;
1162     }
1163     OSSpinLockUnlock(&wwo->lock);
1164
1165     return MMSYSERR_NOERROR;
1166 }
1167
1168 /**************************************************************************
1169 *                       wodPause                                [internal]
1170 */
1171 static DWORD wodPause(WORD wDevID)
1172 {
1173     OSStatus status;
1174
1175     TRACE("(%u);!\n", wDevID);
1176     
1177     if (wDevID >= MAX_WAVEOUTDRV)
1178     {
1179         WARN("bad device ID !\n");
1180         return MMSYSERR_BADDEVICEID;
1181     }
1182
1183     /* The order of the following operations is important since we can't hold
1184      * the mutex while we make an Audio Unit call.  Stop the Audio Unit before
1185      * setting the PAUSED state.  In wodRestart, the order is reversed.  This
1186      * guarantees that we can't get into a situation where the state is
1187      * PLAYING or STOPPED but the Audio Unit isn't running.  Although we can
1188      * be in PAUSED state with the Audio Unit still running, that's harmless
1189      * because the render callback will just produce silence.
1190      */
1191     status = AudioOutputUnitStop(WOutDev[wDevID].audioUnit);
1192     if (status) {
1193         WARN("AudioOutputUnitStop return %c%c%c%c\n",
1194              (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1195     }
1196
1197     OSSpinLockLock(&WOutDev[wDevID].lock);
1198     if (WOutDev[wDevID].state == WINE_WS_PLAYING || WOutDev[wDevID].state == WINE_WS_STOPPED)
1199         WOutDev[wDevID].state = WINE_WS_PAUSED;
1200     OSSpinLockUnlock(&WOutDev[wDevID].lock);
1201
1202     return MMSYSERR_NOERROR;
1203 }
1204
1205 /**************************************************************************
1206 *                       wodRestart                              [internal]
1207 */
1208 static DWORD wodRestart(WORD wDevID)
1209 {
1210     OSStatus status;
1211
1212     TRACE("(%u);\n", wDevID);
1213     
1214     if (wDevID >= MAX_WAVEOUTDRV )
1215     {
1216         WARN("bad device ID !\n");
1217         return MMSYSERR_BADDEVICEID;
1218     }
1219
1220     /* The order of the following operations is important since we can't hold
1221      * the mutex while we make an Audio Unit call.  Set the PLAYING/STOPPED
1222      * state before starting the Audio Unit.  In wodPause, the order is
1223      * reversed.  This guarantees that we can't get into a situation where
1224      * the state is PLAYING or STOPPED but the Audio Unit isn't running.
1225      * Although we can be in PAUSED state with the Audio Unit still running,
1226      * that's harmless because the render callback will just produce silence.
1227      */
1228     OSSpinLockLock(&WOutDev[wDevID].lock);
1229     if (WOutDev[wDevID].state == WINE_WS_PAUSED)
1230     {
1231         if (WOutDev[wDevID].lpPlayPtr)
1232             WOutDev[wDevID].state = WINE_WS_PLAYING;
1233         else
1234             WOutDev[wDevID].state = WINE_WS_STOPPED;
1235     }
1236     OSSpinLockUnlock(&WOutDev[wDevID].lock);
1237
1238     status = AudioOutputUnitStart(WOutDev[wDevID].audioUnit);
1239     if (status) {
1240         ERR("AudioOutputUnitStart return %c%c%c%c\n",
1241             (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1242         return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1243     }
1244
1245     return MMSYSERR_NOERROR;
1246 }
1247
1248 /**************************************************************************
1249 *                       wodReset                                [internal]
1250 */
1251 static DWORD wodReset(WORD wDevID)
1252 {
1253     WINE_WAVEOUT* wwo;
1254     OSStatus status;
1255
1256     TRACE("(%u);\n", wDevID);
1257
1258     if (wDevID >= MAX_WAVEOUTDRV)
1259     {
1260         WARN("bad device ID !\n");
1261         return MMSYSERR_BADDEVICEID;
1262     }
1263
1264     wwo = &WOutDev[wDevID];
1265
1266     FIXME("\n");
1267
1268     /* updates current notify list */
1269     /* if resetting, remove all wave headers and notify client that all headers were completed */
1270     wodHelper_NotifyCompletions(wwo, TRUE);
1271     
1272     OSSpinLockLock(&wwo->lock);
1273     
1274     wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
1275     wwo->state = WINE_WS_STOPPED;
1276     wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
1277
1278     wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */
1279
1280     OSSpinLockUnlock(&wwo->lock);
1281
1282     status = AudioOutputUnitStart(wwo->audioUnit);
1283
1284     if (status) {
1285         ERR( "AudioOutputUnitStart return %c%c%c%c\n",
1286              (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1287         return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1288     }
1289
1290     return MMSYSERR_NOERROR;
1291 }
1292
1293 /**************************************************************************
1294 *                               wodGetPosition                  [internal]
1295 */
1296 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1297 {
1298     DWORD               val;
1299     WINE_WAVEOUT*       wwo;
1300
1301     TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
1302     
1303     if (wDevID >= MAX_WAVEOUTDRV)
1304     {
1305         WARN("bad device ID !\n");
1306         return MMSYSERR_BADDEVICEID;
1307     }
1308     
1309     /* if null pointer to time structure return error */
1310     if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1311     
1312     wwo = &WOutDev[wDevID];
1313     
1314     OSSpinLockLock(&WOutDev[wDevID].lock);
1315     val = wwo->dwPlayedTotal;
1316     OSSpinLockUnlock(&WOutDev[wDevID].lock);
1317     
1318     return bytes_to_mmtime(lpTime, val, &wwo->format);
1319 }
1320
1321 /**************************************************************************
1322 *                               wodGetVolume                    [internal]
1323 */
1324 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1325 {
1326     float left;
1327     float right;
1328     
1329     if (wDevID >= MAX_WAVEOUTDRV)
1330     {
1331         WARN("bad device ID !\n");
1332         return MMSYSERR_BADDEVICEID;
1333     }    
1334     
1335     TRACE("(%u, %p);\n", wDevID, lpdwVol);
1336
1337     AudioUnit_GetVolume(WOutDev[wDevID].audioUnit, &left, &right); 
1338
1339     *lpdwVol = ((WORD) left * 0xFFFFl) + (((WORD) right * 0xFFFFl) << 16);
1340     
1341     return MMSYSERR_NOERROR;
1342 }
1343
1344 /**************************************************************************
1345 *                               wodSetVolume                    [internal]
1346 */
1347 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1348 {
1349     float left;
1350     float right;
1351     
1352     if (wDevID >= MAX_WAVEOUTDRV)
1353     {
1354         WARN("bad device ID !\n");
1355         return MMSYSERR_BADDEVICEID;
1356     }
1357
1358     left  = LOWORD(dwParam) / 65535.0f;
1359     right = HIWORD(dwParam) / 65535.0f;
1360     
1361     TRACE("(%u, %08x);\n", wDevID, dwParam);
1362
1363     AudioUnit_SetVolume(WOutDev[wDevID].audioUnit, left, right); 
1364
1365     return MMSYSERR_NOERROR;
1366 }
1367
1368 /**************************************************************************
1369 *                               wodGetNumDevs                   [internal]
1370 */
1371 static DWORD wodGetNumDevs(void)
1372 {
1373     TRACE("\n");
1374     return MAX_WAVEOUTDRV;
1375 }
1376
1377 /**************************************************************************
1378 *                              wodDevInterfaceSize             [internal]
1379 */
1380 static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1381 {
1382     TRACE("(%u, %p)\n", wDevID, dwParam1);
1383     
1384     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1385                                     NULL, 0 ) * sizeof(WCHAR);
1386     return MMSYSERR_NOERROR;
1387 }
1388
1389 /**************************************************************************
1390 *                              wodDevInterface                 [internal]
1391 */
1392 static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1393 {
1394     TRACE("\n");
1395     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1396                                         NULL, 0 ) * sizeof(WCHAR))
1397     {
1398         MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1399                             dwParam1, dwParam2 / sizeof(WCHAR));
1400         return MMSYSERR_NOERROR;
1401     }
1402     return MMSYSERR_INVALPARAM;
1403 }
1404
1405 /**************************************************************************
1406 *                               wodMessage (WINECOREAUDIO.7)
1407 */
1408 DWORD WINAPI CoreAudio_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
1409                                   DWORD dwParam1, DWORD dwParam2)
1410 {
1411     TRACE("(%u, %s, %08x, %08x, %08x);\n",
1412           wDevID, getMessage(wMsg), dwUser, dwParam1, dwParam2);
1413     
1414     switch (wMsg) {
1415         case DRVM_INIT:
1416         case DRVM_EXIT:
1417         case DRVM_ENABLE:
1418         case DRVM_DISABLE:
1419             
1420             /* FIXME: Pretend this is supported */
1421             return 0;
1422         case WODM_OPEN:         return wodOpen(wDevID, (LPWAVEOPENDESC) dwParam1, dwParam2);          
1423         case WODM_CLOSE:        return wodClose(wDevID);
1424         case WODM_WRITE:        return wodWrite(wDevID, (LPWAVEHDR) dwParam1, dwParam2);
1425         case WODM_PAUSE:        return wodPause(wDevID);  
1426         case WODM_GETPOS:       return wodGetPosition(wDevID, (LPMMTIME) dwParam1, dwParam2);
1427         case WODM_BREAKLOOP:    return MMSYSERR_NOTSUPPORTED;
1428         case WODM_PREPARE:      return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1429         case WODM_UNPREPARE:    return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1430             
1431         case WODM_GETDEVCAPS:   return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSW) dwParam1, dwParam2);
1432         case WODM_GETNUMDEVS:   return wodGetNumDevs();  
1433             
1434         case WODM_GETPITCH:         
1435         case WODM_SETPITCH:        
1436         case WODM_GETPLAYBACKRATE:      
1437         case WODM_SETPLAYBACKRATE:      return MMSYSERR_NOTSUPPORTED;
1438         case WODM_GETVOLUME:    return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1439         case WODM_SETVOLUME:    return wodSetVolume(wDevID, dwParam1);
1440         case WODM_RESTART:      return wodRestart(wDevID);
1441         case WODM_RESET:        return wodReset(wDevID);
1442             
1443         case DRV_QUERYDEVICEINTERFACESIZE:  return wodDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
1444         case DRV_QUERYDEVICEINTERFACE:      return wodDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
1445         case DRV_QUERYDSOUNDIFACE:      
1446         case DRV_QUERYDSOUNDDESC:       
1447             return MMSYSERR_NOTSUPPORTED;
1448             
1449         default:
1450             FIXME("unknown message %d!\n", wMsg);
1451     }
1452     
1453     return MMSYSERR_NOTSUPPORTED;
1454 }
1455
1456 /*======================================================================*
1457 *                  Low level DSOUND implementation                      *
1458 *======================================================================*/
1459
1460 typedef struct IDsDriverImpl IDsDriverImpl;
1461 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1462
1463 struct IDsDriverImpl
1464 {
1465     /* IUnknown fields */
1466     const IDsDriverVtbl *lpVtbl;
1467     DWORD               ref;
1468     /* IDsDriverImpl fields */
1469     UINT                wDevID;
1470     IDsDriverBufferImpl*primary;
1471 };
1472
1473 struct IDsDriverBufferImpl
1474 {
1475     /* IUnknown fields */
1476     const IDsDriverBufferVtbl *lpVtbl;
1477     DWORD ref;
1478     /* IDsDriverBufferImpl fields */
1479     IDsDriverImpl* drv;
1480     DWORD buflen;
1481 };
1482
1483
1484 /*
1485     CoreAudio IO threaded callback,
1486     we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
1487 */
1488 OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
1489                                      AudioUnitRenderActionFlags *ioActionFlags, 
1490                                      const AudioTimeStamp *inTimeStamp, 
1491                                      UInt32 inBusNumber, 
1492                                      UInt32 inNumberFrames, 
1493                                      AudioBufferList *ioData)
1494 {
1495     UInt32 buffer;
1496     WINE_WAVEOUT *wwo = (WINE_WAVEOUT *) inRefCon;
1497     int needNotify = 0;
1498
1499     unsigned int dataNeeded = ioData->mBuffers[0].mDataByteSize;
1500     unsigned int dataProvided = 0;
1501
1502     OSSpinLockLock(&wwo->lock);
1503
1504     while (dataNeeded > 0 && wwo->state == WINE_WS_PLAYING && wwo->lpPlayPtr)
1505     {
1506         unsigned int available = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
1507         unsigned int toCopy;
1508
1509         if (available >= dataNeeded)
1510             toCopy = dataNeeded;
1511         else
1512             toCopy = available;
1513
1514         if (toCopy > 0)
1515         {
1516             memcpy((char*)ioData->mBuffers[0].mData + dataProvided,
1517                 wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toCopy);
1518             wwo->dwPartialOffset += toCopy;
1519             wwo->dwPlayedTotal += toCopy;
1520             dataProvided += toCopy;
1521             dataNeeded -= toCopy;
1522             available -= toCopy;
1523         }
1524
1525         if (available == 0)
1526         {
1527             wodHelper_PlayPtrNext(wwo);
1528             needNotify = 1;
1529         }
1530     }
1531
1532     OSSpinLockUnlock(&wwo->lock);
1533
1534     /* We can't provide any more wave data.  Fill the rest with silence. */
1535     if (dataNeeded > 0)
1536     {
1537         if (!dataProvided)
1538             *ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
1539         memset((char*)ioData->mBuffers[0].mData + dataProvided, 0, dataNeeded);
1540         dataProvided += dataNeeded;
1541         dataNeeded = 0;
1542     }
1543
1544     /* We only fill buffer 0.  Set any others that might be requested to 0. */
1545     for (buffer = 1; buffer < ioData->mNumberBuffers; buffer++)
1546     {
1547         memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize);
1548     }
1549
1550     if (needNotify) wodSendNotifyCompletionsMessage(wwo);
1551     return noErr;
1552 }
1553
1554
1555 /*======================================================================*
1556  *                  Low level WAVE IN implementation                    *
1557  *======================================================================*/
1558
1559 /**************************************************************************
1560  *                      widNotifyClient                 [internal]
1561  */
1562 static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
1563 {
1564     TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2);
1565
1566     switch (wMsg)
1567     {
1568         case WIM_OPEN:
1569         case WIM_CLOSE:
1570         case WIM_DATA:
1571             if (wwi->wFlags != DCB_NULL &&
1572                 !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
1573                                 (HDRVR)wwi->waveDesc.hWave, wMsg, wwi->waveDesc.dwInstance,
1574                                 dwParam1, dwParam2))
1575             {
1576                 WARN("can't notify client !\n");
1577                 return MMSYSERR_ERROR;
1578             }
1579             break;
1580         default:
1581             FIXME("Unknown callback message %u\n", wMsg);
1582             return MMSYSERR_INVALPARAM;
1583     }
1584     return MMSYSERR_NOERROR;
1585 }
1586
1587
1588 /**************************************************************************
1589  *                      widHelper_NotifyCompletions              [internal]
1590  */
1591 static void widHelper_NotifyCompletions(WINE_WAVEIN* wwi)
1592 {
1593     LPWAVEHDR       lpWaveHdr;
1594     LPWAVEHDR       lpFirstDoneWaveHdr = NULL;
1595     LPWAVEHDR       lpLastDoneWaveHdr = NULL;
1596
1597     OSSpinLockLock(&wwi->lock);
1598
1599     /* First, excise all of the done headers from the queue into
1600      * a free-standing list. */
1601
1602     /* Start from lpQueuePtr and keep notifying until:
1603         * - we hit an unfilled wavehdr
1604         * - we hit the end of the list
1605         */
1606     for (
1607         lpWaveHdr = wwi->lpQueuePtr;
1608         lpWaveHdr &&
1609             lpWaveHdr->dwBytesRecorded >= lpWaveHdr->dwBufferLength;
1610         lpWaveHdr = lpWaveHdr->lpNext
1611         )
1612     {
1613         if (!lpFirstDoneWaveHdr)
1614             lpFirstDoneWaveHdr = lpWaveHdr;
1615         lpLastDoneWaveHdr = lpWaveHdr;
1616     }
1617
1618     if (lpLastDoneWaveHdr)
1619     {
1620         wwi->lpQueuePtr = lpLastDoneWaveHdr->lpNext;
1621         lpLastDoneWaveHdr->lpNext = NULL;
1622     }
1623
1624     OSSpinLockUnlock(&wwi->lock);
1625
1626     /* Now, send the "done" notification for each header in our list. */
1627     for (lpWaveHdr = lpFirstDoneWaveHdr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext)
1628     {
1629         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1630         lpWaveHdr->dwFlags |= WHDR_DONE;
1631
1632         widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
1633     }
1634 }
1635
1636
1637 /**************************************************************************
1638  *                      widGetDevCaps                           [internal]
1639  */
1640 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
1641 {
1642     TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
1643
1644     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1645
1646     if (wDevID >= MAX_WAVEINDRV)
1647     {
1648         TRACE("MAX_WAVEINDRV reached !\n");
1649         return MMSYSERR_BADDEVICEID;
1650     }
1651
1652     memcpy(lpCaps, &WInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1653     return MMSYSERR_NOERROR;
1654 }
1655
1656
1657 /**************************************************************************
1658  *                    widHelper_DestroyAudioBufferList           [internal]
1659  * Convenience function to dispose of our audio buffers
1660  */
1661 static void widHelper_DestroyAudioBufferList(AudioBufferList* list)
1662 {
1663     if (list)
1664     {
1665         UInt32 i;
1666         for (i = 0; i < list->mNumberBuffers; i++)
1667         {
1668             if (list->mBuffers[i].mData)
1669                 HeapFree(GetProcessHeap(), 0, list->mBuffers[i].mData);
1670         }
1671         HeapFree(GetProcessHeap(), 0, list);
1672     }
1673 }
1674
1675
1676 /**************************************************************************
1677  *                    widHelper_AllocateAudioBufferList          [internal]
1678  * Convenience function to allocate our audio buffers
1679  */
1680 static AudioBufferList* widHelper_AllocateAudioBufferList(UInt32 numChannels, UInt32 size)
1681 {
1682     AudioBufferList*            list;
1683     UInt32                      i;
1684
1685     list = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer));
1686     if (list == NULL)
1687         return NULL;
1688
1689     list->mNumberBuffers = numChannels;
1690     for (i = 0; i < numChannels; ++i)
1691     {
1692         list->mBuffers[i].mNumberChannels = 1;
1693         list->mBuffers[i].mDataByteSize = size;
1694         list->mBuffers[i].mData = HeapAlloc(GetProcessHeap(), 0, size);
1695         if (list->mBuffers[i].mData == NULL)
1696         {
1697             widHelper_DestroyAudioBufferList(list);
1698             return NULL;
1699         }
1700     }
1701     return list;
1702 }
1703
1704
1705 /**************************************************************************
1706  *                              widOpen                         [internal]
1707  */
1708 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1709 {
1710     WINE_WAVEIN*    wwi;
1711     UInt32          frameCount;
1712     UInt32          bytesPerFrame;
1713
1714     TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
1715     if (lpDesc == NULL)
1716     {
1717         WARN("Invalid Parameter !\n");
1718         return MMSYSERR_INVALPARAM;
1719     }
1720     if (wDevID >= MAX_WAVEINDRV)
1721     {
1722         TRACE ("MAX_WAVEINDRV reached !\n");
1723         return MMSYSERR_BADDEVICEID;
1724     }
1725
1726     TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
1727           lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1728           lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
1729
1730     if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1731         lpDesc->lpFormat->nChannels == 0 ||
1732         lpDesc->lpFormat->nSamplesPerSec == 0
1733         )
1734     {
1735         WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
1736              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1737              lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
1738         return WAVERR_BADFORMAT;
1739     }
1740
1741     if (dwFlags & WAVE_FORMAT_QUERY)
1742     {
1743         TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1744               lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1745               lpDesc->lpFormat->nSamplesPerSec);
1746         return MMSYSERR_NOERROR;
1747     }
1748
1749     wwi = &WInDev[wDevID];
1750     if (!OSSpinLockTry(&wwi->lock))
1751         return MMSYSERR_ALLOCATED;
1752
1753     if (wwi->state != WINE_WS_CLOSED)
1754     {
1755         OSSpinLockUnlock(&wwi->lock);
1756         return MMSYSERR_ALLOCATED;
1757     }
1758
1759     wwi->state = WINE_WS_STOPPED;
1760     wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1761
1762     memcpy(&wwi->waveDesc, lpDesc,              sizeof(WAVEOPENDESC));
1763     memcpy(&wwi->format,   lpDesc->lpFormat,    sizeof(PCMWAVEFORMAT));
1764
1765     if (wwi->format.wBitsPerSample == 0)
1766     {
1767         WARN("Resetting zeroed wBitsPerSample\n");
1768         wwi->format.wBitsPerSample = 8 *
1769             (wwi->format.wf.nAvgBytesPerSec /
1770             wwi->format.wf.nSamplesPerSec) /
1771             wwi->format.wf.nChannels;
1772     }
1773
1774     wwi->dwTotalRecorded = 0;
1775
1776     wwi->trace_on = TRACE_ON(wave);
1777     wwi->warn_on  = WARN_ON(wave);
1778     wwi->err_on   = ERR_ON(wave);
1779
1780     if (!AudioUnit_CreateInputUnit(wwi, &wwi->audioUnit,
1781         wwi->format.wf.nChannels, wwi->format.wf.nSamplesPerSec,
1782         wwi->format.wBitsPerSample, &frameCount))
1783     {
1784         ERR("AudioUnit_CreateInputUnit failed\n");
1785         OSSpinLockUnlock(&wwi->lock);
1786         return MMSYSERR_ERROR;
1787     }
1788
1789     /* Allocate our audio buffers */
1790     /* For interleaved audio, we allocate one buffer for all channels. */
1791     bytesPerFrame = wwi->format.wBitsPerSample * wwi->format.wf.nChannels / 8;
1792     wwi->bufferList = widHelper_AllocateAudioBufferList(1, wwi->format.wf.nChannels * frameCount * bytesPerFrame);
1793     if (wwi->bufferList == NULL)
1794     {
1795         ERR("Failed to allocate buffer list\n");
1796         AudioUnitUninitialize(wwi->audioUnit);
1797         AudioUnit_CloseAudioUnit(wwi->audioUnit);
1798         OSSpinLockUnlock(&wwi->lock);
1799         return MMSYSERR_NOMEM;
1800     }
1801
1802     OSSpinLockUnlock(&wwi->lock);
1803
1804     return widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
1805 }
1806
1807
1808 /**************************************************************************
1809  *                              widClose                        [internal]
1810  */
1811 static DWORD widClose(WORD wDevID)
1812 {
1813     DWORD           ret = MMSYSERR_NOERROR;
1814     WINE_WAVEIN*    wwi;
1815
1816     TRACE("(%u);\n", wDevID);
1817
1818     if (wDevID >= MAX_WAVEINDRV)
1819     {
1820         WARN("bad device ID !\n");
1821         return MMSYSERR_BADDEVICEID;
1822     }
1823
1824     wwi = &WInDev[wDevID];
1825     OSSpinLockLock(&wwi->lock);
1826     if (wwi->state == WINE_WS_CLOSED)
1827     {
1828         WARN("Device already closed.\n");
1829         ret = MMSYSERR_INVALHANDLE;
1830     }
1831     else if (wwi->lpQueuePtr)
1832     {
1833         WARN("Buffers in queue.\n");
1834         ret = WAVERR_STILLPLAYING;
1835     }
1836     else
1837     {
1838         wwi->state = WINE_WS_CLOSED;
1839     }
1840
1841     OSSpinLockUnlock(&wwi->lock);
1842
1843     if (ret == MMSYSERR_NOERROR)
1844     {
1845         OSStatus err = AudioUnitUninitialize(wwi->audioUnit);
1846         if (err)
1847         {
1848             ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24),
1849                                                            (char) (err >> 16),
1850                                                            (char) (err >> 8),
1851                                                            (char) err);
1852         }
1853
1854         if (!AudioUnit_CloseAudioUnit(wwi->audioUnit))
1855         {
1856             ERR("Can't close AudioUnit\n");
1857         }
1858
1859         /* Dellocate our audio buffers */
1860         widHelper_DestroyAudioBufferList(wwi->bufferList);
1861         wwi->bufferList = NULL;
1862
1863         ret = widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
1864     }
1865
1866     return ret;
1867 }
1868
1869
1870 /**************************************************************************
1871  *                              widAddBuffer            [internal]
1872  */
1873 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1874 {
1875     DWORD           ret = MMSYSERR_NOERROR;
1876     WINE_WAVEIN*    wwi;
1877
1878     TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
1879
1880     if (wDevID >= MAX_WAVEINDRV)
1881     {
1882         WARN("invalid device ID\n");
1883         return MMSYSERR_INVALHANDLE;
1884     }
1885     if (!(lpWaveHdr->dwFlags & WHDR_PREPARED))
1886     {
1887         TRACE("never been prepared !\n");
1888         return WAVERR_UNPREPARED;
1889     }
1890     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1891     {
1892         TRACE("header already in use !\n");
1893         return WAVERR_STILLPLAYING;
1894     }
1895
1896     wwi = &WInDev[wDevID];
1897     OSSpinLockLock(&wwi->lock);
1898
1899     if (wwi->state == WINE_WS_CLOSED)
1900     {
1901         WARN("Trying to add buffer to closed device.\n");
1902         ret = MMSYSERR_INVALHANDLE;
1903     }
1904     else
1905     {
1906         LPWAVEHDR* wh;
1907
1908         lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1909         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1910         lpWaveHdr->dwBytesRecorded = 0;
1911         lpWaveHdr->lpNext = NULL;
1912
1913         /* insert buffer at end of queue */
1914         for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
1915             /* Do nothing */;
1916         *wh = lpWaveHdr;
1917     }
1918
1919     OSSpinLockUnlock(&wwi->lock);
1920
1921     return ret;
1922 }
1923
1924
1925 /**************************************************************************
1926  *                      widStart                                [internal]
1927  */
1928 static DWORD widStart(WORD wDevID)
1929 {
1930     DWORD           ret = MMSYSERR_NOERROR;
1931     WINE_WAVEIN*    wwi;
1932
1933     TRACE("(%u);\n", wDevID);
1934     if (wDevID >= MAX_WAVEINDRV)
1935     {
1936         WARN("invalid device ID\n");
1937         return MMSYSERR_INVALHANDLE;
1938     }
1939
1940     /* The order of the following operations is important since we can't hold
1941      * the mutex while we make an Audio Unit call.  Set the PLAYING state
1942      * before starting the Audio Unit.  In widStop, the order is reversed.
1943      * This guarantees that we can't get into a situation where the state is
1944      * PLAYING but the Audio Unit isn't running.  Although we can be in STOPPED
1945      * state with the Audio Unit still running, that's harmless because the
1946      * input callback will just throw away the sound data.
1947      */
1948     wwi = &WInDev[wDevID];
1949     OSSpinLockLock(&wwi->lock);
1950
1951     if (wwi->state == WINE_WS_CLOSED)
1952     {
1953         WARN("Trying to start closed device.\n");
1954         ret = MMSYSERR_INVALHANDLE;
1955     }
1956     else
1957         wwi->state = WINE_WS_PLAYING;
1958
1959     OSSpinLockUnlock(&wwi->lock);
1960
1961     if (ret == MMSYSERR_NOERROR)
1962     {
1963         /* Start pulling for audio data */
1964         OSStatus err = AudioOutputUnitStart(wwi->audioUnit);
1965         if (err != noErr)
1966             ERR("Failed to start AU: %08lx\n", err);
1967
1968         TRACE("Recording started...\n");
1969     }
1970
1971     return ret;
1972 }
1973
1974
1975 /**************************************************************************
1976  *                      widStop                                 [internal]
1977  */
1978 static DWORD widStop(WORD wDevID)
1979 {
1980     DWORD           ret = MMSYSERR_NOERROR;
1981     WINE_WAVEIN*    wwi;
1982     WAVEHDR*        lpWaveHdr = NULL;
1983     OSStatus        err;
1984
1985     TRACE("(%u);\n", wDevID);
1986     if (wDevID >= MAX_WAVEINDRV)
1987     {
1988         WARN("invalid device ID\n");
1989         return MMSYSERR_INVALHANDLE;
1990     }
1991
1992     wwi = &WInDev[wDevID];
1993
1994     /* The order of the following operations is important since we can't hold
1995      * the mutex while we make an Audio Unit call.  Stop the Audio Unit before
1996      * setting the STOPPED state.  In widStart, the order is reversed.  This
1997      * guarantees that we can't get into a situation where the state is
1998      * PLAYING but the Audio Unit isn't running.  Although we can be in STOPPED
1999      * state with the Audio Unit still running, that's harmless because the
2000      * input callback will just throw away the sound data.
2001      */
2002     err = AudioOutputUnitStop(wwi->audioUnit);
2003     if (err != noErr)
2004         WARN("Failed to stop AU: %08lx\n", err);
2005
2006     TRACE("Recording stopped.\n");
2007
2008     OSSpinLockLock(&wwi->lock);
2009
2010     if (wwi->state == WINE_WS_CLOSED)
2011     {
2012         WARN("Trying to stop closed device.\n");
2013         ret = MMSYSERR_INVALHANDLE;
2014     }
2015     else if (wwi->state != WINE_WS_STOPPED)
2016     {
2017         wwi->state = WINE_WS_STOPPED;
2018         /* If there's a buffer in progress, it's done.  Remove it from the
2019          * queue so that we can return it to the app, below. */
2020         if (wwi->lpQueuePtr)
2021         {
2022             lpWaveHdr = wwi->lpQueuePtr;
2023             wwi->lpQueuePtr = lpWaveHdr->lpNext;
2024         }
2025     }
2026
2027     OSSpinLockUnlock(&wwi->lock);
2028
2029     if (lpWaveHdr)
2030     {
2031         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2032         lpWaveHdr->dwFlags |= WHDR_DONE;
2033         widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
2034     }
2035
2036     return ret;
2037 }
2038
2039
2040 /**************************************************************************
2041  *                      widReset                                [internal]
2042  */
2043 static DWORD widReset(WORD wDevID)
2044 {
2045     DWORD           ret = MMSYSERR_NOERROR;
2046     WINE_WAVEIN*    wwi;
2047     WAVEHDR*        lpWaveHdr = NULL;
2048
2049     TRACE("(%u);\n", wDevID);
2050     if (wDevID >= MAX_WAVEINDRV)
2051     {
2052         WARN("invalid device ID\n");
2053         return MMSYSERR_INVALHANDLE;
2054     }
2055
2056     wwi = &WInDev[wDevID];
2057     OSSpinLockLock(&wwi->lock);
2058
2059     if (wwi->state == WINE_WS_CLOSED)
2060     {
2061         WARN("Trying to reset a closed device.\n");
2062         ret = MMSYSERR_INVALHANDLE;
2063     }
2064     else
2065     {
2066         lpWaveHdr               = wwi->lpQueuePtr;
2067         wwi->lpQueuePtr         = NULL;
2068         wwi->state              = WINE_WS_STOPPED;
2069         wwi->dwTotalRecorded    = 0;
2070     }
2071
2072     OSSpinLockUnlock(&wwi->lock);
2073
2074     if (ret == MMSYSERR_NOERROR)
2075     {
2076         OSStatus err = AudioOutputUnitStop(wwi->audioUnit);
2077         if (err != noErr)
2078             WARN("Failed to stop AU: %08lx\n", err);
2079
2080         TRACE("Recording stopped.\n");
2081     }
2082
2083     while (lpWaveHdr)
2084     {
2085         WAVEHDR* lpNext = lpWaveHdr->lpNext;
2086
2087         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2088         lpWaveHdr->dwFlags |= WHDR_DONE;
2089         widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
2090
2091         lpWaveHdr = lpNext;
2092     }
2093
2094     return ret;
2095 }
2096
2097
2098 /**************************************************************************
2099  *                              widGetNumDevs                   [internal]
2100  */
2101 static DWORD widGetNumDevs(void)
2102 {
2103     return MAX_WAVEINDRV;
2104 }
2105
2106
2107 /**************************************************************************
2108  *                              widDevInterfaceSize             [internal]
2109  */
2110 static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
2111 {
2112     TRACE("(%u, %p)\n", wDevID, dwParam1);
2113
2114     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2115                                     NULL, 0 ) * sizeof(WCHAR);
2116     return MMSYSERR_NOERROR;
2117 }
2118
2119
2120 /**************************************************************************
2121  *                              widDevInterface                 [internal]
2122  */
2123 static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
2124 {
2125     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2126                                         NULL, 0 ) * sizeof(WCHAR))
2127     {
2128         MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2129                             dwParam1, dwParam2 / sizeof(WCHAR));
2130         return MMSYSERR_NOERROR;
2131     }
2132     return MMSYSERR_INVALPARAM;
2133 }
2134
2135
2136 /**************************************************************************
2137  *                              widMessage (WINECOREAUDIO.6)
2138  */
2139 DWORD WINAPI CoreAudio_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2140                             DWORD dwParam1, DWORD dwParam2)
2141 {
2142     TRACE("(%u, %04X, %08X, %08X, %08X);\n",
2143             wDevID, wMsg, dwUser, dwParam1, dwParam2);
2144
2145     switch (wMsg)
2146     {
2147         case DRVM_INIT:
2148         case DRVM_EXIT:
2149         case DRVM_ENABLE:
2150         case DRVM_DISABLE:
2151             /* FIXME: Pretend this is supported */
2152             return 0;
2153         case WIDM_OPEN:             return widOpen          (wDevID, (LPWAVEOPENDESC)dwParam1,  dwParam2);
2154         case WIDM_CLOSE:            return widClose         (wDevID);
2155         case WIDM_ADDBUFFER:        return widAddBuffer     (wDevID, (LPWAVEHDR)dwParam1,       dwParam2);
2156         case WIDM_PREPARE:          return MMSYSERR_NOTSUPPORTED;
2157         case WIDM_UNPREPARE:        return MMSYSERR_NOTSUPPORTED;
2158         case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (LPWAVEINCAPSW)dwParam1,   dwParam2);
2159         case WIDM_GETNUMDEVS:       return widGetNumDevs    ();
2160         case WIDM_RESET:            return widReset         (wDevID);
2161         case WIDM_START:            return widStart         (wDevID);
2162         case WIDM_STOP:             return widStop          (wDevID);
2163         case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
2164         case DRV_QUERYDEVICEINTERFACE:     return widDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
2165         default:
2166             FIXME("unknown message %d!\n", wMsg);
2167     }
2168
2169     return MMSYSERR_NOTSUPPORTED;
2170 }
2171
2172
2173 OSStatus CoreAudio_wiAudioUnitIOProc(void *inRefCon,
2174                                      AudioUnitRenderActionFlags *ioActionFlags,
2175                                      const AudioTimeStamp *inTimeStamp,
2176                                      UInt32 inBusNumber,
2177                                      UInt32 inNumberFrames,
2178                                      AudioBufferList *ioData)
2179 {
2180     WINE_WAVEIN*    wwi = (WINE_WAVEIN*)inRefCon;
2181     OSStatus        err = noErr;
2182     BOOL            needNotify = FALSE;
2183     WAVEHDR*        lpStorePtr;
2184     unsigned int    dataToStore;
2185     unsigned int    dataStored = 0;
2186
2187
2188     if (wwi->trace_on)
2189         fprintf(stderr, "trace:wave:CoreAudio_wiAudioUnitIOProc (ioActionFlags = %08lx, inTimeStamp = { %f, %llu, %f, %llu, %08lx }, inBusNumber = %lu, inNumberFrames = %lu)\n",
2190             *ioActionFlags, inTimeStamp->mSampleTime, inTimeStamp->mHostTime, inTimeStamp->mRateScalar, inTimeStamp->mWordClockTime, inTimeStamp->mFlags, inBusNumber, inNumberFrames);
2191
2192     /* Render into audio buffer */
2193     /* FIXME: implement sample rate conversion on input.  This will require
2194      * a different render strategy.  We'll need to buffer the sound data
2195      * received here and pass it off to an AUConverter in another thread. */
2196     err = AudioUnitRender(wwi->audioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, wwi->bufferList);
2197     if (err)
2198     {
2199         if (wwi->err_on)
2200             fprintf(stderr, "err:wave:CoreAudio_wiAudioUnitIOProc AudioUnitRender failed with error %li\n", err);
2201         return err;
2202     }
2203
2204     /* Copy from audio buffer to the wavehdrs */
2205     dataToStore = wwi->bufferList->mBuffers[0].mDataByteSize;
2206
2207     OSSpinLockLock(&wwi->lock);
2208
2209     lpStorePtr = wwi->lpQueuePtr;
2210
2211     while (dataToStore > 0 && wwi->state == WINE_WS_PLAYING && lpStorePtr)
2212     {
2213         unsigned int room = lpStorePtr->dwBufferLength - lpStorePtr->dwBytesRecorded;
2214         unsigned int toCopy;
2215
2216         if (wwi->trace_on)
2217             fprintf(stderr, "trace:wave:CoreAudio_wiAudioUnitIOProc Looking to store %u bytes to wavehdr %p, which has room for %u\n",
2218                 dataToStore, lpStorePtr, room);
2219
2220         if (room >= dataToStore)
2221             toCopy = dataToStore;
2222         else
2223             toCopy = room;
2224
2225         if (toCopy > 0)
2226         {
2227             memcpy(lpStorePtr->lpData + lpStorePtr->dwBytesRecorded,
2228                 (char*)wwi->bufferList->mBuffers[0].mData + dataStored, toCopy);
2229             lpStorePtr->dwBytesRecorded += toCopy;
2230             wwi->dwTotalRecorded += toCopy;
2231             dataStored += toCopy;
2232             dataToStore -= toCopy;
2233             room -= toCopy;
2234         }
2235
2236         if (room == 0)
2237         {
2238             lpStorePtr = lpStorePtr->lpNext;
2239             needNotify = TRUE;
2240         }
2241     }
2242
2243     OSSpinLockUnlock(&wwi->lock);
2244
2245     if (needNotify) wodSendNotifyInputCompletionsMessage(wwi);
2246     return err;
2247 }
2248
2249 #else
2250
2251 /**************************************************************************
2252  *                              widMessage (WINECOREAUDIO.6)
2253  */
2254 DWORD WINAPI CoreAudio_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2255                             DWORD dwParam1, DWORD dwParam2)
2256 {
2257     FIXME("(%u, %04X, %08X, %08X, %08X): CoreAudio support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2258     return MMSYSERR_NOTENABLED;
2259 }
2260
2261 /**************************************************************************
2262 *                               wodMessage (WINECOREAUDIO.7)
2263 */
2264 DWORD WINAPI CoreAudio_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
2265                                   DWORD dwParam1, DWORD dwParam2)
2266 {
2267     FIXME("(%u, %04X, %08X, %08X, %08X): CoreAudio support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2268     return MMSYSERR_NOTENABLED;
2269 }
2270
2271 #endif