--- /dev/null	2006-05-25 21:19:13.000000000 +0200
+++ dlls/winmm/winecoreaudio/audio.c	2006-05-25 21:16:42.000000000 +0200
@@ -0,0 +1,1455 @@
+/*
+ * Wine Driver for CoreAudio based on Jack Driver
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn)
+ * Copyright 2000 Eric Pouech (loops in waveOut)
+ * Copyright 2002 Chris Morgan (jack version of this file)
+ * Copyright 2005, 2006 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "wingdi.h"
+#include "winerror.h"
+#include "mmddk.h"
+#include "dsound.h"
+#include "dsdriver.h"
+#include "coreaudio.h"
+#include "wine/unicode.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wave);
+
+
+#if defined(HAVE_COREAUDIO_COREAUDIO_H) && defined(HAVE_AUDIOUNIT_AUDIOUNIT_H)
+#include <CoreAudio/CoreAudio.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+/*
+    Due to AudioUnit headers conflict define some needed types.
+*/
+
+typedef void *AudioUnit;
+
+/* From AudioUnit/AUComponents.h */
+typedef UInt32 AudioUnitRenderActionFlags;
+
+/* only allow 10 output devices through this driver, this ought to be adequate */
+#define MAX_WAVEOUTDRV  (1)
+#define MAX_WAVEINDRV   (1)
+
+/* state diagram for waveOut writing:
+*
+* +---------+-------------+---------------+---------------------------------+
+* |  state  |  function   |     event     |            new state	     |
+* +---------+-------------+---------------+---------------------------------+
+* |	     | open()	   |		   | STOPPED		       	     |
+* | PAUSED  | write()	   | 		   | PAUSED		       	     |
+* | STOPPED | write()	   | <thrd create> | PLAYING		  	     |
+* | PLAYING | write()	   | HEADER        | PLAYING		  	     |
+* | (other) | write()	   | <error>       |		       		     |
+* | (any)   | pause()	   | PAUSING	   | PAUSED		       	     |
+* | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
+* | (any)   | reset()	   | RESETTING     | STOPPED		      	     |
+* | (any)   | close()	   | CLOSING	   | CLOSED		      	     |
+* +---------+-------------+---------------+---------------------------------+
+*/
+
+/* states of the playing device */
+#define	WINE_WS_PLAYING   0
+#define	WINE_WS_PAUSED    1
+#define	WINE_WS_STOPPED   2
+#define WINE_WS_CLOSED    3
+
+typedef struct tagCoreAudio_Device {
+    char                        dev_name[32];
+    char                        mixer_name[32];
+    unsigned                    open_count;
+    char*                       interface_name;
+    
+    WAVEOUTCAPSA                out_caps;
+    WAVEINCAPSA                 in_caps;
+    DWORD                       in_caps_support;
+    int                         sample_rate;
+    int                         stereo;
+    int                         format;
+    unsigned                    audio_fragment;
+    BOOL                        full_duplex;
+    BOOL                        bTriggerSupport;
+    BOOL                        bOutputEnabled;
+    BOOL                        bInputEnabled;
+    DSDRIVERDESC                ds_desc;
+    DSDRIVERCAPS                ds_caps;
+    DSCDRIVERCAPS               dsc_caps;
+    GUID                        ds_guid;
+    GUID                        dsc_guid;
+    
+    AudioDeviceID outputDeviceID;
+    AudioDeviceID inputDeviceID;
+    AudioStreamBasicDescription streamDescription;
+} CoreAudio_Device;
+
+/* for now use the default device */
+static CoreAudio_Device CoreAudio_DefaultDevice;
+
+typedef struct {
+    volatile int                state;      /* one of the WINE_WS_ manifest constants */
+    CoreAudio_Device            *cadev;
+    WAVEOPENDESC                waveDesc;
+    WORD                        wFlags;
+    PCMWAVEFORMAT               format;
+    DWORD                       woID;
+    AudioUnit                   audioUnit;
+    AudioStreamBasicDescription streamDescription;
+    
+    WAVEOUTCAPSW                caps;
+    char                        interface_name[32];
+    LPWAVEHDR			lpQueuePtr;		/* start of queued WAVEHDRs (waiting to be notified) */
+    LPWAVEHDR			lpPlayPtr;		/* start of not yet fully played buffers */
+    DWORD			dwPartialOffset;	/* Offset of not yet written bytes in lpPlayPtr */
+    
+    LPWAVEHDR			lpLoopPtr;              /* pointer of first buffer in loop, if any */
+    DWORD			dwLoops;		/* private copy of loop counter */
+    
+    DWORD			dwPlayedTotal;		/* number of bytes actually played since opening */
+    DWORD                       dwWrittenTotal;         /* number of bytes written to OSS buffer since opening */
+        
+    DWORD                       tickCountMS; /* time in MS of last AudioUnit callback */
+
+    pthread_mutex_t             lock;         /* synchronization stuff */
+} WINE_WAVEOUT;
+
+typedef struct {
+    volatile int    state;
+    CoreAudio_Device *cadev;
+    WAVEOPENDESC    waveDesc;
+    WORD            wFlags;
+    PCMWAVEFORMAT   format;
+    LPWAVEHDR       lpQueuePtr;
+    DWORD           dwTotalRecorded;
+    WAVEINCAPSW     caps;
+    
+    AudioUnit                   audioUnit;
+    AudioStreamBasicDescription streamDescription;
+        
+    /*  BOOL            bTriggerSupport;
+    WORD              wDevID;
+    char              interface_name[32];*/
+        
+    /* synchronization stuff */
+    pthread_mutex_t lock;
+} WINE_WAVEIN;
+
+static WINE_WAVEOUT WOutDev   [MAX_WAVEOUTDRV];
+static WINE_WAVEIN  WInDev    [MAX_WAVEINDRV ];
+
+static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
+static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
+
+static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
+static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
+
+extern int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au);
+extern int AudioUnit_CloseAudioUnit(AudioUnit au);
+extern int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription streamFormat);
+
+extern OSStatus AudioOutputUnitStart(AudioUnit au);
+extern OSStatus AudioOutputUnitStop(AudioUnit au);
+extern OSStatus AudioUnitUninitialize(AudioUnit au);
+
+extern int AudioUnit_SetVolume(AudioUnit au, float left, float right);
+extern int AudioUnit_GetVolume(AudioUnit au, float *left, float *right);
+
+OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
+                                     AudioUnitRenderActionFlags *ioActionFlags, 
+                                     const AudioTimeStamp *inTimeStamp, 
+                                     UInt32 inBusNumber, 
+                                     UInt32 inNumberFrames, 
+                                     AudioBufferList *ioData);
+
+/* These strings used only for tracing */
+
+static const char * getMessage(UINT msg)
+{
+    static char unknown[32];
+#define MSG_TO_STR(x) case x: return #x
+    switch(msg) {
+        MSG_TO_STR(DRVM_INIT);
+        MSG_TO_STR(DRVM_EXIT);
+        MSG_TO_STR(DRVM_ENABLE);
+        MSG_TO_STR(DRVM_DISABLE);
+        MSG_TO_STR(WIDM_OPEN);
+        MSG_TO_STR(WIDM_CLOSE);
+        MSG_TO_STR(WIDM_ADDBUFFER);
+        MSG_TO_STR(WIDM_PREPARE);
+        MSG_TO_STR(WIDM_UNPREPARE);
+        MSG_TO_STR(WIDM_GETDEVCAPS);
+        MSG_TO_STR(WIDM_GETNUMDEVS);
+        MSG_TO_STR(WIDM_GETPOS);
+        MSG_TO_STR(WIDM_RESET);
+        MSG_TO_STR(WIDM_START);
+        MSG_TO_STR(WIDM_STOP);
+        MSG_TO_STR(WODM_OPEN);
+        MSG_TO_STR(WODM_CLOSE);
+        MSG_TO_STR(WODM_WRITE);
+        MSG_TO_STR(WODM_PAUSE);
+        MSG_TO_STR(WODM_GETPOS);
+        MSG_TO_STR(WODM_BREAKLOOP);
+        MSG_TO_STR(WODM_PREPARE);
+        MSG_TO_STR(WODM_UNPREPARE);
+        MSG_TO_STR(WODM_GETDEVCAPS);
+        MSG_TO_STR(WODM_GETNUMDEVS);
+        MSG_TO_STR(WODM_GETPITCH);
+        MSG_TO_STR(WODM_SETPITCH);
+        MSG_TO_STR(WODM_GETPLAYBACKRATE);
+        MSG_TO_STR(WODM_SETPLAYBACKRATE);
+        MSG_TO_STR(WODM_GETVOLUME);
+        MSG_TO_STR(WODM_SETVOLUME);
+        MSG_TO_STR(WODM_RESTART);
+        MSG_TO_STR(WODM_RESET);
+        MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
+        MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
+        MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
+        MSG_TO_STR(DRV_QUERYDSOUNDDESC);
+    }
+#undef MSG_TO_STR
+    sprintf(unknown, "UNKNOWN(0x%04x)", msg);
+    return unknown;
+}
+
+//#define TRACE
+
+#define kStopLoopMessage 0
+#define kWaveOutCallbackMessage 1
+#define kWaveInCallbackMessage 2
+
+/* Mach Message Handling */
+static CFDataRef wodMessageHandler(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info)
+{
+    UInt32 *buffer = NULL;
+    WINE_WAVEOUT* wwo = NULL;
+    
+    switch (msgid)
+    {
+        case kWaveOutCallbackMessage:
+            buffer = (UInt32 *) CFDataGetBytePtr(data);
+            wwo = &WOutDev[buffer[0]];
+            
+            pthread_mutex_lock(&wwo->lock);
+            DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
+                           (HDRVR)wwo->waveDesc.hWave, (WORD)buffer[1], wwo->waveDesc.dwInstance,
+                           (DWORD)buffer[2], (DWORD)buffer[3]);
+            pthread_mutex_unlock(&wwo->lock);
+            break;
+        case kWaveInCallbackMessage:
+        default:
+            CFRunLoopStop(CFRunLoopGetCurrent());
+            break;
+    }
+    
+    return NULL;
+}
+
+static DWORD messageThread(LPVOID p)
+{
+    CFMessagePortRef local;
+    CFRunLoopSourceRef source;
+    Boolean info;
+    
+    local = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("WaveMessagePort"), 
+                                        &wodMessageHandler, NULL, &info);
+                                        
+    source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, local, (CFIndex)0);
+    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
+        
+    CFRunLoopRun();
+    
+    return 0;
+}
+
+static DWORD wodSendDriverCallbackMessage(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
+{
+    CFDataRef data;
+    UInt32 *buffer;
+    SInt32 ret;
+    
+    CFMessagePortRef messagePort;
+    messagePort = CFMessagePortCreateRemote(kCFAllocatorDefault, CFSTR("WaveMessagePort"));
+        
+    buffer = CFAllocatorAllocate(NULL, sizeof(UInt32) * 4, 0);
+    if (!buffer)
+        return 0;
+    
+    buffer[0] = (UInt32) wwo->woID;
+    buffer[1] = (UInt32) wMsg;
+    buffer[2] = (UInt32) dwParam1;
+    buffer[3] = (UInt32) dwParam2;
+    
+    data = CFDataCreate(kCFAllocatorDefault, buffer, sizeof(UInt32) * 4);
+    if (!data)
+    {
+        CFAllocatorDeallocate(NULL, buffer);
+        return 0;
+    }
+    
+    ret = CFMessagePortSendRequest(messagePort, kWaveOutCallbackMessage, data, 0.0, 0.0, NULL, NULL);
+    CFRelease(data);
+    CFAllocatorDeallocate(NULL, buffer);
+    
+    return (ret == kCFMessagePortSuccess)?1:0;
+}
+
+static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
+                             PCMWAVEFORMAT* format)
+{
+    TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
+          lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
+          format->wf.nChannels, format->wf.nAvgBytesPerSec);
+    TRACE("Position in bytes=%lu\n", position);
+
+    switch (lpTime->wType) {
+    case TIME_SAMPLES:
+        lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
+        break;
+    case TIME_MS:
+        lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
+        TRACE("TIME_MS=%lu\n", lpTime->u.ms);
+        break;
+    case TIME_SMPTE:
+        lpTime->u.smpte.fps = 30;
+        position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
+        position += (format->wf.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
+        lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
+        position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
+        lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
+        lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
+        lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
+        lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
+        lpTime->u.smpte.fps = 30;
+        lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
+        TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
+              lpTime->u.smpte.hour, lpTime->u.smpte.min,
+              lpTime->u.smpte.sec, lpTime->u.smpte.frame);
+        break;
+    default:
+        WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
+        lpTime->wType = TIME_BYTES;
+        /* fall through */
+    case TIME_BYTES:
+        lpTime->u.cb = position;
+        TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
+        break;
+    }
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 			CoreAudio_GetDevCaps            [internal]
+*/
+BOOL CoreAudio_GetDevCaps (void)
+{
+    OSStatus status;
+    UInt32 propertySize;
+    AudioDeviceID devId = CoreAudio_DefaultDevice.outputDeviceID;
+    
+    char name[MAXPNAMELEN];
+    
+    propertySize = MAXPNAMELEN;
+    status = AudioDeviceGetProperty(devId, 0 , FALSE, kAudioDevicePropertyDeviceName, &propertySize, name);
+    if (status) {
+        ERR("AudioHardwareGetProperty for kAudioDevicePropertyDeviceName return %c%c%c%c\n", (char) (status >> 24),
+                                                                                             (char) (status >> 16),
+                                                                                             (char) (status >> 8),
+                                                                                             (char) status);
+        return FALSE;
+    }
+    
+    memcpy(CoreAudio_DefaultDevice.ds_desc.szDesc, name, sizeof(name));
+    strcpy(CoreAudio_DefaultDevice.ds_desc.szDrvname, "winecoreaudio.drv");
+    MultiByteToWideChar(CP_ACP, 0, name, sizeof(name), 
+                        CoreAudio_DefaultDevice.out_caps.szPname, 
+                        sizeof(CoreAudio_DefaultDevice.out_caps.szPname) / sizeof(WCHAR));
+    memcpy(CoreAudio_DefaultDevice.dev_name, name, 32);
+    
+    propertySize = sizeof(CoreAudio_DefaultDevice.streamDescription);
+    status = AudioDeviceGetProperty(devId, 0, FALSE , kAudioDevicePropertyStreamFormat, &propertySize, &CoreAudio_DefaultDevice.streamDescription);
+    if (status != noErr) {
+        ERR("AudioHardwareGetProperty for kAudioDevicePropertyStreamFormat return %c%c%c%c\n", (char) (status >> 24),
+                                                                                                (char) (status >> 16),
+                                                                                                (char) (status >> 8),
+                                                                                                (char) status);
+        return FALSE;
+    }
+    
+    TRACE("Device Stream Description mSampleRate : %f\n mFormatID : %c%c%c%c\n"
+            "mFormatFlags : %lX\n mBytesPerPacket : %u\n mFramesPerPacket : %u\n"
+            "mBytesPerFrame : %u\n mChannelsPerFrame : %u\n mBitsPerChannel : %u\n",
+                               CoreAudio_DefaultDevice.streamDescription.mSampleRate,
+                               (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 24),
+                               (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 16),
+                               (char) (CoreAudio_DefaultDevice.streamDescription.mFormatID >> 8),
+                               (char) CoreAudio_DefaultDevice.streamDescription.mFormatID,
+                               CoreAudio_DefaultDevice.streamDescription.mFormatFlags,
+                               CoreAudio_DefaultDevice.streamDescription.mBytesPerPacket,
+                               CoreAudio_DefaultDevice.streamDescription.mFramesPerPacket,
+                               CoreAudio_DefaultDevice.streamDescription.mBytesPerFrame,
+                               CoreAudio_DefaultDevice.streamDescription.mChannelsPerFrame,
+                               CoreAudio_DefaultDevice.streamDescription.mBitsPerChannel);
+    
+    CoreAudio_DefaultDevice.out_caps.wMid = 0xcafe;
+    CoreAudio_DefaultDevice.out_caps.wPid = 0x0001;
+    
+    CoreAudio_DefaultDevice.out_caps.vDriverVersion = 0x0001;
+    CoreAudio_DefaultDevice.out_caps.dwFormats = 0x00000000;
+    CoreAudio_DefaultDevice.out_caps.wReserved1 = 0;
+    CoreAudio_DefaultDevice.out_caps.dwSupport = WAVECAPS_VOLUME;
+    CoreAudio_DefaultDevice.out_caps.dwSupport |= WAVECAPS_LRVOLUME;
+    
+    CoreAudio_DefaultDevice.out_caps.wChannels = 2;
+    CoreAudio_DefaultDevice.out_caps.dwFormats|= WAVE_FORMAT_4S16;
+        
+    printf("out dwFormats = %08lX, dwSupport = %08lX\n",
+           CoreAudio_DefaultDevice.out_caps.dwFormats, CoreAudio_DefaultDevice.out_caps.dwSupport);
+    
+    return TRUE;
+}
+
+/******************************************************************
+*		CoreAudio_WaveInit
+*
+* Initialize CoreAudio_DefaultDevice
+*/
+LONG CoreAudio_WaveInit(void)
+{
+    OSStatus status;
+    UInt32 propertySize;
+    CHAR szPname[MAXPNAMELEN];
+    int i;
+    HANDLE hThread;
+
+    TRACE("()\n");
+    
+    /* number of sound cards */
+    AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propertySize, NULL);
+    propertySize /= sizeof(AudioDeviceID);
+    TRACE("sound cards : %u\n", propertySize);
+    
+    /* Get the output device */
+    propertySize = sizeof(CoreAudio_DefaultDevice.outputDeviceID);
+    status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &CoreAudio_DefaultDevice.outputDeviceID);
+    if (status) {
+        ERR("AudioHardwareGetProperty return %c%c%c%c for kAudioHardwarePropertyDefaultOutputDevice\n", (char) (status >> 24),
+                                                                                                (char) (status >> 16),
+                                                                                                (char) (status >> 8),
+                                                                                                (char) status);
+        return 1;
+    }
+    if (CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown) {
+        ERR("AudioHardwareGetProperty: CoreAudio_DefaultDevice.outputDeviceID == kAudioDeviceUnknown\n");
+        return 1;
+    }
+    
+    if ( ! CoreAudio_GetDevCaps() )
+        return 1;
+    
+    CoreAudio_DefaultDevice.interface_name=HeapAlloc(GetProcessHeap(),0,strlen(CoreAudio_DefaultDevice.dev_name)+1);
+    sprintf(CoreAudio_DefaultDevice.interface_name, "%s", CoreAudio_DefaultDevice.dev_name);
+    
+    for (i = 0; i < MAX_WAVEOUTDRV; ++i)
+    {
+        WOutDev[i].state = WINE_WS_CLOSED;
+        WOutDev[i].cadev = &CoreAudio_DefaultDevice; 
+        WOutDev[i].woID = i;
+        
+        memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
+        
+        WOutDev[i].caps.wMid = 0xcafe; 	/* Manufac ID */
+        WOutDev[i].caps.wPid = 0x0001; 	/* Product ID */
+        snprintf(szPname, sizeof(szPname), "CoreAudio WaveOut %d", i);
+        MultiByteToWideChar(CP_ACP, 0, szPname, -1, WOutDev[i].caps.szPname, sizeof(WOutDev[i].caps.szPname)/sizeof(WCHAR));
+        snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winecoreaudio: %d", i);
+        
+        WOutDev[i].caps.vDriverVersion = 0x0001;
+        WOutDev[i].caps.dwFormats = 0x00000000;
+        WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
+        
+        WOutDev[i].caps.wChannels = 2;
+      /*  WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME; */ /* FIXME */
+        
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; 
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; 
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
+        WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
+    }
+    
+    /* create mach messages handler */
+    hThread = CreateThread(NULL, 0, messageThread, NULL, 0, NULL);
+    if ( !hThread )
+    {
+        ERR("Can't create message thread\n");
+        return 1;
+    }
+    
+    return 0;
+}
+
+void CoreAudio_WaveRelease(void)
+{
+    TRACE("()\n");
+    
+    /* Stop CFRunLoop in messageThread */
+    CFMessagePortRef messagePort;
+ 
+    messagePort = CFMessagePortCreateRemote(kCFAllocatorDefault, CFSTR("WaveMessagePort"));
+    CFMessagePortSendRequest(messagePort, kStopLoopMessage, NULL, 0.0, 0.0, NULL, NULL);
+    CFRelease(messagePort);
+}
+
+/*======================================================================*
+*                  Low level WAVE OUT implementation			*
+*======================================================================*/
+
+/**************************************************************************
+* 			wodNotifyClient			[internal]
+*/
+static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
+{
+    /* Call from AudioUnit IO thread can't use Wine debug channels */
+    fprintf(stderr, "trace:winecoreaudio:wodNotifyClient wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
+
+    switch (wMsg) {
+        case WOM_OPEN:
+        case WOM_CLOSE:
+            if (wwo->wFlags != DCB_NULL &&
+                !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
+                                (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
+                                dwParam1, dwParam2))
+            {
+                fprintf(stderr, "can't notify client !\n");
+                return MMSYSERR_ERROR;
+            }
+            break;
+        case WOM_DONE:
+            if (wwo->wFlags != DCB_NULL &&
+                ! wodSendDriverCallbackMessage(wwo, wMsg, dwParam1, dwParam2))
+            {
+                fprintf(stderr, "can't notify client !\n");
+                return MMSYSERR_ERROR;
+            }
+            break;
+        default:
+            fprintf(stderr, "Unknown callback message %u\n", wMsg);
+            return MMSYSERR_INVALPARAM;
+    }
+    return MMSYSERR_NOERROR;
+}
+
+
+/**************************************************************************
+* 			wodGetDevCaps               [internal]
+*/
+static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
+{
+    TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
+    
+    if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        TRACE("MAX_WAVOUTDRV reached !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    TRACE("dwSupport=(0x%lx), dwFormats=(0x%lx)\n", WOutDev[wDevID].caps.dwSupport, WOutDev[wDevID].caps.dwFormats);
+    memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodOpen				[internal]
+*
+* NOTE: doesn't it seem like there is a race condition if you try to open 
+* the same device twice?
+*/
+static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
+{
+    WINE_WAVEOUT*	wwo;
+    DWORD retval;
+    DWORD               ret;
+    int			audio_fragment;
+    
+    TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
+    if (lpDesc == NULL)
+    {
+        WARN("Invalid Parameter !\n");
+        return MMSYSERR_INVALPARAM;
+    }
+    if (wDevID >= MAX_WAVEOUTDRV) {
+        TRACE("MAX_WAVOUTDRV reached !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    TRACE("Format: tag=%04X nChannels=%d nSamplesPerSec=%ld wBitsPerSample=%d !\n",
+          lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
+          lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
+    
+    if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
+        lpDesc->lpFormat->nChannels == 0 ||
+        lpDesc->lpFormat->nSamplesPerSec == 0
+         )
+    {
+        WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld wBitsPerSample=%d !\n",
+             lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
+             lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
+        return WAVERR_BADFORMAT;
+    }
+    
+    if (dwFlags & WAVE_FORMAT_QUERY)
+    {
+        TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
+              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
+              lpDesc->lpFormat->nSamplesPerSec);
+        return MMSYSERR_NOERROR;
+    }
+    
+    wwo = &WOutDev[wDevID];
+    if (!AudioUnit_CreateDefaultAudioUnit((void *) wwo, &wwo->audioUnit))
+    {
+        ERR("CoreAudio_CreateDefaultAudioUnit(%p) failed\n", wwo);
+        return MMSYSERR_ERROR;
+    }
+
+    if ((dwFlags & WAVE_DIRECTSOUND) && 
+        !(wwo->caps.dwSupport & WAVECAPS_DIRECTSOUND))
+	/* not supported, ignore it */
+	dwFlags &= ~WAVE_DIRECTSOUND;
+
+    if (wwo->state != WINE_WS_CLOSED) return MMSYSERR_ALLOCATED;
+    
+    pthread_mutex_init(&wwo->lock, NULL); /* initialize the mutex */
+    pthread_mutex_lock(&wwo->lock);
+    
+    AudioStreamBasicDescription streamFormat;
+    
+    streamFormat.mFormatID = kAudioFormatLinearPCM;
+    
+    /* FIXME check for 32bits float -> kLinearPCMFormatFlagIsFloat */
+    streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger
+# ifdef __powerpc__
+            | kLinearPCMFormatFlagIsBigEndian /* FIXME Wave format is little endian */
+# endif
+            | kLinearPCMFormatFlagIsPacked;
+
+    streamFormat.mSampleRate = lpDesc->lpFormat->nSamplesPerSec;
+    streamFormat.mChannelsPerFrame = lpDesc->lpFormat->nChannels;	
+    streamFormat.mFramesPerPacket = 1;	
+    streamFormat.mBitsPerChannel = lpDesc->lpFormat->wBitsPerSample;
+    streamFormat.mBytesPerFrame = streamFormat.mBitsPerChannel * streamFormat.mChannelsPerFrame / 8;	
+    streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket;		
+    
+    ret = AudioUnit_InitializeWithStreamDescription(wwo->audioUnit, streamFormat);
+    if (!ret) 
+    {
+        pthread_mutex_unlock(&wwo->lock);
+        return WAVERR_BADFORMAT; /* FIXME return an error based on the OSStatus */
+    }
+    wwo->streamDescription = streamFormat;
+    wwo->state = WINE_WS_STOPPED;
+        
+    pthread_mutex_unlock(&wwo->lock);
+                
+    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
+    
+    memcpy(&wwo->waveDesc, lpDesc, 	     sizeof(WAVEOPENDESC));
+    memcpy(&wwo->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
+    
+    if (wwo->format.wBitsPerSample == 0) {
+	WARN("Resetting zeroed wBitsPerSample\n");
+	wwo->format.wBitsPerSample = 8 *
+	    (wwo->format.wf.nAvgBytesPerSec /
+	     wwo->format.wf.nSamplesPerSec) /
+	    wwo->format.wf.nChannels;
+    }
+    
+    wwo->dwPlayedTotal = 0;
+    wwo->dwWrittenTotal = 0;
+    
+    retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
+    
+    return retval;
+}
+
+/**************************************************************************
+* 				wodClose			[internal]
+*/
+static DWORD wodClose(WORD wDevID)
+{
+    DWORD		ret = MMSYSERR_NOERROR;
+    WINE_WAVEOUT*	wwo;
+    
+    TRACE("(%u);\n", wDevID);
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    wwo = &WOutDev[wDevID];
+    if (wwo->lpQueuePtr)
+    {
+        WARN("buffers still playing !\n");
+        ret = WAVERR_STILLPLAYING;
+    } else
+    {
+        OSStatus err;
+        /* sanity check: this should not happen since the device must have been reset before */
+        if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
+        
+        wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
+        
+        err = AudioUnitUninitialize(wwo->audioUnit);
+        if (err) {
+            ERR("AudioUnitUninitialize return %c%c%c%c\n", (char) (err >> 24),
+                                                            (char) (err >> 16),
+                                                            (char) (err >> 8),
+                                                            (char) err);
+            pthread_mutex_destroy(&wwo->lock);
+            return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+        }
+        
+        if ( !AudioUnit_CloseAudioUnit(wwo->audioUnit) )
+        {
+            ERR("Can't close AudioUnit\n");
+            pthread_mutex_destroy(&wwo->lock);
+            return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+        }  
+        pthread_mutex_destroy(&wwo->lock);
+        
+        ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
+    }
+    
+    return ret;
+}
+
+/**************************************************************************
+* 				wodPrepare			[internal]
+*/
+static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
+{
+    OSStatus status;
+
+    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
+    
+    if (wDevID >= MAX_WAVEOUTDRV) {
+	WARN("bad device ID !\n");
+	return MMSYSERR_BADDEVICEID;
+    }
+    
+    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
+	return WAVERR_STILLPLAYING;
+    
+    lpWaveHdr->dwFlags |= WHDR_PREPARED;
+    lpWaveHdr->dwFlags &= ~WHDR_DONE;
+  
+    WOutDev[wDevID].state = WINE_WS_STOPPED;
+    
+    status = AudioOutputUnitStart(WOutDev[wDevID].audioUnit);
+    if (status) {
+        ERR("AudioOutputUnitStart return %c%c%c%c\n", (char) (status >> 24),
+                                                        (char) (status >> 16),
+                                                        (char) (status >> 8),
+                                                        (char) status);
+        return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+    }
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodUnprepare			[internal]
+*/
+static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
+{
+    OSStatus status;
+
+    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
+    
+    if (wDevID >= MAX_WAVEOUTDRV) {
+	WARN("bad device ID !\n");
+	return MMSYSERR_BADDEVICEID;
+    }
+    
+    if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
+	return WAVERR_STILLPLAYING;
+    
+    lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
+    lpWaveHdr->dwFlags |= WHDR_DONE;
+   
+    status = AudioOutputUnitStop(WOutDev[wDevID].audioUnit);
+    if (status) {
+        fprintf(stderr, "err:winecoreaudio:wodUnprepare AudioOutputUnitStop return %c%c%c%c\n", (char) (status >> 24),
+                                                                                                (char) (status >> 16),
+                                                                                                (char) (status >> 8),
+                                                                                                (char) status);
+        return MMSYSERR_ERROR; /* FIXME return an error based on the OSStatus */
+    }
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodHelper_BeginWaveHdr          [internal]
+*
+* Makes the specified lpWaveHdr the currently playing wave header.
+* If the specified wave header is a begin loop and we're not already in
+* a loop, setup the loop.
+*/
+static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
+{
+    /* Call from AudioUnit IO thread can't use Wine debug channels */
+    fprintf(stderr, "trace:winecoreaudio:wodHelper_BeginWaveHdr\n");  
+
+    wwo->lpPlayPtr = lpWaveHdr;
+    
+    if (!lpWaveHdr)
+    {
+        return;
+    }
+    
+    if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
+    {
+        if (wwo->lpLoopPtr)
+        {
+            fprintf(stderr, "trace:winecoreaudio:wodHelper_BeginWaveHdr Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
+        } else
+        {
+            fprintf(stderr, "trace:winecoreaudio:wodHelper_BeginWaveHdr Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
+
+            wwo->lpLoopPtr = lpWaveHdr;
+            /* Windows does not touch WAVEHDR.dwLoops,
+                * so we need to make an internal copy */
+            wwo->dwLoops = lpWaveHdr->dwLoops;
+        }
+    }
+    wwo->dwPartialOffset = 0;
+}
+
+
+/**************************************************************************
+* 				wodHelper_PlayPtrNext	        [internal]
+*
+* Advance the play pointer to the next waveheader, looping if required.
+*/
+static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
+{
+    LPWAVEHDR lpWaveHdr;
+    /* Call from AudioUnit IO thread can't use Wine debug channels */
+    fprintf(stderr, "trace:winecoreaudio:wodHelper_PlayPtrNext\n");
+
+    pthread_mutex_lock(&wwo->lock);
+    
+    lpWaveHdr = wwo->lpPlayPtr;
+    
+    wwo->dwPartialOffset = 0;
+    if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
+    {
+        /* We're at the end of a loop, loop if required */
+        if (--wwo->dwLoops > 0)
+        {
+            wwo->lpPlayPtr = wwo->lpLoopPtr;
+        } else
+        {
+            /* Handle overlapping loops correctly */
+            if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
+                fprintf(stderr, "trace:winecoreaudio:wodHelper_PlayPtrNext Correctly handled case ? (ending loop buffer also starts a new loop)\n");
+                /* shall we consider the END flag for the closing loop or for
+                * the opening one or for both ???
+                * code assumes for closing loop only
+                */
+            } else
+            {
+                lpWaveHdr = lpWaveHdr->lpNext;
+            }
+            wwo->lpLoopPtr = NULL;
+            wodHelper_BeginWaveHdr(wwo, lpWaveHdr);
+        }
+    } else
+    {
+        /* We're not in a loop.  Advance to the next wave header */
+        fprintf(stderr, "trace:winecoreaudio:wodHelper_PlayPtrNext not inside of a loop, advancing to next wave header\n");
+
+        wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
+    }
+    
+    pthread_mutex_unlock(&wwo->lock);
+    
+    return lpWaveHdr;
+}
+
+/* if force is TRUE then notify the client that all the headers were completed */
+static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
+{
+    LPWAVEHDR		lpWaveHdr;
+    DWORD retval;
+
+    pthread_mutex_lock(&wwo->lock);
+
+    /* Start from lpQueuePtr and keep notifying until:
+        * - we hit an unwritten wavehdr
+        * - we hit the beginning of a running loop
+        * - we hit a wavehdr which hasn't finished playing
+        */
+    while ((lpWaveHdr = wwo->lpQueuePtr) &&
+           (force || 
+            (lpWaveHdr != wwo->lpPlayPtr &&
+             lpWaveHdr != wwo->lpLoopPtr)))
+    {
+        wwo->lpQueuePtr = lpWaveHdr->lpNext;
+        
+        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
+        lpWaveHdr->dwFlags |= WHDR_DONE;
+        
+        /* Call from AudioUnit IO thread can't use Wine debug channels */
+        fprintf(stderr, "trace:winecoreaudio:wodHelper_NotifyCompletions notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) dwFlags=(%ld)\n",
+              lpWaveHdr, wwo->lpPlayPtr, lpWaveHdr->dwFlags);
+        
+        wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
+    }
+    fprintf(stderr, "trace:winecoreaudio:wodHelper_NotifyCompletions Not notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) lpLoopPtr=(%p)\n",
+          lpWaveHdr, wwo->lpPlayPtr, wwo->lpLoopPtr);
+
+    retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != 
+              wwo->lpLoopPtr) ? 0 : INFINITE;
+    
+    pthread_mutex_unlock(&wwo->lock);
+    
+    return retval;
+}
+
+/**************************************************************************
+* 				wodHelper_Reset			[internal]
+*
+* Resets current output stream.
+*/
+static  void  wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset)
+{
+    FIXME("\n");
+   
+    /* updates current notify list */
+    wodHelper_NotifyCompletions(wwo, FALSE);
+    
+    if (reset)
+    {
+        /* remove all wave headers and notify client that all headers were completed */
+        wodHelper_NotifyCompletions(wwo, TRUE);
+
+        pthread_mutex_lock(&wwo->lock);
+        
+        wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
+        wwo->state = WINE_WS_STOPPED;
+        wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
+        
+        wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */
+        
+        pthread_mutex_unlock(&wwo->lock);
+    } 
+    else
+    {
+        pthread_mutex_lock(&wwo->lock);
+        if (wwo->lpLoopPtr)
+        {
+            /* complicated case, not handled yet (could imply modifying the loop counter) */
+            FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
+            wwo->lpPlayPtr = wwo->lpLoopPtr;
+            wwo->dwPartialOffset = 0;
+            wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
+        } else
+        {
+            LPWAVEHDR   ptr;
+            DWORD       sz = wwo->dwPartialOffset;
+            
+            /* reset all the data as if we had written only up to lpPlayedTotal bytes */
+            /* compute the max size playable from lpQueuePtr */
+            for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)
+            {
+                sz += ptr->dwBufferLength;
+            }
+            
+            /* because the reset lpPlayPtr will be lpQueuePtr */
+            if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");
+            wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
+            wwo->dwWrittenTotal = wwo->dwPlayedTotal;
+            wwo->lpPlayPtr = wwo->lpQueuePtr;
+        }
+        
+        wwo->state = WINE_WS_PAUSED;
+        pthread_mutex_unlock(&wwo->lock);
+    }
+}
+
+
+/**************************************************************************
+* 				wodWrite			[internal]
+* 
+*/
+static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
+{
+    LPWAVEHDR*wh;
+    WINE_WAVEOUT *wwo;
+    
+    TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
+    
+    /* first, do the sanity checks... */
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad dev ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    wwo = &WOutDev[wDevID];
+    
+    if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
+    {
+        TRACE("unprepared\n");
+        return WAVERR_UNPREPARED;
+    }
+    
+    if (lpWaveHdr->dwFlags & WHDR_INQUEUE) 
+    {
+        TRACE("still playing\n");
+        return WAVERR_STILLPLAYING;
+    }
+    
+    lpWaveHdr->dwFlags &= ~WHDR_DONE;
+    lpWaveHdr->dwFlags |= WHDR_INQUEUE;
+    lpWaveHdr->lpNext = 0;
+
+    pthread_mutex_lock(&wwo->lock);
+    /* insert buffer at the end of queue */
+    for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
+    *wh = lpWaveHdr;
+    
+    if (!wwo->lpPlayPtr)
+        wodHelper_BeginWaveHdr(wwo,lpWaveHdr);
+    if (wwo->state == WINE_WS_STOPPED)
+        wwo->state = WINE_WS_PLAYING;
+    pthread_mutex_unlock(&wwo->lock);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 			wodPause				[internal]
+*/
+static DWORD wodPause(WORD wDevID)
+{
+    TRACE("(%u);!\n", wDevID);
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    if (WOutDev[wDevID].state == WINE_WS_PLAYING)
+    {
+        pthread_mutex_lock(&WOutDev[wDevID].lock);
+        WOutDev[wDevID].state = WINE_WS_PAUSED;
+        pthread_mutex_unlock(&WOutDev[wDevID].lock);
+    }
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 			wodRestart				[internal]
+*/
+static DWORD wodRestart(WORD wDevID)
+{
+    TRACE("(%u);\n", wDevID);
+    
+    if (wDevID >= MAX_WAVEOUTDRV )
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    if (WOutDev[wDevID].state == WINE_WS_PAUSED)
+    {
+        pthread_mutex_lock(&WOutDev[wDevID].lock);
+        WOutDev[wDevID].state = WINE_WS_PLAYING;
+        pthread_mutex_unlock(&WOutDev[wDevID].lock);
+    }
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 			wodReset				[internal]
+*/
+static DWORD wodReset(WORD wDevID)
+{
+    TRACE("(%u);\n", wDevID);
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    wodHelper_Reset(&WOutDev[wDevID], TRUE);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodGetPosition			[internal]
+*/
+static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
+{
+    DWORD		val;
+    WINE_WAVEOUT*	wwo;
+    DWORD elapsedMS;
+    
+    TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    
+    /* if null pointer to time structure return error */
+    if (lpTime == NULL)	return MMSYSERR_INVALPARAM;
+    
+    wwo = &WOutDev[wDevID];
+    
+    pthread_mutex_lock(&WOutDev[wDevID].lock);
+    val = wwo->dwPlayedTotal;
+    pthread_mutex_unlock(&WOutDev[wDevID].lock);
+    
+    return bytes_to_mmtime(lpTime, val, &wwo->format);
+}
+
+/**************************************************************************
+* 				wodBreakLoop			[internal]
+*/
+static DWORD wodBreakLoop(WORD wDevID)
+{
+    FIXME("(%u);\n", wDevID);
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+    pthread_mutex_lock(&WOutDev[wDevID].lock);
+    
+    if (WOutDev[wDevID].state == WINE_WS_PLAYING && WOutDev[wDevID].lpLoopPtr != NULL)
+    {
+        /* ensure exit at end of current loop */
+        WOutDev[wDevID].dwLoops = 1;
+    }
+    
+    pthread_mutex_unlock(&WOutDev[wDevID].lock);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodGetVolume			[internal]
+*/
+static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
+{
+    float left;
+    float right;
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }    
+    
+    TRACE("(%u, %08lX);\n", wDevID, lpdwVol);
+    
+    pthread_mutex_lock(&WOutDev[wDevID].lock);
+    
+    AudioUnit_GetVolume(WOutDev[wDevID].audioUnit, &left, &right); 
+        
+    pthread_mutex_unlock(&WOutDev[wDevID].lock);
+        
+    *lpdwVol = ((WORD) left * 0xFFFFl) + (((WORD) right * 0xFFFFl) << 16);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodSetVolume			[internal]
+*/
+static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
+{
+    float left;
+    float right;
+    
+    if (wDevID >= MAX_WAVEOUTDRV)
+    {
+        WARN("bad device ID !\n");
+        return MMSYSERR_BADDEVICEID;
+    }
+
+    left  = LOWORD(dwParam) / 65535.0f;
+    right = HIWORD(dwParam) / 65535.0f;
+    
+    TRACE("(%u, %08lX);\n", wDevID, dwParam);
+    
+    pthread_mutex_lock(&WOutDev[wDevID].lock);
+    
+    AudioUnit_SetVolume(WOutDev[wDevID].audioUnit, left, right); 
+        
+    pthread_mutex_unlock(&WOutDev[wDevID].lock);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+* 				wodGetNumDevs			[internal]
+*/
+static DWORD wodGetNumDevs(void)
+{
+    TRACE("\n");
+    return MAX_WAVEOUTDRV;
+}
+
+/**************************************************************************
+*                              wodDevInterfaceSize             [internal]
+*/
+static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
+{
+    TRACE("(%u, %p)\n", wDevID, dwParam1);
+    
+    *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
+                                    NULL, 0 ) * sizeof(WCHAR);
+    return MMSYSERR_NOERROR;
+}
+
+/**************************************************************************
+*                              wodDevInterface                 [internal]
+*/
+static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
+{
+    TRACE("\n");
+    if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
+                                        NULL, 0 ) * sizeof(WCHAR))
+    {
+        MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].cadev->interface_name, -1,
+                            dwParam1, dwParam2 / sizeof(WCHAR));
+        return MMSYSERR_NOERROR;
+    }
+    return MMSYSERR_INVALPARAM;
+}
+
+/**************************************************************************
+* 				wodMessage (WINEJACK.7)
+*/
+DWORD WINAPI CoreAudio_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
+                                  DWORD dwParam1, DWORD dwParam2)
+{
+    TRACE("(%u, %s, %08lX, %08lX, %08lX);\n",
+          wDevID, getMessage(wMsg), dwUser, dwParam1, dwParam2);
+    
+    switch (wMsg) {
+        case DRVM_INIT:
+        case DRVM_EXIT:
+        case DRVM_ENABLE:
+        case DRVM_DISABLE:
+            
+            // FIXME: Pretend this is supported //
+            return 0;
+        case WODM_OPEN:         return wodOpen(wDevID, (LPWAVEOPENDESC) dwParam1, dwParam2);          
+        case WODM_CLOSE:        return wodClose(wDevID);
+        case WODM_WRITE:        return wodWrite(wDevID, (LPWAVEHDR) dwParam1, dwParam2);
+        case WODM_PAUSE:        return wodPause(wDevID);  
+        case WODM_GETPOS:       return wodGetPosition(wDevID, (LPMMTIME) dwParam1, dwParam2);
+        case WODM_BREAKLOOP:    return MMSYSERR_NOTSUPPORTED;
+        case WODM_PREPARE:      return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
+        case WODM_UNPREPARE:    return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
+            
+        case WODM_GETDEVCAPS:   return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSW) dwParam1, dwParam2);
+        case WODM_GETNUMDEVS:   return wodGetNumDevs();  
+            
+        case WODM_GETPITCH:         
+        case WODM_SETPITCH:        
+        case WODM_GETPLAYBACKRATE:	
+        case WODM_SETPLAYBACKRATE:	return MMSYSERR_NOTSUPPORTED;
+        case WODM_GETVOLUME:    return wodGetVolume(wDevID, (LPDWORD)dwParam1);
+        case WODM_SETVOLUME:    return wodSetVolume(wDevID, dwParam1);
+        case WODM_RESTART:      return wodRestart(wDevID);
+        case WODM_RESET:    	return wodReset(wDevID);
+            
+        case DRV_QUERYDEVICEINTERFACESIZE:  return wodDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
+        case DRV_QUERYDEVICEINTERFACE:      return wodDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
+        case DRV_QUERYDSOUNDIFACE:	
+        case DRV_QUERYDSOUNDDESC:	
+            return MMSYSERR_NOTSUPPORTED;
+            
+        default:
+            FIXME("unknown message %d!\n", wMsg);
+    }
+    
+    return MMSYSERR_NOTSUPPORTED;
+}
+
+/*======================================================================*
+*                  Low level DSOUND implementation			*
+*======================================================================*/
+
+typedef struct IDsDriverImpl IDsDriverImpl;
+typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
+
+struct IDsDriverImpl
+{
+    /* IUnknown fields */
+    const IDsDriverVtbl *lpVtbl;
+    DWORD		ref;
+    /* IDsDriverImpl fields */
+    UINT		wDevID;
+    IDsDriverBufferImpl*primary;
+};
+
+struct IDsDriverBufferImpl
+{
+    /* IUnknown fields */
+    const IDsDriverBufferVtbl *lpVtbl;
+    DWORD ref;
+    /* IDsDriverBufferImpl fields */
+    IDsDriverImpl* drv;
+    DWORD buflen;
+};
+
+static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
+{
+    /* we can't perform memory mapping as we don't have a file stream 
+    interface with jack like we do with oss */
+    MESSAGE("This sound card's driver does not support direct access\n");
+    MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
+    return MMSYSERR_NOTSUPPORTED;
+}
+
+static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
+{
+    memset(desc, 0, sizeof(*desc));
+    strcpy(desc->szDesc, "Wine CoreAudio DirectSound Driver");
+    strcpy(desc->szDrvname, "winecoreaudio.drv");
+    return MMSYSERR_NOERROR;
+}
+
+
+/*
+    CoreAudio IO threaded callback,
+    we can't call Wine debug channels, critical section or anything using NtCurrentTeb here.
+*/
+OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
+                                     AudioUnitRenderActionFlags *ioActionFlags, 
+                                     const AudioTimeStamp *inTimeStamp, 
+                                     UInt32 inBusNumber, 
+                                     UInt32 inNumberFrames, 
+                                     AudioBufferList *ioData)
+{
+    UInt32 channel;
+    WINE_WAVEOUT *wwo = (WINE_WAVEOUT *) inRefCon;
+    int nextPtr = 0;
+    int needNotify = 0;
+    
+    pthread_mutex_lock(&wwo->lock);
+    if(wwo->state == WINE_WS_PLAYING)
+    {
+        unsigned int available;
+        unsigned int count = ioData->mBuffers[0].mDataByteSize;
+        
+        available = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
+        
+        for (channel = 0; channel < ioData->mNumberBuffers; channel++)
+        {
+            if ( available >= count)
+            { 
+                memcpy(ioData->mBuffers[channel].mData, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, count);
+                wwo->dwPartialOffset += count;
+                wwo->dwPlayedTotal += count;
+            }
+            else
+            {
+                int s;
+                memcpy(ioData->mBuffers[channel].mData, wwo->lpPlayPtr->lpData + wwo->dwPartialOffset, available);
+                wwo->dwPartialOffset += available;
+                wwo->dwPlayedTotal += available;
+                
+                /* Fill with silence */
+                for (s = available; s < count; s++)
+                    ((int *)ioData->mBuffers[channel].mData)[s] = 0;
+                
+                nextPtr = 1;
+            }
+        }
+        needNotify = 1;
+    }
+    else
+    {
+        for (channel = 0; channel < ioData->mNumberBuffers; channel++)
+            memset(ioData->mBuffers[channel].mData, 0, ioData->mBuffers[channel].mDataByteSize);
+    }
+    pthread_mutex_unlock(&wwo->lock);
+
+    if (nextPtr) wodHelper_PlayPtrNext(wwo); 
+    if (needNotify) wodHelper_NotifyCompletions(wwo, FALSE);
+    return noErr;
+}
+#else
+
+/**************************************************************************
+* 				wodMessage (WINECOREAUDIO.7)
+*/
+DWORD WINAPI CoreAudio_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
+                                  DWORD dwParam1, DWORD dwParam2)
+{
+    FIXME("(%u, %04X, %08lX, %08lX, %08lX): CoreAudio support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
+    return MMSYSERR_NOTENABLED;
+}
+
+#endif
--- /dev/null	2006-05-25 21:19:13.000000000 +0200
+++ dlls/winmm/winecoreaudio/audiounit.c	2006-05-22 20:23:51.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * Wine Driver for CoreAudio / AudioUnit
+ *
+ * Copyright 2005, 2006 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#ifdef HAVE_AUDIOUNIT_AUDIOUNIT_H
+#include <AudioUnit/AudioUnit.h>
+
+static char streamStr[512] = {0};
+static char *streamDescription(AudioStreamBasicDescription stream)
+{
+    sprintf(streamStr, "\n mSampleRate : %f\n mFormatID : %c%c%c%c\n mFormatFlags : %lX\n mBytesPerPacket : %u\n mFramesPerPacket : %u\n mBytesPerFrame : %u\n mChannelsPerFrame : %u\n mBitsPerChannel : %u\n",
+        stream.mSampleRate,  
+        (char) (stream.mFormatID >> 24),
+        (char) (stream.mFormatID >> 16),
+        (char) (stream.mFormatID >> 8),
+        (char) stream.mFormatID,
+        stream.mFormatFlags, 
+        stream.mBytesPerPacket, 
+        stream.mFramesPerPacket, 
+        stream.mBytesPerFrame, 
+        stream.mChannelsPerFrame, 
+        stream.mBitsPerChannel);
+    return streamStr;
+}
+
+extern OSStatus CoreAudio_woAudioUnitIOProc(void *inRefCon, 
+				AudioUnitRenderActionFlags *ioActionFlags, 
+				const AudioTimeStamp *inTimeStamp, 
+				UInt32 inBusNumber, 
+				UInt32 inNumberFrames, 
+				AudioBufferList *ioData);
+
+int AudioUnit_CreateDefaultAudioUnit(void *wwo, AudioUnit *au)
+{
+    OSStatus err;
+    ComponentDescription desc;
+    AURenderCallbackStruct callbackStruct;
+
+    fprintf (stderr, "%s\n", __FUNCTION__);
+    
+    desc.componentType = kAudioUnitType_Output;
+    desc.componentSubType = kAudioUnitSubType_DefaultOutput;
+    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+    desc.componentFlags = 0;
+    desc.componentFlagsMask = 0;
+       
+    Component comp = FindNextComponent(NULL, &desc);
+    if (comp == NULL)
+        return 0;
+    
+    err = OpenAComponent(comp, au);
+    if (comp == NULL)
+        return 0;
+        
+    callbackStruct.inputProc = CoreAudio_woAudioUnitIOProc;
+    callbackStruct.inputProcRefCon = wwo;
+
+    err = AudioUnitSetProperty( *au, 
+                                kAudioUnitProperty_SetRenderCallback, 
+                                kAudioUnitScope_Input,
+                                0, 
+                                &callbackStruct, 
+                                sizeof(callbackStruct));
+    return (err == noErr);
+}
+
+int AudioUnit_CloseAudioUnit(AudioUnit au)
+{
+    OSStatus err = CloseComponent(au);
+    return (err == noErr);
+}
+
+int AudioUnit_InitializeWithStreamDescription(AudioUnit au, AudioStreamBasicDescription stream)
+{
+    OSStatus err = noErr;
+    
+    fprintf (stderr, "%s %s\n", __FUNCTION__, streamDescription(stream));
+    
+    err = AudioUnitSetProperty(au, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
+                                0, &stream, sizeof(AudioStreamBasicDescription));
+                                
+    if (err != noErr)
+    {
+        fprintf (stderr, "%s AudioUnitSetProperty return an error %c%c%c%c\n", __FUNCTION__, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+        return 0;
+    }
+    
+    err = AudioUnitInitialize(au);
+    if (err != noErr)
+    {
+        fprintf (stderr, "%s AudioUnitInitialize return an error %c%c%c%c\n", __FUNCTION__, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+        return 0;
+    }
+    return 1;
+}
+
+int AudioUnit_SetVolume(AudioUnit au, float left, float right)
+{
+    OSStatus err = noErr;
+    fprintf (stderr, "fixme:winecoreaudio:%s (%f, %f)\n", __FUNCTION__, left, right);
+   
+    err = AudioUnitSetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0);
+                                
+    if (err != noErr)
+    {
+        fprintf (stderr, "%s AudioUnitSetParameter return an error %c%c%c%c\n", __FUNCTION__, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+        return 0;
+    }
+    return 1;
+}
+
+int AudioUnit_GetVolume(AudioUnit au, float *left, float *right)
+{
+    OSStatus err = noErr;
+    fprintf (stderr, "fixme:winecoreaudio:%s\n", __FUNCTION__);
+    
+    err = AudioUnitGetParameter(au, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left);
+    if (err != noErr)
+    {
+        fprintf (stderr, "%s AudioUnitGetParameter return an error %c%c%c%c\n", __FUNCTION__, (char) (err >> 24), (char) (err >> 16), (char) (err >> 8), (char) err);
+        return 0;
+    }
+    *right = *left;
+    return 1;
+}
+#endif
--- /dev/null	2006-05-25 21:19:43.000000000 +0200
+++ dlls/winmm/winecoreaudio/coreaudio.h	2006-03-09 23:00:16.000000000 +0100
@@ -0,0 +1,28 @@
+/* Definition for CoreAudio drivers : wine multimedia system
+ *
+ * Copyright 2005 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __WINE_COREAUDIO_H
+#define __WINE_COREAUDIO_H
+
+extern LONG CoreAudio_WaveInit(void);
+extern void CoreAudio_WaveRelease(void);
+
+/* extern BOOL CoreAudio_MidiInit(void); */
+
+#endif /* __WINE_COREAUDIO_H */
\ No newline at end of file
--- /dev/null	2006-05-25 21:19:43.000000000 +0200
+++ dlls/winmm/winecoreaudio/coreaudio.c	2006-03-09 22:59:57.000000000 +0100
@@ -0,0 +1,114 @@
+/*
+ * Wine Driver for CoreAudio
+ *
+ * Copyright 2005 Emmanuel Maillard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmddk.h"
+#include "coreaudio.h"
+#include "wine/library.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
+
+#ifdef HAVE_COREAUDIO_COREAUDIO_H
+
+/**************************************************************************
+ * 				CoreAudio_drvLoad       [internal]	
+ */
+static LRESULT CoreAudio_drvLoad(void)
+{
+    TRACE("()\n");
+    CoreAudio_WaveInit();
+    return 1;
+}
+
+/**************************************************************************
+ * 				CoreAudio_drvFree       [internal]	
+ */
+static LRESULT CoreAudio_drvFree(void)
+{
+    TRACE("()\n");
+    CoreAudio_WaveRelease();
+    return 1;
+}
+
+/**************************************************************************
+ * 				CoreAudio_drvOpen       [internal]
+ */
+static LRESULT CoreAudio_drvOpen(LPSTR str)
+{
+    TRACE("(%s)\n", str);
+    return 1;
+}
+
+/**************************************************************************
+ * 				CoreAudio_drvClose      [internal]
+ */
+static DWORD CoreAudio_drvClose(DWORD dwDevID)
+{
+    TRACE("(%08lx)\n", dwDevID);
+    return 1;
+}
+#endif /* HAVE_COREAUDIO_COREAUDIO_H */
+
+/**************************************************************************
+ * 				DriverProc (WINECOREAUDIO.1)
+ */
+LRESULT CALLBACK CoreAudio_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, 
+                                 LPARAM dwParam1, LPARAM dwParam2)
+{
+     TRACE("(%08lX, %p, %s (%08X), %08lX, %08lX)\n",
+           dwDevID, hDriv, wMsg == DRV_LOAD ? "DRV_LOAD" :
+           wMsg == DRV_FREE ? "DRV_FREE" :
+           wMsg == DRV_OPEN ? "DRV_OPEN" :
+           wMsg == DRV_CLOSE ? "DRV_CLOSE" :
+           wMsg == DRV_ENABLE ? "DRV_ENABLE" :
+           wMsg == DRV_DISABLE ? "DRV_DISABLE" :
+           wMsg == DRV_QUERYCONFIGURE ? "DRV_QUERYCONFIGURE" :
+           wMsg == DRV_CONFIGURE ? "DRV_CONFIGURE" :
+           wMsg == DRV_INSTALL ? "DRV_INSTALL" :
+           wMsg == DRV_REMOVE ? "DRV_REMOVE" : "UNKNOWN", 
+           wMsg, dwParam1, dwParam2);
+    
+    switch(wMsg) {
+#ifdef HAVE_COREAUDIO_COREAUDIO_H
+    case DRV_LOAD:		return CoreAudio_drvLoad();
+    case DRV_FREE:		return CoreAudio_drvFree();
+    case DRV_OPEN:		return CoreAudio_drvOpen((LPSTR)dwParam1);
+    case DRV_CLOSE:		return CoreAudio_drvClose(dwDevID);
+    case DRV_ENABLE:		return 1;
+    case DRV_DISABLE:		return 1;
+    case DRV_QUERYCONFIGURE:	return 1;
+    case DRV_CONFIGURE:		MessageBoxA(0, "CoreAudio driver!", "CoreAudio driver", MB_OK); return 1;
+    case DRV_INSTALL:		return DRVCNF_RESTART;
+    case DRV_REMOVE:		return DRVCNF_RESTART;
+#endif
+    default:
+	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+    }
+}
+
--- /dev/null	2006-05-25 21:19:43.000000000 +0200
+++ dlls/winmm/winecoreaudio/winecoreaudio.drv.spec	2005-12-28 02:42:58.000000000 +0100
@@ -0,0 +1,2 @@
+@ stdcall -private DriverProc(long long long long long) CoreAudio_DriverProc
+@ stdcall -private wodMessage(long long long long long) CoreAudio_wodMessage
--- /dev/null	2006-05-25 21:19:43.000000000 +0200
+++ dlls/winmm/winecoreaudio/Makefile.in	2006-05-22 23:54:15.000000000 +0200
@@ -0,0 +1,16 @@
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = winecoreaudio.drv
+IMPORTS   = winmm user32 kernel32
+EXTRALIBS = $(LIBUUID) @COREAUDIO@
+
+C_SRCS = \
+	audio.c \
+	audiounit.c \
+	coreaudio.c
+
+@MAKE_DLL_RULES@
+
+### Dependencies:
