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