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