winecoreaudio: Create port for sending messages to the callback thread only once.
[wine] / dlls / winmm / winecoreaudio / 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 #ifdef HAVE_PTHREAD_H
36 # include <pthread.h>
37 #endif
38
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "wingdi.h"
43 #include "winerror.h"
44 #include "mmddk.h"
45 #include "dsound.h"
46 #include "dsdriver.h"
47 #include "coreaudio.h"
48 #include "wine/unicode.h"
49 #include "wine/library.h"
50 #include "wine/debug.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(wave);
53
54
55 #if defined(HAVE_COREAUDIO_COREAUDIO_H) && defined(HAVE_AUDIOUNIT_AUDIOUNIT_H)
56 #include <CoreAudio/CoreAudio.h>
57 #include <CoreFoundation/CoreFoundation.h>
58
59 /*
60     Due to AudioUnit headers conflict define some needed types.
61 */
62
63 typedef void *AudioUnit;
64
65 /* From AudioUnit/AUComponents.h */
66 typedef UInt32 AudioUnitRenderActionFlags;
67
68 /* only allow 10 output devices through this driver, this ought to be adequate */
69 #define MAX_WAVEOUTDRV  (1)
70 #define MAX_WAVEINDRV   (1)
71
72 /* state diagram for waveOut writing:
73 *
74 * +---------+-------------+---------------+---------------------------------+
75 * |  state  |  function   |     event     |            new state             |
76 * +---------+-------------+---------------+---------------------------------+
77 * |          | open()      |               | STOPPED                         |
78 * | PAUSED  | write()      |               | PAUSED                          |
79 * | STOPPED | write()      | <thrd create> | PLAYING                         |
80 * | PLAYING | write()      | HEADER        | PLAYING                         |
81 * | (other) | write()      | <error>       |                                 |
82 * | (any)   | pause()      | PAUSING       | PAUSED                          |
83 * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
84 * | (any)   | reset()      | RESETTING     | STOPPED                         |
85 * | (any)   | close()      | CLOSING       | CLOSED                          |
86 * +---------+-------------+---------------+---------------------------------+
87 */
88
89 /* states of the playing device */
90 #define WINE_WS_PLAYING   0
91 #define WINE_WS_PAUSED    1
92 #define WINE_WS_STOPPED   2
93 #define WINE_WS_CLOSED    3
94
95 typedef struct tagCoreAudio_Device {
96     char                        dev_name[32];
97     char                        mixer_name[32];
98     unsigned                    open_count;
99     char*                       interface_name;
100     
101     WAVEOUTCAPSW                out_caps;
102     WAVEINCAPSW                 in_caps;
103     DWORD                       in_caps_support;
104     int                         sample_rate;
105     int                         stereo;
106     int                         format;
107     unsigned                    audio_fragment;
108     BOOL                        full_duplex;
109     BOOL                        bTriggerSupport;
110     BOOL                        bOutputEnabled;
111     BOOL                        bInputEnabled;
112     DSDRIVERDESC                ds_desc;
113     DSDRIVERCAPS                ds_caps;
114     DSCDRIVERCAPS               dsc_caps;
115     GUID                        ds_guid;
116     GUID                        dsc_guid;
117     
118     AudioDeviceID outputDeviceID;
119     AudioDeviceID inputDeviceID;
120     AudioStreamBasicDescription streamDescription;
121 } CoreAudio_Device;
122
123 /* for now use the default device */
124 static CoreAudio_Device CoreAudio_DefaultDevice;
125
126 typedef struct {
127     volatile int                state;      /* one of the WINE_WS_ manifest constants */
128     CoreAudio_Device            *cadev;
129     WAVEOPENDESC                waveDesc;
130     WORD                        wFlags;
131     PCMWAVEFORMAT               format;
132     DWORD                       woID;
133     AudioUnit                   audioUnit;
134     AudioStreamBasicDescription streamDescription;
135     
136     WAVEOUTCAPSW                caps;
137     char                        interface_name[32];
138     LPWAVEHDR                   lpQueuePtr;             /* start of queued WAVEHDRs (waiting to be notified) */
139     LPWAVEHDR                   lpPlayPtr;              /* start of not yet fully played buffers */
140     DWORD                       dwPartialOffset;        /* Offset of not yet written bytes in lpPlayPtr */
141     
142     LPWAVEHDR                   lpLoopPtr;              /* pointer of first buffer in loop, if any */
143     DWORD                       dwLoops;                /* private copy of loop counter */
144     
145     DWORD                       dwPlayedTotal;          /* number of bytes actually played since opening */
146     DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
147         
148     DWORD                       tickCountMS; /* time in MS of last AudioUnit callback */
149
150     pthread_mutex_t             lock;         /* synchronization stuff */
151
152     BOOL trace_on;
153     BOOL warn_on;
154     BOOL err_on;
155 } WINE_WAVEOUT;
156
157 typedef struct {
158     volatile int    state;
159     CoreAudio_Device *cadev;
160     WAVEOPENDESC    waveDesc;
161     WORD            wFlags;
162     PCMWAVEFORMAT   format;
163     LPWAVEHDR       lpQueuePtr;
164     DWORD           dwTotalRecorded;
165     WAVEINCAPSW     caps;
166     
167     AudioUnit                   audioUnit;
168     AudioStreamBasicDescription streamDescription;
169         
170     /*  BOOL            bTriggerSupport;
171     WORD              wDevID;
172     char              interface_name[32];*/
173         
174     /* synchronization stuff */
175     pthread_mutex_t lock;
176 } WINE_WAVEIN;
177
178 static WINE_WAVEOUT WOutDev   [MAX_WAVEOUTDRV];
179
180 static CFMessagePortRef Port_SendToMessageThread;
181
182 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
183 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
184
185 extern int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
186 extern int AudioUnit_CloseAudioUnit(AudioUnit au);
187 extern int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription *streamFormat);
188
189 extern OSStatus AudioOutputUnitStart(AudioUnit au);
190 extern OSStatus AudioOutputUnitStop(AudioUnit au);
191 extern OSStatus AudioUnitUninitialize(AudioUnit au);
192
193 extern int AudioUnit_SetVolume(AudioUnit au, float left, float right);
194 extern int AudioUnit_GetVolume(AudioUnit au, float *left, float *right);
195
196 OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
197                                      AudioUnitRenderActionFlags *ioActionFlags, 
198                                      const AudioTimeStamp *inTimeStamp, 
199                                      UInt32 inBusNumber, 
200                                      UInt32 inNumberFrames, 
201                                      AudioBufferList *ioData);
202
203 /* These strings used only for tracing */
204
205 static const char * getMessage(UINT msg)
206 {
207     static char unknown[32];
208 #define MSG_TO_STR(x) case x: return #x
209     switch(msg) {
210         MSG_TO_STR(DRVM_INIT);
211         MSG_TO_STR(DRVM_EXIT);
212         MSG_TO_STR(DRVM_ENABLE);
213         MSG_TO_STR(DRVM_DISABLE);
214         MSG_TO_STR(WIDM_OPEN);
215         MSG_TO_STR(WIDM_CLOSE);
216         MSG_TO_STR(WIDM_ADDBUFFER);
217         MSG_TO_STR(WIDM_PREPARE);
218         MSG_TO_STR(WIDM_UNPREPARE);
219         MSG_TO_STR(WIDM_GETDEVCAPS);
220         MSG_TO_STR(WIDM_GETNUMDEVS);
221         MSG_TO_STR(WIDM_GETPOS);
222         MSG_TO_STR(WIDM_RESET);
223         MSG_TO_STR(WIDM_START);
224         MSG_TO_STR(WIDM_STOP);
225         MSG_TO_STR(WODM_OPEN);
226         MSG_TO_STR(WODM_CLOSE);
227         MSG_TO_STR(WODM_WRITE);
228         MSG_TO_STR(WODM_PAUSE);
229         MSG_TO_STR(WODM_GETPOS);
230         MSG_TO_STR(WODM_BREAKLOOP);
231         MSG_TO_STR(WODM_PREPARE);
232         MSG_TO_STR(WODM_UNPREPARE);
233         MSG_TO_STR(WODM_GETDEVCAPS);
234         MSG_TO_STR(WODM_GETNUMDEVS);
235         MSG_TO_STR(WODM_GETPITCH);
236         MSG_TO_STR(WODM_SETPITCH);
237         MSG_TO_STR(WODM_GETPLAYBACKRATE);
238         MSG_TO_STR(WODM_SETPLAYBACKRATE);
239         MSG_TO_STR(WODM_GETVOLUME);
240         MSG_TO_STR(WODM_SETVOLUME);
241         MSG_TO_STR(WODM_RESTART);
242         MSG_TO_STR(WODM_RESET);
243         MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
244         MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
245         MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
246         MSG_TO_STR(DRV_QUERYDSOUNDDESC);
247     }
248 #undef MSG_TO_STR
249     sprintf(unknown, "UNKNOWN(0x%04x)", msg);
250     return unknown;
251 }
252
253 #define kStopLoopMessage 0
254 #define kWaveOutCallbackMessage 1
255 #define kWaveInCallbackMessage 2
256
257 /* Mach Message Handling */
258 static CFDataRef wodMessageHandler(CFMessagePortRef port_ReceiveInMessageThread, SInt32 msgid, CFDataRef data, void *info)
259 {
260     UInt32 *buffer = NULL;
261     WINE_WAVEOUT* wwo = NULL;
262     
263     switch (msgid)
264     {
265         case kWaveOutCallbackMessage:
266             buffer = (UInt32 *) CFDataGetBytePtr(data);
267             wwo = &WOutDev[buffer[0]];
268             
269             pthread_mutex_lock(&wwo->lock);
270             DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
271                            (HDRVR)wwo->waveDesc.hWave, (WORD)buffer[1], wwo->waveDesc.dwInstance,
272                            (DWORD)buffer[2], (DWORD)buffer[3]);
273             pthread_mutex_unlock(&wwo->lock);
274             break;
275         case kWaveInCallbackMessage:
276         default:
277             CFRunLoopStop(CFRunLoopGetCurrent());
278             break;
279     }
280     
281     return NULL;
282 }
283
284 static DWORD WINAPI messageThread(LPVOID p)
285 {
286     CFMessagePortRef port_ReceiveInMessageThread = (CFMessagePortRef) p;
287     CFRunLoopSourceRef source;
288     
289     source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, port_ReceiveInMessageThread, (CFIndex)0);
290     CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
291         
292     CFRunLoopRun();
293
294     CFRunLoopSourceInvalidate(source);
295     CFRelease(source);
296     CFRelease(port_ReceiveInMessageThread);
297
298     return 0;
299 }
300
301 static DWORD wodSendDriverCallbackMessage(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
302 {
303     CFDataRef data;
304     UInt32 buffer[4];
305     SInt32 ret;
306     
307     buffer[0] = (UInt32) wwo->woID;
308     buffer[1] = (UInt32) wMsg;
309     buffer[2] = (UInt32) dwParam1;
310     buffer[3] = (UInt32) dwParam2;
311
312     data = CFDataCreate(kCFAllocatorDefault, (UInt8 *)buffer, sizeof(buffer));
313     if (!data)
314         return 0;
315     
316     ret = CFMessagePortSendRequest(Port_SendToMessageThread, kWaveOutCallbackMessage, data, 0.0, 0.0, NULL, NULL);
317     CFRelease(data);
318     
319     return (ret == kCFMessagePortSuccess)?1:0;
320 }
321
322 static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
323                              PCMWAVEFORMAT* format)
324 {
325     TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
326           lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
327           format->wf.nChannels, format->wf.nAvgBytesPerSec);
328     TRACE("Position in bytes=%u\n", position);
329
330     switch (lpTime->wType) {
331     case TIME_SAMPLES:
332         lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
333         TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
334         break;
335     case TIME_MS:
336         lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
337         TRACE("TIME_MS=%u\n", lpTime->u.ms);
338         break;
339     case TIME_SMPTE:
340         lpTime->u.smpte.fps = 30;
341         position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
342         position += (format->wf.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
343         lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
344         position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
345         lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
346         lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
347         lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
348         lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
349         lpTime->u.smpte.fps = 30;
350         lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
351         TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
352               lpTime->u.smpte.hour, lpTime->u.smpte.min,
353               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
354         break;
355     default:
356         WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
357         lpTime->wType = TIME_BYTES;
358         /* fall through */
359     case TIME_BYTES:
360         lpTime->u.cb = position;
361         TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
362         break;
363     }
364     return MMSYSERR_NOERROR;
365 }
366
367 /**************************************************************************
368 *                       CoreAudio_GetDevCaps            [internal]
369 */
370 BOOL CoreAudio_GetDevCaps (void)
371 {
372     OSStatus status;
373     UInt32 propertySize;
374     AudioDeviceID devId = CoreAudio_DefaultDevice.outputDeviceID;
375     
376     char name[MAXPNAMELEN];
377     
378     propertySize = MAXPNAMELEN;
379     status = AudioDeviceGetProperty(devId, 0 , FALSE, kAudioDevicePropertyDeviceName, &propertySize, name);
380     if (status) {
381         ERR("AudioHardwareGetProperty for kAudioDevicePropertyDeviceName return %c%c%c%c\n", (char) (status >> 24),
382                                                                                              (char) (status >> 16),
383                                                                                              (char) (status >> 8),
384                                                                                              (char) status);
385         return FALSE;
386     }
387     
388     memcpy(CoreAudio_DefaultDevice.ds_desc.szDesc, name, sizeof(name));
389     strcpy(CoreAudio_DefaultDevice.ds_desc.szDrvname, "winecoreaudio.drv");
390     MultiByteToWideChar(CP_ACP, 0, name, sizeof(name), 
391                         CoreAudio_DefaultDevice.out_caps.szPname, 
392                         sizeof(CoreAudio_DefaultDevice.out_caps.szPname) / sizeof(WCHAR));
393     memcpy(CoreAudio_DefaultDevice.dev_name, name, 32);
394     
395     propertySize = sizeof(CoreAudio_DefaultDevice.streamDescription);
396     status = AudioDeviceGetProperty(devId, 0, FALSE , kAudioDevicePropertyStreamFormat, &propertySize, &CoreAudio_DefaultDevice.streamDescription);
397     if (status != noErr) {
398         ERR("AudioHardwareGetProperty for kAudioDevicePropertyStreamFormat return %c%c%c%c\n", (char) (status >> 24),
399                                                                                                 (char) (status >> 16),
400                                                                                                 (char) (status >> 8),
401                                                                                                 (char) status);
402         return FALSE;
403     }
404     
405     TRACE("Device Stream Description mSampleRate : %f\n mFormatID : %c%c%c%c\n"
406             "mFormatFlags : %lX\n mBytesPerPacket : %lu\n mFramesPerPacket : %lu\n"
407             "mBytesPerFrame : %lu\n mChannelsPerFrame : %lu\n mBitsPerChannel : %lu\n",
408                                CoreAudio_DefaultDevice.streamDescription.mSampleRate,
409                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 24),
410                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 16),
411                                (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 8),
412                                (char) CoreAudio_DefaultDevice.streamDescription.mFormatID,
413                                CoreAudio_DefaultDevice.streamDescription.mFormatFlags,
414                                CoreAudio_DefaultDevice.streamDescription.mBytesPerPacket,
415                                CoreAudio_DefaultDevice.streamDescription.mFramesPerPacket,
416                                CoreAudio_DefaultDevice.streamDescription.mBytesPerFrame,
417                                CoreAudio_DefaultDevice.streamDescription.mChannelsPerFrame,
418                                CoreAudio_DefaultDevice.streamDescription.mBitsPerChannel);
419     
420     CoreAudio_DefaultDevice.out_caps.wMid = 0xcafe;
421     CoreAudio_DefaultDevice.out_caps.wPid = 0x0001;
422     
423     CoreAudio_DefaultDevice.out_caps.vDriverVersion = 0x0001;
424     CoreAudio_DefaultDevice.out_caps.dwFormats = 0x00000000;
425     CoreAudio_DefaultDevice.out_caps.wReserved1 = 0;
426     CoreAudio_DefaultDevice.out_caps.dwSupport = WAVECAPS_VOLUME;
427     CoreAudio_DefaultDevice.out_caps.dwSupport |= WAVECAPS_LRVOLUME;
428     
429     CoreAudio_DefaultDevice.out_caps.wChannels = 2;
430     CoreAudio_DefaultDevice.out_caps.dwFormats|= WAVE_FORMAT_4S16;
431     
432     return TRUE;
433 }
434
435 /******************************************************************
436 *               CoreAudio_WaveInit
437 *
438 * Initialize CoreAudio_DefaultDevice
439 */
440 LONG CoreAudio_WaveInit(void)
441 {
442     OSStatus status;
443     UInt32 propertySize;
444     CHAR szPname[MAXPNAMELEN];
445     pthread_mutexattr_t mutexattr;
446     int i;
447     HANDLE hThread;
448     CFStringRef  messageThreadPortName;
449     CFMessagePortRef port_ReceiveInMessageThread;
450
451     TRACE("()\n");
452     
453     /* number of sound cards */
454     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
455     propertySize /= sizeof(AudioDeviceID);
456     TRACE("sound cards : %lu\n", propertySize);
457     
458     /* Get the output device */
459     propertySize = sizeof(CoreAudio_DefaultDevice.outputDeviceID);
460     status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &CoreAudio_DefaultDevice.outputDeviceID);
461     if (status) {
462         ERR("AudioHardwareGetProperty return %c%c%c%c for kAudioHardwarePropertyDefaultOutputDevice\n", (char) (status >> 24),
463                                                                                                 (char) (status >> 16),
464                                                                                                 (char) (status >> 8),
465                                                                                                 (char) status);
466         return 1;
467     }
468     if (CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown) {
469         ERR("AudioHardwareGetProperty: CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown\n");
470         return 1;
471     }
472     
473     if ( ! CoreAudio_GetDevCaps() )
474         return 1;
475     
476     CoreAudio_DefaultDevice.interface_name=HeapAlloc(GetProcessHeap(),0,strlen(CoreAudio_DefaultDevice.dev_name)+1);
477     sprintf(CoreAudio_DefaultDevice.interface_name, "%s", CoreAudio_DefaultDevice.dev_name);
478     
479     pthread_mutexattr_init(&mutexattr);
480     pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
481
482     for (i = 0; i < MAX_WAVEOUTDRV; ++i)
483     {
484         WOutDev[i].state = WINE_WS_CLOSED;
485         WOutDev[i].cadev = &CoreAudio_DefaultDevice; 
486         WOutDev[i].woID = i;
487         
488         memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
489         
490         WOutDev[i].caps.wMid = 0xcafe;  /* Manufac ID */
491         WOutDev[i].caps.wPid = 0x0001;  /* Product ID */
492         snprintf(szPname, sizeof(szPname), "CoreAudio WaveOut %d", i);
493         MultiByteToWideChar(CP_ACP, 0, szPname, -1, WOutDev[i].caps.szPname, sizeof(WOutDev[i].caps.szPname)/sizeof(WCHAR));
494         snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winecoreaudio: %d", i);
495         
496         WOutDev[i].caps.vDriverVersion = 0x0001;
497         WOutDev[i].caps.dwFormats = 0x00000000;
498         WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
499         
500         WOutDev[i].caps.wChannels = 2;
501       /*  WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME; */ /* FIXME */
502         
503         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
504         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; 
505         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
506         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
507         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
508         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; 
509         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
510         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
511         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
512         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
513         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
514         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
515
516         pthread_mutex_init(&WOutDev[i].lock, &mutexattr); /* initialize the mutex */
517     }
518
519     pthread_mutexattr_destroy(&mutexattr);
520     
521     /* create mach messages handler */
522     srandomdev();
523     messageThreadPortName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
524         CFSTR("WaveMessagePort.%d.%lu"), getpid(), (unsigned long)random());
525     if (!messageThreadPortName)
526     {
527         ERR("Can't create message thread port name\n");
528         return 1;
529     }
530
531     port_ReceiveInMessageThread = CFMessagePortCreateLocal(kCFAllocatorDefault, messageThreadPortName,
532                                         &wodMessageHandler, NULL, NULL);
533     if (!port_ReceiveInMessageThread)
534     {
535         ERR("Can't create message thread local port\n");
536         CFRelease(messageThreadPortName);
537         return 1;
538     }
539
540     Port_SendToMessageThread = CFMessagePortCreateRemote(kCFAllocatorDefault, messageThreadPortName);
541     CFRelease(messageThreadPortName);
542     if (!Port_SendToMessageThread)
543     {
544         ERR("Can't create port for sending to message thread\n");
545         CFRelease(port_ReceiveInMessageThread);
546         return 1;
547     }
548
549     hThread = CreateThread(NULL, 0, messageThread, (LPVOID)port_ReceiveInMessageThread, 0, NULL);
550     if ( !hThread )
551     {
552         ERR("Can't create message thread\n");
553         CFRelease(port_ReceiveInMessageThread);
554         CFRelease(Port_SendToMessageThread);
555         Port_SendToMessageThread = NULL;
556         return 1;
557     }
558
559     /* The message thread is responsible for releasing port_ReceiveInMessageThread. */
560
561     return 0;
562 }
563
564 void CoreAudio_WaveRelease(void)
565 {
566     /* Stop CFRunLoop in messageThread */
567     int i;
568
569     TRACE("()\n");
570
571     CFMessagePortSendRequest(Port_SendToMessageThread, kStopLoopMessage, NULL, 0.0, 0.0, NULL, NULL);
572     CFRelease(Port_SendToMessageThread);
573     Port_SendToMessageThread = NULL;
574
575     for (i = 0; i < MAX_WAVEOUTDRV; ++i)
576     {
577         pthread_mutex_destroy(&WOutDev[i].lock);
578     }
579 }
580
581 /*======================================================================*
582 *                  Low level WAVE OUT implementation                    *
583 *======================================================================*/
584
585 /**************************************************************************
586 *                       wodNotifyClient                 [internal]
587 *   Call from AudioUnit IO thread can't use Wine debug channels.
588 */
589 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
590 {
591     switch (wMsg) {
592         case WOM_OPEN:
593         case WOM_CLOSE:
594             if (wwo->wFlags != DCB_NULL &&
595                 !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
596                                 (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
597                                 dwParam1, dwParam2))
598             {
599                 return MMSYSERR_ERROR;
600             }
601             break;
602         case WOM_DONE:
603             if (wwo->wFlags != DCB_NULL &&
604                 ! wodSendDriverCallbackMessage(wwo, wMsg, dwParam1, dwParam2))
605             {
606                 return MMSYSERR_ERROR;
607             }
608             break;
609         default:
610             return MMSYSERR_INVALPARAM;
611     }
612     return MMSYSERR_NOERROR;
613 }
614
615
616 /**************************************************************************
617 *                       wodGetDevCaps               [internal]
618 */
619 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
620 {
621     TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
622     
623     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
624     
625     if (wDevID >= MAX_WAVEOUTDRV)
626     {
627         TRACE("MAX_WAVOUTDRV reached !\n");
628         return MMSYSERR_BADDEVICEID;
629     }
630     
631     TRACE("dwSupport=(0x%x), dwFormats=(0x%x)\n", WOutDev[wDevID].caps.dwSupport, WOutDev[wDevID].caps.dwFormats);
632     memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
633     return MMSYSERR_NOERROR;
634 }
635
636 /**************************************************************************
637 *                               wodOpen                         [internal]
638 */
639 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
640 {
641     WINE_WAVEOUT*       wwo;
642     DWORD retval;
643     DWORD               ret;
644     AudioStreamBasicDescription streamFormat;
645
646     TRACE("(%u, %p, %08x);\n", wDevID, lpDesc, dwFlags);
647     if (lpDesc == NULL)
648     {
649         WARN("Invalid Parameter !\n");
650         return MMSYSERR_INVALPARAM;
651     }
652     if (wDevID >= MAX_WAVEOUTDRV) {
653         TRACE("MAX_WAVOUTDRV reached !\n");
654         return MMSYSERR_BADDEVICEID;
655     }
656     
657     TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
658           lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
659           lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
660     
661     if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
662         lpDesc->lpFormat->nChannels == 0 ||
663         lpDesc->lpFormat->nSamplesPerSec == 0
664          )
665     {
666         WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d wBitsPerSample=%d !\n",
667              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
668              lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
669         return WAVERR_BADFORMAT;
670     }
671     
672     if (dwFlags & WAVE_FORMAT_QUERY)
673     {
674         TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
675               lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
676               lpDesc->lpFormat->nSamplesPerSec);
677         return MMSYSERR_NOERROR;
678     }
679     
680     wwo = &WOutDev[wDevID];
681     pthread_mutex_lock(&wwo->lock);
682
683     if (wwo->state != WINE_WS_CLOSED)
684     {
685         pthread_mutex_unlock(&wwo->lock);
686         return MMSYSERR_ALLOCATED;
687     }
688
689     if (!AudioUnit_CreateDefaultAudioUnit((void *) wwo, &wwo->audioUnit))
690     {
691         ERR("CoreAudio_CreateDefaultAudioUnit(%p) failed\n", wwo);
692         pthread_mutex_unlock(&wwo->lock);
693         return MMSYSERR_ERROR;
694     }
695
696     if ((dwFlags & WAVE_DIRECTSOUND) && 
697         !(wwo->caps.dwSupport & WAVECAPS_DIRECTSOUND))
698         /* not supported, ignore it */
699         dwFlags &= ~WAVE_DIRECTSOUND;
700
701     streamFormat.mFormatID = kAudioFormatLinearPCM;
702     streamFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked;
703     /* FIXME check for 32bits float -> kLinearPCMFormatFlagIsFloat */
704     if (lpDesc->lpFormat->wBitsPerSample != 8)
705         streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
706 # ifdef WORDS_BIGENDIAN
707     streamFormat.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; /* FIXME Wave format is little endian */
708 # endif
709
710     streamFormat.mSampleRate = lpDesc->lpFormat->nSamplesPerSec;
711     streamFormat.mChannelsPerFrame = lpDesc->lpFormat->nChannels;       
712     streamFormat.mFramesPerPacket = 1;  
713     streamFormat.mBitsPerChannel = lpDesc->lpFormat->wBitsPerSample;
714     streamFormat.mBytesPerFrame = streamFormat.mBitsPerChannel * streamFormat.mChannelsPerFrame / 8;    
715     streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket;         
716
717     ret = AudioUnit_InitializeWithStreamDescription(wwo->audioUnit, &streamFormat);
718     if (!ret) 
719     {
720         AudioUnit_CloseAudioUnit(wwo->audioUnit);
721         pthread_mutex_unlock(&wwo->lock);
722         return WAVERR_BADFORMAT; /* FIXME return an error based on the OSStatus */
723     }
724     wwo->streamDescription = streamFormat;
725     wwo->state = WINE_WS_STOPPED;
726                 
727     wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
728     
729     memcpy(&wwo->waveDesc, lpDesc,           sizeof(WAVEOPENDESC));
730     memcpy(&wwo->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
731     
732     if (wwo->format.wBitsPerSample == 0) {
733         WARN("Resetting zeroed wBitsPerSample\n");
734         wwo->format.wBitsPerSample = 8 *
735             (wwo->format.wf.nAvgBytesPerSec /
736              wwo->format.wf.nSamplesPerSec) /
737             wwo->format.wf.nChannels;
738     }
739     
740     wwo->dwPlayedTotal = 0;
741     wwo->dwWrittenTotal = 0;
742
743     wwo->trace_on = TRACE_ON(wave);
744     wwo->warn_on  = WARN_ON(wave);
745     wwo->err_on   = ERR_ON(wave);
746
747     pthread_mutex_unlock(&wwo->lock);
748     
749     retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
750     
751     return retval;
752 }
753
754 /**************************************************************************
755 *                               wodClose                        [internal]
756 */
757 static DWORD wodClose(WORD wDevID)
758 {
759     DWORD               ret = MMSYSERR_NOERROR;
760     WINE_WAVEOUT*       wwo;
761     
762     TRACE("(%u);\n", wDevID);
763     
764     if (wDevID >= MAX_WAVEOUTDRV)
765     {
766         WARN("bad device ID !\n");
767         return MMSYSERR_BADDEVICEID;
768     }
769     
770     wwo = &WOutDev[wDevID];
771     pthread_mutex_lock(&wwo->lock);
772     if (wwo->lpQueuePtr)
773     {
774         WARN("buffers still playing !\n");
775         pthread_mutex_unlock(&wwo->lock);
776         ret = WAVERR_STILLPLAYING;
777     } else
778     {
779         OSStatus err;
780         /* sanity check: this should not happen since the device must have been reset before */
781         if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
782         
783         wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
784         
785         err = AudioUnitUninitialize(wwo->audioUnit);
786         if (err) {
787             ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24),
788                                                             (char) (err >> 16),
789                                                             (char) (err >> 8),
790                                                             (char) err);
791             pthread_mutex_unlock(&wwo->lock);
792             return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
793         }
794         
795         if ( !AudioUnit_CloseAudioUnit(wwo->audioUnit) )
796         {
797             ERR("Can't close AudioUnit\n");
798             pthread_mutex_unlock(&wwo->lock);
799             return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
800         }  
801         pthread_mutex_unlock(&wwo->lock);
802         
803         ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
804     }
805     
806     return ret;
807 }
808
809 /**************************************************************************
810 *                               wodPrepare                      [internal]
811 */
812 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
813 {
814     TRACE("(%u, %p, %08x);\n", wDevID, lpWaveHdr, dwSize);
815     
816     if (wDevID >= MAX_WAVEOUTDRV) {
817         WARN("bad device ID !\n");
818         return MMSYSERR_BADDEVICEID;
819     }
820     
821     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
822         return WAVERR_STILLPLAYING;
823     
824     lpWaveHdr->dwFlags |= WHDR_PREPARED;
825     lpWaveHdr->dwFlags &= ~WHDR_DONE;
826
827     return MMSYSERR_NOERROR;
828 }
829
830 /**************************************************************************
831 *                               wodUnprepare                    [internal]
832 */
833 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
834 {
835     TRACE("(%u, %p, %08x);\n", wDevID, lpWaveHdr, dwSize);
836     
837     if (wDevID >= MAX_WAVEOUTDRV) {
838         WARN("bad device ID !\n");
839         return MMSYSERR_BADDEVICEID;
840     }
841     
842     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
843         return WAVERR_STILLPLAYING;
844     
845     lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
846     lpWaveHdr->dwFlags |= WHDR_DONE;
847    
848     return MMSYSERR_NOERROR;
849 }
850
851 /**************************************************************************
852 *                               wodHelper_BeginWaveHdr          [internal]
853 *
854 * Makes the specified lpWaveHdr the currently playing wave header.
855 * If the specified wave header is a begin loop and we're not already in
856 * a loop, setup the loop.
857 * Call from AudioUnit IO thread can't use Wine debug channels.
858 */
859 static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
860 {
861     OSStatus status;
862
863     wwo->lpPlayPtr = lpWaveHdr;
864     
865     if (!lpWaveHdr)
866     {
867         if (wwo->state == WINE_WS_PLAYING)
868         {
869             wwo->state = WINE_WS_STOPPED;
870             status = AudioOutputUnitStop(wwo->audioUnit);
871             if (status && wwo->err_on)
872                 fprintf(stderr, "err:winecoreaudio:wodHelper_BeginWaveHdr AudioOutputUnitStop return %c%c%c%c\n",
873                         (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
874         }
875         return;
876     }
877
878     if (wwo->state == WINE_WS_STOPPED)
879     {
880         status = AudioOutputUnitStart(wwo->audioUnit);
881         if (status) {
882             if (wwo->err_on)
883                 fprintf(stderr, "err:winecoreaudio:AudioOutputUnitStart return %c%c%c%c\n",
884                         (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
885         }
886         else wwo->state = WINE_WS_PLAYING;
887     }
888     
889     if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
890     {
891         if (wwo->lpLoopPtr)
892         {
893             if (wwo->warn_on)
894                 fprintf(stderr, "warn:winecoreaudio:wodHelper_BeginWaveHdr Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
895         } else
896         {
897             if (wwo->trace_on)
898                 fprintf(stderr, "trace:winecoreaudio:wodHelper_BeginWaveHdr Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
899
900             wwo->lpLoopPtr = lpWaveHdr;
901             /* Windows does not touch WAVEHDR.dwLoops,
902                 * so we need to make an internal copy */
903             wwo->dwLoops = lpWaveHdr->dwLoops;
904         }
905     }
906     wwo->dwPartialOffset = 0;
907 }
908
909
910 /**************************************************************************
911 *                               wodHelper_PlayPtrNext           [internal]
912 *
913 * Advance the play pointer to the next waveheader, looping if required.
914 * Call from AudioUnit IO thread can't use Wine debug channels.
915 */
916 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
917 {
918     LPWAVEHDR lpWaveHdr;
919
920     pthread_mutex_lock(&wwo->lock);
921     
922     lpWaveHdr = wwo->lpPlayPtr;
923     if (!lpWaveHdr)
924     {
925         pthread_mutex_unlock(&wwo->lock);
926         return NULL;
927     }
928
929     wwo->dwPartialOffset = 0;
930     if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
931     {
932         /* We're at the end of a loop, loop if required */
933         if (wwo->dwLoops > 1)
934         {
935             wwo->dwLoops--;
936             wwo->lpPlayPtr = wwo->lpLoopPtr;
937         } else
938         {
939             /* Handle overlapping loops correctly */
940             if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
941                 /* shall we consider the END flag for the closing loop or for
942                 * the opening one or for both ???
943                 * code assumes for closing loop only
944                 */
945             } else
946             {
947                 lpWaveHdr = lpWaveHdr->lpNext;
948             }
949             wwo->lpLoopPtr = NULL;
950             wodHelper_BeginWaveHdr(wwo, lpWaveHdr);
951         }
952     } else
953     {
954         /* We're not in a loop.  Advance to the next wave header */
955         wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
956     }
957     
958     pthread_mutex_unlock(&wwo->lock);
959     
960     return lpWaveHdr;
961 }
962
963 /* if force is TRUE then notify the client that all the headers were completed
964  * Call from AudioUnit IO thread can't use Wine debug channels.
965  */
966 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
967 {
968     LPWAVEHDR           lpWaveHdr;
969     DWORD retval;
970
971     pthread_mutex_lock(&wwo->lock);
972
973     /* Start from lpQueuePtr and keep notifying until:
974         * - we hit an unwritten wavehdr
975         * - we hit the beginning of a running loop
976         * - we hit a wavehdr which hasn't finished playing
977         */
978     while ((lpWaveHdr = wwo->lpQueuePtr) &&
979            (force || 
980             (lpWaveHdr != wwo->lpPlayPtr &&
981              lpWaveHdr != wwo->lpLoopPtr)))
982     {
983         wwo->lpQueuePtr = lpWaveHdr->lpNext;
984         
985         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
986         lpWaveHdr->dwFlags |= WHDR_DONE;
987         
988         wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
989     }
990
991     retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != 
992               wwo->lpLoopPtr) ? 0 : INFINITE;
993     
994     pthread_mutex_unlock(&wwo->lock);
995     
996     return retval;
997 }
998
999 /**************************************************************************
1000 *                               wodHelper_Reset                 [internal]
1001 *
1002 * Resets current output stream.
1003 */
1004 static  DWORD  wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset)
1005 {
1006     OSStatus status;
1007
1008     FIXME("\n");
1009    
1010     /* updates current notify list */
1011     /* if resetting, remove all wave headers and notify client that all headers were completed */
1012     wodHelper_NotifyCompletions(wwo, reset);
1013     
1014     pthread_mutex_lock(&wwo->lock);
1015     
1016     if (reset)
1017     {
1018         wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
1019         wwo->state = WINE_WS_STOPPED;
1020         wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
1021         
1022         wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */
1023     } 
1024     else
1025     {
1026         if (wwo->lpLoopPtr)
1027         {
1028             /* complicated case, not handled yet (could imply modifying the loop counter) */
1029             FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
1030             wwo->lpPlayPtr = wwo->lpLoopPtr;
1031             wwo->dwPartialOffset = 0;
1032             wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
1033         } else
1034         {
1035             LPWAVEHDR   ptr;
1036             DWORD       sz = wwo->dwPartialOffset;
1037             
1038             /* reset all the data as if we had written only up to lpPlayedTotal bytes */
1039             /* compute the max size playable from lpQueuePtr */
1040             for (ptr = wwo->lpQueuePtr; ptr && ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)
1041             {
1042                 sz += ptr->dwBufferLength;
1043             }
1044             
1045             /* because the reset lpPlayPtr will be lpQueuePtr */
1046             if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");
1047             wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
1048             wwo->dwWrittenTotal = wwo->dwPlayedTotal;
1049             wwo->lpPlayPtr = wwo->lpQueuePtr;
1050         }
1051         
1052         wwo->state = WINE_WS_PAUSED;
1053     }
1054
1055     status = AudioOutputUnitStop(wwo->audioUnit);
1056
1057     pthread_mutex_unlock(&wwo->lock);
1058
1059     if (status) {
1060         ERR( "AudioOutputUnitStop return %c%c%c%c\n",
1061              (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1062         return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1063     }
1064
1065     return MMSYSERR_NOERROR;
1066 }
1067
1068
1069 /**************************************************************************
1070 *                               wodWrite                        [internal]
1071
1072 */
1073 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1074 {
1075     LPWAVEHDR*wh;
1076     WINE_WAVEOUT *wwo;
1077     
1078     TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
1079     
1080     /* first, do the sanity checks... */
1081     if (wDevID >= MAX_WAVEOUTDRV)
1082     {
1083         WARN("bad dev ID !\n");
1084         return MMSYSERR_BADDEVICEID;
1085     }
1086     
1087     wwo = &WOutDev[wDevID];
1088     
1089     if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1090     {
1091         TRACE("unprepared\n");
1092         return WAVERR_UNPREPARED;
1093     }
1094     
1095     if (lpWaveHdr->dwFlags & WHDR_INQUEUE) 
1096     {
1097         TRACE("still playing\n");
1098         return WAVERR_STILLPLAYING;
1099     }
1100     
1101     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1102     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1103     lpWaveHdr->lpNext = 0;
1104
1105     pthread_mutex_lock(&wwo->lock);
1106     /* insert buffer at the end of queue */
1107     for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
1108         /* Do nothing */;
1109     *wh = lpWaveHdr;
1110     
1111     if (!wwo->lpPlayPtr)
1112         wodHelper_BeginWaveHdr(wwo,lpWaveHdr);
1113     pthread_mutex_unlock(&wwo->lock);
1114     
1115     return MMSYSERR_NOERROR;
1116 }
1117
1118 /**************************************************************************
1119 *                       wodPause                                [internal]
1120 */
1121 static DWORD wodPause(WORD wDevID)
1122 {
1123     OSStatus status;
1124
1125     TRACE("(%u);!\n", wDevID);
1126     
1127     if (wDevID >= MAX_WAVEOUTDRV)
1128     {
1129         WARN("bad device ID !\n");
1130         return MMSYSERR_BADDEVICEID;
1131     }
1132     
1133     pthread_mutex_lock(&WOutDev[wDevID].lock);
1134     if (WOutDev[wDevID].state == WINE_WS_PLAYING || WOutDev[wDevID].state == WINE_WS_STOPPED)
1135     {
1136         WOutDev[wDevID].state = WINE_WS_PAUSED;
1137         status = AudioOutputUnitStop(WOutDev[wDevID].audioUnit);
1138         if (status) {
1139             ERR( "AudioOutputUnitStop return %c%c%c%c\n",
1140                  (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1141             pthread_mutex_unlock(&WOutDev[wDevID].lock);
1142             return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1143         }
1144     }
1145     pthread_mutex_unlock(&WOutDev[wDevID].lock);
1146     
1147     return MMSYSERR_NOERROR;
1148 }
1149
1150 /**************************************************************************
1151 *                       wodRestart                              [internal]
1152 */
1153 static DWORD wodRestart(WORD wDevID)
1154 {
1155     TRACE("(%u);\n", wDevID);
1156     
1157     if (wDevID >= MAX_WAVEOUTDRV )
1158     {
1159         WARN("bad device ID !\n");
1160         return MMSYSERR_BADDEVICEID;
1161     }
1162     
1163     pthread_mutex_lock(&WOutDev[wDevID].lock);
1164     if (WOutDev[wDevID].state == WINE_WS_PAUSED)
1165     {
1166         if (WOutDev[wDevID].lpPlayPtr)
1167         {
1168             OSStatus status = AudioOutputUnitStart(WOutDev[wDevID].audioUnit);
1169             if (status) {
1170                 ERR("AudioOutputUnitStart return %c%c%c%c\n",
1171                     (char) (status >> 24), (char) (status >> 16), (char) (status >> 8), (char) status);
1172                 pthread_mutex_unlock(&WOutDev[wDevID].lock);
1173                 return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
1174             }
1175             WOutDev[wDevID].state = WINE_WS_PLAYING;
1176         }
1177         else
1178             WOutDev[wDevID].state = WINE_WS_STOPPED;
1179     }
1180     pthread_mutex_unlock(&WOutDev[wDevID].lock);
1181     
1182     return MMSYSERR_NOERROR;
1183 }
1184
1185 /**************************************************************************
1186 *                       wodReset                                [internal]
1187 */
1188 static DWORD wodReset(WORD wDevID)
1189 {
1190     TRACE("(%u);\n", wDevID);
1191     
1192     if (wDevID >= MAX_WAVEOUTDRV)
1193     {
1194         WARN("bad device ID !\n");
1195         return MMSYSERR_BADDEVICEID;
1196     }
1197     
1198     return wodHelper_Reset(&WOutDev[wDevID], TRUE);
1199 }
1200
1201 /**************************************************************************
1202 *                               wodGetPosition                  [internal]
1203 */
1204 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1205 {
1206     DWORD               val;
1207     WINE_WAVEOUT*       wwo;
1208
1209     TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
1210     
1211     if (wDevID >= MAX_WAVEOUTDRV)
1212     {
1213         WARN("bad device ID !\n");
1214         return MMSYSERR_BADDEVICEID;
1215     }
1216     
1217     /* if null pointer to time structure return error */
1218     if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1219     
1220     wwo = &WOutDev[wDevID];
1221     
1222     pthread_mutex_lock(&WOutDev[wDevID].lock);
1223     val = wwo->dwPlayedTotal;
1224     pthread_mutex_unlock(&WOutDev[wDevID].lock);
1225     
1226     return bytes_to_mmtime(lpTime, val, &wwo->format);
1227 }
1228
1229 /**************************************************************************
1230 *                               wodGetVolume                    [internal]
1231 */
1232 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1233 {
1234     float left;
1235     float right;
1236     
1237     if (wDevID >= MAX_WAVEOUTDRV)
1238     {
1239         WARN("bad device ID !\n");
1240         return MMSYSERR_BADDEVICEID;
1241     }    
1242     
1243     TRACE("(%u, %p);\n", wDevID, lpdwVol);
1244     
1245     pthread_mutex_lock(&WOutDev[wDevID].lock);
1246     
1247     AudioUnit_GetVolume(WOutDev[wDevID].audioUnit, &left, &right); 
1248         
1249     pthread_mutex_unlock(&WOutDev[wDevID].lock);
1250         
1251     *lpdwVol = ((WORD) left * 0xFFFFl) + (((WORD) right * 0xFFFFl) << 16);
1252     
1253     return MMSYSERR_NOERROR;
1254 }
1255
1256 /**************************************************************************
1257 *                               wodSetVolume                    [internal]
1258 */
1259 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1260 {
1261     float left;
1262     float right;
1263     
1264     if (wDevID >= MAX_WAVEOUTDRV)
1265     {
1266         WARN("bad device ID !\n");
1267         return MMSYSERR_BADDEVICEID;
1268     }
1269
1270     left  = LOWORD(dwParam) / 65535.0f;
1271     right = HIWORD(dwParam) / 65535.0f;
1272     
1273     TRACE("(%u, %08x);\n", wDevID, dwParam);
1274     
1275     pthread_mutex_lock(&WOutDev[wDevID].lock);
1276     
1277     AudioUnit_SetVolume(WOutDev[wDevID].audioUnit, left, right); 
1278         
1279     pthread_mutex_unlock(&WOutDev[wDevID].lock);
1280     
1281     return MMSYSERR_NOERROR;
1282 }
1283
1284 /**************************************************************************
1285 *                               wodGetNumDevs                   [internal]
1286 */
1287 static DWORD wodGetNumDevs(void)
1288 {
1289     TRACE("\n");
1290     return MAX_WAVEOUTDRV;
1291 }
1292
1293 /**************************************************************************
1294 *                              wodDevInterfaceSize             [internal]
1295 */
1296 static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1297 {
1298     TRACE("(%u, %p)\n", wDevID, dwParam1);
1299     
1300     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1301                                     NULL, 0 ) * sizeof(WCHAR);
1302     return MMSYSERR_NOERROR;
1303 }
1304
1305 /**************************************************************************
1306 *                              wodDevInterface                 [internal]
1307 */
1308 static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1309 {
1310     TRACE("\n");
1311     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1312                                         NULL, 0 ) * sizeof(WCHAR))
1313     {
1314         MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
1315                             dwParam1, dwParam2 / sizeof(WCHAR));
1316         return MMSYSERR_NOERROR;
1317     }
1318     return MMSYSERR_INVALPARAM;
1319 }
1320
1321 /**************************************************************************
1322 *                               wodMessage (WINEJACK.7)
1323 */
1324 DWORD WINAPI CoreAudio_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
1325                                   DWORD dwParam1, DWORD dwParam2)
1326 {
1327     TRACE("(%u, %s, %08x, %08x, %08x);\n",
1328           wDevID, getMessage(wMsg), dwUser, dwParam1, dwParam2);
1329     
1330     switch (wMsg) {
1331         case DRVM_INIT:
1332         case DRVM_EXIT:
1333         case DRVM_ENABLE:
1334         case DRVM_DISABLE:
1335             
1336             /* FIXME: Pretend this is supported */
1337             return 0;
1338         case WODM_OPEN:         return wodOpen(wDevID, (LPWAVEOPENDESC) dwParam1, dwParam2);          
1339         case WODM_CLOSE:        return wodClose(wDevID);
1340         case WODM_WRITE:        return wodWrite(wDevID, (LPWAVEHDR) dwParam1, dwParam2);
1341         case WODM_PAUSE:        return wodPause(wDevID);  
1342         case WODM_GETPOS:       return wodGetPosition(wDevID, (LPMMTIME) dwParam1, dwParam2);
1343         case WODM_BREAKLOOP:    return MMSYSERR_NOTSUPPORTED;
1344         case WODM_PREPARE:      return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1345         case WODM_UNPREPARE:    return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1346             
1347         case WODM_GETDEVCAPS:   return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSW) dwParam1, dwParam2);
1348         case WODM_GETNUMDEVS:   return wodGetNumDevs();  
1349             
1350         case WODM_GETPITCH:         
1351         case WODM_SETPITCH:        
1352         case WODM_GETPLAYBACKRATE:      
1353         case WODM_SETPLAYBACKRATE:      return MMSYSERR_NOTSUPPORTED;
1354         case WODM_GETVOLUME:    return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1355         case WODM_SETVOLUME:    return wodSetVolume(wDevID, dwParam1);
1356         case WODM_RESTART:      return wodRestart(wDevID);
1357         case WODM_RESET:        return wodReset(wDevID);
1358             
1359         case DRV_QUERYDEVICEINTERFACESIZE:  return wodDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
1360         case DRV_QUERYDEVICEINTERFACE:      return wodDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
1361         case DRV_QUERYDSOUNDIFACE:      
1362         case DRV_QUERYDSOUNDDESC:       
1363             return MMSYSERR_NOTSUPPORTED;
1364             
1365         default:
1366             FIXME("unknown message %d!\n", wMsg);
1367     }
1368     
1369     return MMSYSERR_NOTSUPPORTED;
1370 }
1371
1372 /*======================================================================*
1373 *                  Low level DSOUND implementation                      *
1374 *======================================================================*/
1375
1376 typedef struct IDsDriverImpl IDsDriverImpl;
1377 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1378
1379 struct IDsDriverImpl
1380 {
1381     /* IUnknown fields */
1382     const IDsDriverVtbl *lpVtbl;
1383     DWORD               ref;
1384     /* IDsDriverImpl fields */
1385     UINT                wDevID;
1386     IDsDriverBufferImpl*primary;
1387 };
1388
1389 struct IDsDriverBufferImpl
1390 {
1391     /* IUnknown fields */
1392     const IDsDriverBufferVtbl *lpVtbl;
1393     DWORD ref;
1394     /* IDsDriverBufferImpl fields */
1395     IDsDriverImpl* drv;
1396     DWORD buflen;
1397 };
1398
1399
1400 /*
1401     CoreAudio IO threaded callback,
1402     we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
1403 */
1404 OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
1405                                      AudioUnitRenderActionFlags *ioActionFlags, 
1406                                      const AudioTimeStamp *inTimeStamp, 
1407                                      UInt32 inBusNumber, 
1408                                      UInt32 inNumberFrames, 
1409                                      AudioBufferList *ioData)
1410 {
1411     UInt32 buffer;
1412     WINE_WAVEOUT *wwo = (WINE_WAVEOUT *) inRefCon;
1413     int nextPtr = 0;
1414     int needNotify = 0;
1415
1416     unsigned int dataNeeded = ioData->mBuffers[0].mDataByteSize;
1417     unsigned int dataProvided = 0;
1418
1419     while (dataNeeded > 0)
1420     {
1421         pthread_mutex_lock(&wwo->lock);
1422
1423         if (wwo->state == WINE_WS_PLAYING && wwo->lpPlayPtr)
1424         {
1425             unsigned int available = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
1426             unsigned int toCopy;
1427
1428             if (available >= dataNeeded)
1429                 toCopy = dataNeeded;
1430             else
1431                 toCopy = available;
1432
1433             if (toCopy > 0)
1434             {
1435                 memcpy((char*)ioData->mBuffers[0].mData + dataProvided,
1436                     wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, toCopy);
1437                 wwo->dwPartialOffset += toCopy;
1438                 wwo->dwPlayedTotal += toCopy;
1439                 dataProvided += toCopy;
1440                 dataNeeded -= toCopy;
1441                 available -= toCopy;
1442             }
1443
1444             if (available == 0)
1445                 nextPtr = 1;
1446
1447             needNotify = 1;
1448         }
1449         else
1450         {
1451             memset((char*)ioData->mBuffers[0].mData + dataProvided, 0, dataNeeded);
1452             dataProvided += dataNeeded;
1453             dataNeeded = 0;
1454         }
1455
1456         pthread_mutex_unlock(&wwo->lock);
1457
1458         if (nextPtr)
1459         {
1460             wodHelper_PlayPtrNext(wwo);
1461             nextPtr = 0;
1462         }
1463     }
1464
1465     /* We only fill buffer 0.  Set any others that might be requested to 0. */
1466     for (buffer = 1; buffer < ioData->mNumberBuffers; buffer++)
1467     {
1468         memset(ioData->mBuffers[buffer].mData, 0, ioData->mBuffers[buffer].mDataByteSize);
1469     }
1470
1471     if (needNotify) wodHelper_NotifyCompletions(wwo, FALSE);
1472     return noErr;
1473 }
1474 #else
1475
1476 /**************************************************************************
1477 *                               wodMessage (WINECOREAUDIO.7)
1478 */
1479 DWORD WINAPI CoreAudio_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1480                                   DWORD dwParam1, DWORD dwParam2)
1481 {
1482     FIXME("(%u, %04X, %08X, %08X, %08X): CoreAudio support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1483     return MMSYSERR_NOTENABLED;
1484 }
1485
1486 #endif