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