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