ole32: Return an error in CoMarshalInterface if pStream is NULL.
[wine] / dlls / winmm / winearts / audio.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Wine Driver for aRts Sound Server
4  *   http://www.arts-project.org
5  *
6  * Copyright 1994 Martin Ayotte
7  *           1999 Eric Pouech (async playing in waveOut/waveIn)
8  *           2000 Eric Pouech (loops in waveOut)
9  *           2002 Chris Morgan (aRts version of this file)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 /* NOTE:
26  *    with arts we cannot stop the audio that is already in
27  *    the servers buffer, so to reduce delays during starting
28  *    and stoppping of audio streams adjust the
29  *    audio buffer size in the kde control center or in the
30  *    artsd startup script
31  *
32  * FIXME:
33  *      pause in waveOut does not work correctly in loop mode
34  *
35  *      does something need to be done in for WaveIn DirectSound?
36  */
37
38 #include "config.h"
39 #include "wine/port.h"
40
41 #include <math.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <string.h>
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49 #include <fcntl.h>
50 #include "windef.h"
51 #include "winbase.h"
52 #include "wingdi.h"
53 #include "winerror.h"
54 #include "winuser.h"
55 #include "mmddk.h"
56 #include "dsound.h"
57 #include "dsdriver.h"
58 #include "arts.h"
59 #include "wine/unicode.h"
60 #include "wine/exception.h"
61 #include "wine/debug.h"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(wave);
64
65 #ifdef HAVE_ARTS
66
67 #include <artsc.h>
68
69 /* The following four #defines allow you to fine-tune the packet
70  * settings in arts for better low-latency support. You must also
71  * adjust the latency in the KDE arts control panel. I recommend 4
72  * fragments, 1024 bytes.
73  *
74  * The following is from the ARTS documentation and explains what CCCC
75  * and SSSS mean:
76  * 
77  * @li ARTS_P_PACKET_SETTINGS (rw) This is a way to configure packet
78  * size & packet count at the same time.  The format is 0xCCCCSSSS,
79  * where 2^SSSS is the packet size, and CCCC is the packet count. Note
80  * that when writing this, you don't necessarily get the settings you
81  * requested.
82  */
83 #define WAVEOUT_PACKET_CCCC 0x000C
84 #define WAVEOUT_PACKET_SSSS 0x0008
85 #define WAVEIN_PACKET_CCCC  0x000C
86 #define WAVEIN_PACKET_SSSS  0x0008
87
88 #define BUFFER_REFILL_THRESHOLD 4
89
90 #define WAVEOUT_PACKET_SETTINGS ((WAVEOUT_PACKET_CCCC << 16) | (WAVEOUT_PACKET_SSSS))
91 #define WAVEIN_PACKET_SETTINGS  ((WAVEIN_PACKET_CCCC << 16) | (WAVEIN_PACKET_SSSS))
92
93 #define MAX_WAVEOUTDRV  (10)
94 #define MAX_WAVEINDRV   (10)
95
96 /* state diagram for waveOut writing:
97  *
98  * +---------+-------------+---------------+---------------------------------+
99  * |  state  |  function   |     event     |            new state            |
100  * +---------+-------------+---------------+---------------------------------+
101  * |         | open()      |               | STOPPED                         |
102  * | PAUSED  | write()     |               | PAUSED                          |
103  * | STOPPED | write()     | <thrd create> | PLAYING                         |
104  * | PLAYING | write()     | HEADER        | PLAYING                         |
105  * | (other) | write()     | <error>       |                                 |
106  * | (any)   | pause()     | PAUSING       | PAUSED                          |
107  * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
108  * | (any)   | reset()     | RESETTING     | STOPPED                         |
109  * | (any)   | close()     | CLOSING       | CLOSED                          |
110  * +---------+-------------+---------------+---------------------------------+
111  */
112
113 /* states of the playing device */
114 #define WINE_WS_PLAYING         0
115 #define WINE_WS_PAUSED          1
116 #define WINE_WS_STOPPED         2
117 #define WINE_WS_CLOSED          3
118
119 /* events to be send to device */
120 enum win_wm_message {
121     WINE_WM_PAUSING = WM_USER + 1, WINE_WM_RESTARTING, WINE_WM_RESETTING, WINE_WM_HEADER,
122     WINE_WM_UPDATE, WINE_WM_BREAKLOOP, WINE_WM_CLOSING, WINE_WM_STARTING, WINE_WM_STOPPING
123 };
124
125 typedef struct {
126     enum win_wm_message         msg;    /* message identifier */
127     DWORD                       param;  /* parameter for this message */
128     HANDLE                      hEvent; /* if message is synchronous, handle of event for synchro */
129 } RING_MSG;
130
131 /* implement an in-process message ring for better performance
132  * (compared to passing thru the server)
133  * this ring will be used by the input (resp output) record (resp playback) routine
134  */
135 #define ARTS_RING_BUFFER_INCREMENT      64
136 typedef struct {
137     RING_MSG                    * messages;
138     int                         ring_buffer_size;
139     int                         msg_tosave;
140     int                         msg_toget;
141     HANDLE                      msg_event;
142     CRITICAL_SECTION            msg_crst;
143 } ARTS_MSG_RING;
144
145 typedef struct {
146     volatile int                state;                  /* one of the WINE_WS_ manifest constants */
147     WAVEOPENDESC                waveDesc;
148     WORD                        wFlags;
149     PCMWAVEFORMAT               format;
150     WAVEOUTCAPSW                caps;
151     char                        interface_name[32];
152
153     DWORD                       dwSleepTime;            /* Num of milliseconds to sleep between filling the dsp buffers */
154
155     /* arts information */
156     arts_stream_t               play_stream;            /* the stream structure we get from arts when opening a stream for playing */
157     DWORD                       dwBufferSize;           /* size of whole buffer in bytes */
158     int                         packetSettings;
159
160     char*                       sound_buffer;
161     long                        buffer_size;
162
163     DWORD                       volume_left;            /* volume control information */
164     DWORD                       volume_right;
165
166     LPWAVEHDR                   lpQueuePtr;             /* start of queued WAVEHDRs (waiting to be notified) */
167     LPWAVEHDR                   lpPlayPtr;              /* start of not yet fully played buffers */
168     DWORD                       dwPartialOffset;        /* Offset of not yet written bytes in lpPlayPtr */
169
170     LPWAVEHDR                   lpLoopPtr;              /* pointer of first buffer in loop, if any */
171     DWORD                       dwLoops;                /* private copy of loop counter */
172
173     DWORD                       dwPlayedTotal;          /* number of bytes actually played since opening */
174     DWORD                       dwWrittenTotal;         /* number of bytes written to the audio device since opening */
175
176     /* synchronization stuff */
177     HANDLE                      hStartUpEvent;
178     HANDLE                      hThread;
179     DWORD                       dwThreadID;
180     ARTS_MSG_RING               msgRing;
181 } WINE_WAVEOUT;
182
183 typedef struct {
184     volatile int                state;                  /* one of the WINE_WS_ manifest constants */
185     WAVEOPENDESC                waveDesc;
186     WORD                        wFlags;
187     PCMWAVEFORMAT               format;
188     WAVEINCAPSW                 caps;
189     char                        interface_name[32];
190
191     /* arts information */
192     arts_stream_t               record_stream;          /* the stream structure we get from arts when opening a stream for recording */
193     int                         packetSettings;
194
195     LPWAVEHDR                   lpQueuePtr;
196     DWORD                       dwRecordedTotal;
197
198     /* synchronization stuff */
199     HANDLE                      hStartUpEvent;
200     HANDLE                      hThread;
201     DWORD                       dwThreadID;
202     ARTS_MSG_RING               msgRing;
203 } WINE_WAVEIN;
204
205 static BOOL             init;
206 static WINE_WAVEOUT     WOutDev   [MAX_WAVEOUTDRV];
207 static WINE_WAVEIN      WInDev    [MAX_WAVEINDRV];
208
209 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
210 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
211
212 /* These strings used only for tracing */
213 static const char * const wodPlayerCmdString[] = {
214     "WINE_WM_PAUSING",
215     "WINE_WM_RESTARTING",
216     "WINE_WM_RESETTING",
217     "WINE_WM_HEADER",
218     "WINE_WM_UPDATE",
219     "WINE_WM_BREAKLOOP",
220     "WINE_WM_CLOSING",
221     "WINE_WM_STARTING",
222     "WINE_WM_STOPPING",
223 };
224
225 static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
226                              PCMWAVEFORMAT* format)
227 {
228     TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
229           lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
230           format->wf.nChannels, format->wf.nAvgBytesPerSec);
231     TRACE("Position in bytes=%u\n", position);
232
233     switch (lpTime->wType) {
234     case TIME_SAMPLES:
235         lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
236         TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
237         break;
238     case TIME_MS:
239         lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
240         TRACE("TIME_MS=%u\n", lpTime->u.ms);
241         break;
242     case TIME_SMPTE:
243         lpTime->u.smpte.fps = 30;
244         position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
245         position += (format->wf.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
246         lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
247         position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
248         lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
249         lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
250         lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
251         lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
252         lpTime->u.smpte.fps = 30;
253         lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
254         TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
255               lpTime->u.smpte.hour, lpTime->u.smpte.min,
256               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
257         break;
258     default:
259         WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
260         lpTime->wType = TIME_BYTES;
261         /* fall through */
262     case TIME_BYTES:
263         lpTime->u.cb = position;
264         TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
265         break;
266     }
267     return MMSYSERR_NOERROR;
268 }
269
270 /*======================================================================*
271  *                  Low level WAVE implementation                       *
272  *======================================================================*/
273
274 /* Volume functions derived from Alsaplayer source */
275 /* length is the number of 16 bit samples */
276 static void volume_effect16(void *bufin, void* bufout, int length, int left,
277                             int right, int nChannels)
278 {
279   short *d_out = (short *)bufout;
280   short *d_in = (short *)bufin;
281   int i, v;
282
283 /*
284   TRACE("length == %d, nChannels == %d\n", length, nChannels);
285 */
286
287   if (right == -1) right = left;
288
289   for(i = 0; i < length; i+=(nChannels))
290   {
291     v = (int) ((*(d_in++) * left) / 100);
292     *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
293     if(nChannels == 2)
294     {
295       v = (int) ((*(d_in++) * right) / 100);
296       *(d_out++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
297     }
298   }
299 }
300
301 /* length is the number of 8 bit samples */
302 static void volume_effect8(void *bufin, void* bufout, int length, int left,
303                            int right, int       nChannels)
304 {
305   BYTE *d_out = (BYTE *)bufout;
306   BYTE *d_in = (BYTE *)bufin;
307   int i, v;
308
309 /*
310   TRACE("length == %d, nChannels == %d\n", length, nChannels);
311 */
312
313   if (right == -1) right = left;
314
315   for(i = 0; i < length; i+=(nChannels))
316   {
317     v = (BYTE) ((*(d_in++) * left) / 100);
318     *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);
319     if(nChannels == 2)
320     {
321       v = (BYTE) ((*(d_in++) * right) / 100);
322       *(d_out++) = (v>255) ? 255 : ((v<0) ? 0 : v);
323     }
324   }
325 }
326
327 /******************************************************************
328  *              ARTS_CloseWaveOutDevice
329  *
330  */
331 static void ARTS_CloseWaveOutDevice(WINE_WAVEOUT* wwo)
332 {
333   arts_close_stream(wwo->play_stream);  /* close the arts stream */
334   wwo->play_stream = (arts_stream_t*)-1;
335
336   /* free up the buffer we use for volume and reset the size */
337   HeapFree(GetProcessHeap(), 0, wwo->sound_buffer);
338   wwo->sound_buffer = NULL;
339   wwo->buffer_size = 0;
340 }
341
342 /******************************************************************
343  *              ARTS_CloseWaveInDevice
344  *
345  */
346 static void ARTS_CloseWaveInDevice(WINE_WAVEIN* wwi)
347 {
348   arts_close_stream(wwi->record_stream);        /* close the arts stream */
349   wwi->record_stream = (arts_stream_t*)-1;
350 }
351
352 /******************************************************************
353  *              ARTS_Init
354  */
355 static int      ARTS_Init(void)
356 {
357   return arts_init();  /* initialize arts and return errorcode */
358 }
359
360 /******************************************************************
361  *              ARTS_WaveClose
362  */
363 LONG            ARTS_WaveClose(void)
364 {
365     int iDevice;
366
367     /* close all open devices */
368     for(iDevice = 0; iDevice < MAX_WAVEOUTDRV; iDevice++)
369     {
370       if(WOutDev[iDevice].play_stream != (arts_stream_t*)-1)
371       {
372         ARTS_CloseWaveOutDevice(&WOutDev[iDevice]);
373       }
374     }
375
376     for(iDevice = 0; iDevice < MAX_WAVEINDRV; iDevice++)
377     {
378       if(WInDev[iDevice].record_stream != (arts_stream_t*)-1)
379       {
380         ARTS_CloseWaveInDevice(&WInDev[iDevice]);
381       }
382     }
383
384     if (init)
385         arts_free();    /* free up arts */
386     return 1;
387 }
388
389 /******************************************************************
390  *              ARTS_WaveInit
391  *
392  * Initialize internal structures from ARTS server info
393  */
394 LONG ARTS_WaveInit(void)
395 {
396     int         i;
397     int         errorcode;
398     LONG        ret = 0;
399
400     TRACE("called\n");
401
402     __TRY
403     {
404         if ((errorcode = ARTS_Init()) < 0)
405         {
406             WARN("arts_init() failed (%d)\n", errorcode);
407             ret = -1;
408         }
409     }
410     __EXCEPT_PAGE_FAULT
411     {
412         ERR("arts_init() crashed\n");
413         ret = -1;
414     }
415     __ENDTRY
416
417     if (ret)
418         return ret;
419
420     init = TRUE;
421
422     /* initialize all device handles to -1 */
423     for (i = 0; i < MAX_WAVEOUTDRV; ++i)
424     {
425         static const WCHAR ini[] = {'a','R','t','s',' ','W','a','v','e','O','u','t','D','r','i','v','e','r',0};
426
427         WOutDev[i].play_stream = (arts_stream_t*)-1;
428         memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps)); /* zero out
429                                                         caps values */
430         WOutDev[i].caps.wMid = 0x00FF;  /* Manufac ID */
431         WOutDev[i].caps.wPid = 0x0001;  /* Product ID */
432         strcpyW(WOutDev[i].caps.szPname, ini);
433         snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winearts: %d", i);
434
435         WOutDev[i].caps.vDriverVersion = 0x0100;
436         WOutDev[i].caps.dwFormats = 0x00000000;
437         WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
438
439         WOutDev[i].caps.wChannels = 2;
440         WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;
441
442         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
443         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;
444         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
445         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
446         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
447         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;
448         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
449         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
450         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
451         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
452         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
453         WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
454     }
455
456     for (i = 0; i < MAX_WAVEINDRV; ++i)
457     {
458         static const WCHAR ini[] = {'a','R','t','s',' ','W','a','v','e','I','n',' ','D','r','i','v','e','r',0};
459
460         WInDev[i].record_stream = (arts_stream_t*)-1;
461         memset(&WInDev[i].caps, 0, sizeof(WInDev[i].caps)); /* zero out
462                                                         caps values */
463         WInDev[i].caps.wMid = 0x00FF;
464         WInDev[i].caps.wPid = 0x0001;
465         strcpyW(WInDev[i].caps.szPname, ini);
466         snprintf(WInDev[i].interface_name, sizeof(WInDev[i].interface_name), "winearts: %d", i);
467
468         WInDev[i].caps.vDriverVersion = 0x0100;
469         WInDev[i].caps.dwFormats = 0x00000000;
470
471         WInDev[i].caps.wChannels = 2;
472
473         WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
474         WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08;
475         WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
476         WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
477         WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
478         WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08;
479         WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
480         WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
481         WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
482         WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;
483         WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
484         WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
485
486         WInDev[i].caps.wReserved1 = 0;
487     }
488     return 0;
489 }
490
491 /******************************************************************
492  *              ARTS_InitRingMessage
493  *
494  * Initialize the ring of messages for passing between driver's caller and playback/record
495  * thread
496  */
497 static int ARTS_InitRingMessage(ARTS_MSG_RING* mr)
498 {
499     mr->msg_toget = 0;
500     mr->msg_tosave = 0;
501     mr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL);
502     mr->ring_buffer_size = ARTS_RING_BUFFER_INCREMENT;
503     mr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,mr->ring_buffer_size * sizeof(RING_MSG));
504     InitializeCriticalSection(&mr->msg_crst);
505     return 0;
506 }
507
508 /******************************************************************
509  *              ARTS_DestroyRingMessage
510  *
511  */
512 static int ARTS_DestroyRingMessage(ARTS_MSG_RING* mr)
513 {
514     CloseHandle(mr->msg_event);
515     HeapFree(GetProcessHeap(),0,mr->messages);
516     mr->messages=NULL;
517     DeleteCriticalSection(&mr->msg_crst);
518     return 0;
519 }
520
521 /******************************************************************
522  *              ARTS_AddRingMessage
523  *
524  * Inserts a new message into the ring (should be called from DriverProc derivated routines)
525  */
526 static int ARTS_AddRingMessage(ARTS_MSG_RING* mr, enum win_wm_message msg, DWORD param, BOOL wait)
527 {
528     HANDLE      hEvent = INVALID_HANDLE_VALUE;
529
530     EnterCriticalSection(&mr->msg_crst);
531     if ((mr->msg_toget == ((mr->msg_tosave + 1) % mr->ring_buffer_size)))
532     {
533         int old_ring_buffer_size = mr->ring_buffer_size;
534         mr->ring_buffer_size += ARTS_RING_BUFFER_INCREMENT;
535         TRACE("mr->ring_buffer_size=%d\n",mr->ring_buffer_size);
536         mr->messages = HeapReAlloc(GetProcessHeap(),0,mr->messages, mr->ring_buffer_size * sizeof(RING_MSG));
537         /* Now we need to rearrange the ring buffer so that the new
538            buffers just allocated are in between mr->msg_tosave and
539            mr->msg_toget.
540         */
541         if (mr->msg_tosave < mr->msg_toget)
542         {
543             memmove(&(mr->messages[mr->msg_toget + ARTS_RING_BUFFER_INCREMENT]),
544                     &(mr->messages[mr->msg_toget]),
545                     sizeof(RING_MSG)*(old_ring_buffer_size - mr->msg_toget)
546                     );
547             mr->msg_toget += ARTS_RING_BUFFER_INCREMENT;
548         }
549     }
550     if (wait)
551     {
552         hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
553         if (hEvent == INVALID_HANDLE_VALUE)
554         {
555             ERR("can't create event !?\n");
556             LeaveCriticalSection(&mr->msg_crst);
557             return 0;
558         }
559         if (mr->msg_toget != mr->msg_tosave && mr->messages[mr->msg_toget].msg != WINE_WM_HEADER)
560             FIXME("two fast messages in the queue!!!!\n");
561
562         /* fast messages have to be added at the start of the queue */
563         mr->msg_toget = (mr->msg_toget + mr->ring_buffer_size - 1) % mr->ring_buffer_size;
564
565         mr->messages[mr->msg_toget].msg = msg;
566         mr->messages[mr->msg_toget].param = param;
567         mr->messages[mr->msg_toget].hEvent = hEvent;
568     }
569     else
570     {
571         mr->messages[mr->msg_tosave].msg = msg;
572         mr->messages[mr->msg_tosave].param = param;
573         mr->messages[mr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;
574         mr->msg_tosave = (mr->msg_tosave + 1) % mr->ring_buffer_size;
575     }
576
577     LeaveCriticalSection(&mr->msg_crst);
578
579     SetEvent(mr->msg_event);    /* signal a new message */
580
581     if (wait)
582     {
583         /* wait for playback/record thread to have processed the message */
584         WaitForSingleObject(hEvent, INFINITE);
585         CloseHandle(hEvent);
586     }
587
588     return 1;
589 }
590
591 /******************************************************************
592  *              ARTS_RetrieveRingMessage
593  *
594  * Get a message from the ring. Should be called by the playback/record thread.
595  */
596 static int ARTS_RetrieveRingMessage(ARTS_MSG_RING* mr,
597                                    enum win_wm_message *msg, DWORD *param, HANDLE *hEvent)
598 {
599     EnterCriticalSection(&mr->msg_crst);
600
601     if (mr->msg_toget == mr->msg_tosave) /* buffer empty ? */
602     {
603         LeaveCriticalSection(&mr->msg_crst);
604         return 0;
605     }
606
607     *msg = mr->messages[mr->msg_toget].msg;
608     mr->messages[mr->msg_toget].msg = 0;
609     *param = mr->messages[mr->msg_toget].param;
610     *hEvent = mr->messages[mr->msg_toget].hEvent;
611     mr->msg_toget = (mr->msg_toget + 1) % mr->ring_buffer_size;
612     LeaveCriticalSection(&mr->msg_crst);
613     return 1;
614 }
615
616 /*======================================================================*
617  *                  Low level WAVE OUT implementation                   *
618  *======================================================================*/
619
620 /**************************************************************************
621  *                      wodNotifyClient                 [internal]
622  */
623 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
624 {
625     TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2);
626
627     switch (wMsg) {
628     case WOM_OPEN:
629     case WOM_CLOSE:
630     case WOM_DONE:
631         if (wwo->wFlags != DCB_NULL &&
632             !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags, (HDRVR)wwo->waveDesc.hWave,
633                             wMsg, wwo->waveDesc.dwInstance, dwParam1, dwParam2)) {
634             WARN("can't notify client !\n");
635             return MMSYSERR_ERROR;
636         }
637         break;
638     default:
639         FIXME("Unknown callback message %u\n", wMsg);
640         return MMSYSERR_INVALPARAM;
641     }
642     return MMSYSERR_NOERROR;
643 }
644
645 /**************************************************************************
646  *                              wodUpdatePlayedTotal    [internal]
647  *
648  */
649 static BOOL wodUpdatePlayedTotal(WINE_WAVEOUT* wwo)
650 {
651     /* total played is the bytes written less the bytes to write ;-) */
652     wwo->dwPlayedTotal = wwo->dwWrittenTotal -
653         (wwo->dwBufferSize -
654         arts_stream_get(wwo->play_stream, ARTS_P_BUFFER_SPACE));
655
656     return TRUE;
657 }
658
659 /**************************************************************************
660  *                              wodPlayer_BeginWaveHdr          [internal]
661  *
662  * Makes the specified lpWaveHdr the currently playing wave header.
663  * If the specified wave header is a begin loop and we're not already in
664  * a loop, setup the loop.
665  */
666 static void wodPlayer_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
667 {
668     wwo->lpPlayPtr = lpWaveHdr;
669
670     if (!lpWaveHdr) return;
671
672     if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP) {
673         if (wwo->lpLoopPtr) {
674             WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
675             TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
676         } else {
677             TRACE("Starting loop (%dx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
678             wwo->lpLoopPtr = lpWaveHdr;
679             /* Windows does not touch WAVEHDR.dwLoops,
680              * so we need to make an internal copy */
681             wwo->dwLoops = lpWaveHdr->dwLoops;
682         }
683     }
684     wwo->dwPartialOffset = 0;
685 }
686
687 /**************************************************************************
688  *                              wodPlayer_PlayPtrNext           [internal]
689  *
690  * Advance the play pointer to the next waveheader, looping if required.
691  */
692 static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEOUT* wwo)
693 {
694     LPWAVEHDR lpWaveHdr = wwo->lpPlayPtr;
695
696     wwo->dwPartialOffset = 0;
697     if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr) {
698         /* We're at the end of a loop, loop if required */
699         if (--wwo->dwLoops > 0) {
700             wwo->lpPlayPtr = wwo->lpLoopPtr;
701         } else {
702             /* Handle overlapping loops correctly */
703             if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
704                 FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
705                 /* shall we consider the END flag for the closing loop or for
706                  * the opening one or for both ???
707                  * code assumes for closing loop only
708                  */
709             } else {
710                 lpWaveHdr = lpWaveHdr->lpNext;
711             }
712             wwo->lpLoopPtr = NULL;
713             wodPlayer_BeginWaveHdr(wwo, lpWaveHdr);
714         }
715     } else {
716         /* We're not in a loop.  Advance to the next wave header */
717         wodPlayer_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
718     }
719
720     return lpWaveHdr;
721 }
722
723 /**************************************************************************
724  *                           wodPlayer_NotifyWait               [internal]
725  * Returns the number of milliseconds to wait before attempting to notify
726  * completion of the specified wavehdr.
727  * This is based on the number of bytes remaining to be written in the
728  * wave.
729  */
730 static DWORD wodPlayer_NotifyWait(const WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
731 {
732     DWORD dwMillis;
733
734     if(lpWaveHdr->reserved < wwo->dwPlayedTotal)
735     {
736         dwMillis = 1;
737     }
738     else
739     {
740         dwMillis = (lpWaveHdr->reserved - wwo->dwPlayedTotal) * 1000 / wwo->format.wf.nAvgBytesPerSec;
741         if(!dwMillis) dwMillis = 1;
742     }
743
744     TRACE("dwMillis = %d\n", dwMillis);
745
746     return dwMillis;
747 }
748
749
750 /**************************************************************************
751  *                           wodPlayer_WriteMaxFrags            [internal]
752  * Writes the maximum number of bytes possible to the DSP and returns
753  * the number of bytes written.
754  */
755 static int wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes)
756 {
757     /* Only attempt to write to free bytes */
758     DWORD dwLength = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
759     int toWrite = min(dwLength, *bytes);
760     int written;
761
762     TRACE("Writing wavehdr %p.%u[%u]\n",
763           wwo->lpPlayPtr, wwo->dwPartialOffset, wwo->lpPlayPtr->dwBufferLength);
764
765     if (dwLength == 0)
766     {
767         wodPlayer_PlayPtrNext(wwo);
768         return 0;
769     }
770
771     /* see if our buffer isn't large enough for the data we are writing */
772     if(wwo->buffer_size < toWrite)
773     {
774       if(wwo->sound_buffer)
775       {
776         wwo->sound_buffer = HeapReAlloc(GetProcessHeap(), 0, wwo->sound_buffer, toWrite);
777         wwo->buffer_size = toWrite;
778       }
779     }
780
781     /* if we don't have a buffer then get one */
782     if(!wwo->sound_buffer)
783     {
784       /* allocate some memory for the buffer */
785       wwo->sound_buffer = HeapAlloc(GetProcessHeap(), 0, toWrite);
786       wwo->buffer_size = toWrite;
787     }
788
789     /* if we don't have a buffer then error out */
790     if(!wwo->sound_buffer)
791     {
792       ERR("error allocating sound_buffer memory\n");
793       return 0;
794     }
795
796     TRACE("toWrite == %d\n", toWrite);
797
798     /* apply volume to the bits */
799     /* for single channel audio streams we only use the LEFT volume */
800     if(wwo->format.wBitsPerSample == 16)
801     {
802       /* apply volume to the buffer we are about to send */
803       /* divide toWrite(bytes) by 2 as volume processes by 16 bits */
804       volume_effect16(wwo->lpPlayPtr->lpData + wwo->dwPartialOffset,
805                 wwo->sound_buffer, toWrite>>1, wwo->volume_left,
806                 wwo->volume_right, wwo->format.wf.nChannels);
807     } else if(wwo->format.wBitsPerSample == 8)
808     {
809       /* apply volume to the buffer we are about to send */
810       volume_effect8(wwo->lpPlayPtr->lpData + wwo->dwPartialOffset,
811                 wwo->sound_buffer, toWrite, wwo->volume_left,
812                 wwo->volume_right, wwo->format.wf.nChannels);
813     } else
814     {
815       FIXME("unsupported wwo->format.wBitsPerSample of %d\n",
816         wwo->format.wBitsPerSample);
817     }
818
819     /* send the audio data to arts for playing */
820     written = arts_write(wwo->play_stream, wwo->sound_buffer, toWrite);
821
822     TRACE("written = %d\n", written);
823
824     if (written <= 0) 
825     {
826       *bytes = 0; /* apparently arts is actually full */
827       return written; /* if we wrote nothing just return */
828     }
829
830     if (written >= dwLength)
831         wodPlayer_PlayPtrNext(wwo);   /* If we wrote all current wavehdr, skip to the next one */
832     else
833         wwo->dwPartialOffset += written;    /* Remove the amount written */
834
835     if (written < toWrite)
836         *bytes = 0;
837     else
838         *bytes -= written;
839
840     wwo->dwWrittenTotal += written; /* update stats on this wave device */
841
842     return written; /* return the number of bytes written */
843 }
844
845
846 /**************************************************************************
847  *                              wodPlayer_NotifyCompletions     [internal]
848  *
849  * Notifies and remove from queue all wavehdrs which have been played to
850  * the speaker (ie. they have cleared the audio device).  If force is true,
851  * we notify all wavehdrs and remove them all from the queue even if they
852  * are unplayed or part of a loop.
853  */
854 static DWORD wodPlayer_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
855 {
856     LPWAVEHDR           lpWaveHdr;
857
858     if (wwo->lpQueuePtr) {
859         TRACE("lpWaveHdr=(%p), lpPlayPtr=(%p), lpLoopPtr=(%p), reserved=(%d), dwWrittenTotal=(%d), force=(%d)\n",
860               wwo->lpQueuePtr,
861               wwo->lpPlayPtr,
862               wwo->lpLoopPtr,
863               wwo->lpQueuePtr->reserved,
864               wwo->dwWrittenTotal,
865               force);
866     } else {
867         TRACE("lpWaveHdr=(%p), lpPlayPtr=(%p), lpLoopPtr=(%p),  dwWrittenTotal=(%d), force=(%d)\n",
868               wwo->lpQueuePtr,
869               wwo->lpPlayPtr,
870               wwo->lpLoopPtr,
871               wwo->dwWrittenTotal,
872               force);
873     }
874
875     /* Start from lpQueuePtr and keep notifying until:
876      * - we hit an unwritten wavehdr
877      * - we hit the beginning of a running loop
878      * - we hit a wavehdr which hasn't finished playing
879      */
880     while ((lpWaveHdr = wwo->lpQueuePtr) &&
881            (force ||
882             (lpWaveHdr != wwo->lpPlayPtr &&
883              lpWaveHdr != wwo->lpLoopPtr &&
884              lpWaveHdr->reserved <= wwo->dwWrittenTotal))) {
885
886         wwo->lpQueuePtr = lpWaveHdr->lpNext;
887
888         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
889         lpWaveHdr->dwFlags |= WHDR_DONE;
890
891         wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
892     }
893     return  (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr != wwo->lpLoopPtr) ?
894         wodPlayer_NotifyWait(wwo, lpWaveHdr) : INFINITE;
895 }
896
897 /**************************************************************************
898  *                              wodPlayer_Reset                 [internal]
899  *
900  * wodPlayer helper. Resets current output stream.
901  */
902 static  void    wodPlayer_Reset(WINE_WAVEOUT* wwo, BOOL reset)
903 {
904     wodUpdatePlayedTotal(wwo);
905
906     wodPlayer_NotifyCompletions(wwo, FALSE); /* updates current notify list */
907
908     /* we aren't able to flush any data that has already been written */
909     /* to arts, otherwise we would do the flushing here */
910
911     if (reset) {
912         enum win_wm_message     msg;
913         DWORD                   param;
914         HANDLE                  ev;
915
916         /* remove any buffer */
917         wodPlayer_NotifyCompletions(wwo, TRUE);
918
919         wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
920         wwo->state = WINE_WS_STOPPED;
921         wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
922
923         wwo->dwPartialOffset = 0;        /* Clear partial wavehdr */
924
925         /* remove any existing message in the ring */
926         EnterCriticalSection(&wwo->msgRing.msg_crst);
927
928         /* return all pending headers in queue */
929         while (ARTS_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev))
930         {
931             TRACE("flushing msg\n");
932             if (msg != WINE_WM_HEADER)
933             {
934                 FIXME("shouldn't have headers left\n");
935                 SetEvent(ev);
936                 continue;
937             }
938             ((LPWAVEHDR)param)->dwFlags &= ~WHDR_INQUEUE;
939             ((LPWAVEHDR)param)->dwFlags |= WHDR_DONE;
940
941             wodNotifyClient(wwo, WOM_DONE, param, 0);
942         }
943         ResetEvent(wwo->msgRing.msg_event);
944         LeaveCriticalSection(&wwo->msgRing.msg_crst);
945     } else {
946         if (wwo->lpLoopPtr) {
947             /* complicated case, not handled yet (could imply modifying the loop counter */
948             FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
949             wwo->lpPlayPtr = wwo->lpLoopPtr;
950             wwo->dwPartialOffset = 0;
951             wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
952         } else {
953             /* the data already written is going to be played, so take */
954             /* this fact into account here */
955             wwo->dwPlayedTotal = wwo->dwWrittenTotal;
956         }
957         wwo->state = WINE_WS_PAUSED;
958     }
959 }
960
961 /**************************************************************************
962  *                    wodPlayer_ProcessMessages                 [internal]
963  */
964 static void wodPlayer_ProcessMessages(WINE_WAVEOUT* wwo)
965 {
966     LPWAVEHDR           lpWaveHdr;
967     enum win_wm_message msg;
968     DWORD               param;
969     HANDLE              ev;
970
971     while (ARTS_RetrieveRingMessage(&wwo->msgRing, &msg, &param, &ev)) {
972         TRACE("Received %s %x\n", wodPlayerCmdString[msg - WM_USER - 1], param);
973         switch (msg) {
974         case WINE_WM_PAUSING:
975             wodPlayer_Reset(wwo, FALSE);
976             SetEvent(ev);
977             break;
978         case WINE_WM_RESTARTING:
979             wwo->state = WINE_WS_PLAYING;
980             SetEvent(ev);
981             break;
982         case WINE_WM_HEADER:
983             lpWaveHdr = (LPWAVEHDR)param;
984
985             /* insert buffer at the end of queue */
986             {
987                 LPWAVEHDR*      wh;
988                 for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
989                 *wh = lpWaveHdr;
990             }
991             if (!wwo->lpPlayPtr)
992                 wodPlayer_BeginWaveHdr(wwo,lpWaveHdr);
993             if (wwo->state == WINE_WS_STOPPED)
994                 wwo->state = WINE_WS_PLAYING;
995             break;
996         case WINE_WM_RESETTING:
997             wodPlayer_Reset(wwo, TRUE);
998             SetEvent(ev);
999             break;
1000         case WINE_WM_UPDATE:
1001             wodUpdatePlayedTotal(wwo);
1002             SetEvent(ev);
1003             break;
1004         case WINE_WM_BREAKLOOP:
1005             if (wwo->state == WINE_WS_PLAYING && wwo->lpLoopPtr != NULL) {
1006                 /* ensure exit at end of current loop */
1007                 wwo->dwLoops = 1;
1008             }
1009             SetEvent(ev);
1010             break;
1011         case WINE_WM_CLOSING:
1012             /* sanity check: this should not happen since the device must have been reset before */
1013             if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
1014             wwo->hThread = 0;
1015             wwo->state = WINE_WS_CLOSED;
1016             SetEvent(ev);
1017             ExitThread(0);
1018             /* shouldn't go here */
1019         default:
1020             FIXME("unknown message %d\n", msg);
1021             break;
1022         }
1023     }
1024 }
1025
1026 /**************************************************************************
1027  *                           wodPlayer_FeedDSP                  [internal]
1028  * Feed as much sound data as we can into the DSP and return the number of
1029  * milliseconds before it will be necessary to feed the DSP again.
1030  */
1031 static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo)
1032 {
1033     DWORD       availInQ;
1034
1035     wodUpdatePlayedTotal(wwo);
1036     availInQ = arts_stream_get(wwo->play_stream, ARTS_P_BUFFER_SPACE);
1037     TRACE("availInQ = %d\n", availInQ);
1038
1039     /* input queue empty */
1040     if (!wwo->lpPlayPtr) {
1041         TRACE("Run out of wavehdr:s... flushing\n");
1042         return INFINITE;
1043     }
1044
1045     /* no more room... no need to try to feed */
1046     if(!availInQ)
1047     {
1048         TRACE("no more room, no need to try to feed\n");
1049         return wwo->dwSleepTime;
1050     }
1051
1052     /* Feed from partial wavehdr */
1053     if (wwo->lpPlayPtr && wwo->dwPartialOffset != 0)
1054     {
1055         TRACE("feeding from partial wavehdr\n");
1056         wodPlayer_WriteMaxFrags(wwo, &availInQ);
1057     }
1058
1059     /* Feed wavehdrs until we run out of wavehdrs or DSP space */
1060     if (!wwo->dwPartialOffset)
1061     {
1062         while(wwo->lpPlayPtr && availInQ)
1063         {
1064             TRACE("feeding waveheaders until we run out of space\n");
1065             /* note the value that dwPlayedTotal will return when this wave finishes playing */
1066             wwo->lpPlayPtr->reserved = wwo->dwWrittenTotal + wwo->lpPlayPtr->dwBufferLength;
1067             TRACE("reserved=(%d) dwWrittenTotal=(%d) dwBufferLength=(%d)\n",
1068                   wwo->lpPlayPtr->reserved,
1069                   wwo->dwWrittenTotal,
1070                   wwo->lpPlayPtr->dwBufferLength
1071                 );
1072             wodPlayer_WriteMaxFrags(wwo, &availInQ);
1073         }
1074     }
1075
1076     if (!wwo->lpPlayPtr) {
1077         TRACE("Ran out of wavehdrs\n");
1078         return INFINITE;
1079     }
1080
1081     return wwo->dwSleepTime;
1082 }
1083
1084
1085 /**************************************************************************
1086  *                              wodPlayer                       [internal]
1087  */
1088 static  DWORD   CALLBACK        wodPlayer(LPVOID pmt)
1089 {
1090     WORD          uDevID = (DWORD)pmt;
1091     WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)&WOutDev[uDevID];
1092     DWORD         dwNextFeedTime = INFINITE;   /* Time before DSP needs feeding */
1093     DWORD         dwNextNotifyTime = INFINITE; /* Time before next wave completion */
1094     DWORD         dwSleepTime;
1095
1096     wwo->state = WINE_WS_STOPPED;
1097     SetEvent(wwo->hStartUpEvent);
1098
1099     for (;;) {
1100         /** Wait for the shortest time before an action is required.  If there
1101          *  are no pending actions, wait forever for a command.
1102          */
1103         dwSleepTime = min(dwNextFeedTime, dwNextNotifyTime);
1104         TRACE("waiting %ums (%u,%u)\n", dwSleepTime, dwNextFeedTime, dwNextNotifyTime);
1105         WaitForSingleObject(wwo->msgRing.msg_event, dwSleepTime);
1106         wodPlayer_ProcessMessages(wwo);
1107         if (wwo->state == WINE_WS_PLAYING) {
1108             dwNextFeedTime = wodPlayer_FeedDSP(wwo);
1109             dwNextNotifyTime = wodPlayer_NotifyCompletions(wwo, FALSE);
1110         } else {
1111             dwNextFeedTime = dwNextNotifyTime = INFINITE;
1112         }
1113     }
1114 }
1115
1116 /**************************************************************************
1117  *                      wodGetDevCaps                           [internal]
1118  */
1119 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
1120 {
1121     TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
1122
1123     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1124
1125     if (wDevID >= MAX_WAVEOUTDRV) {
1126         TRACE("MAX_WAVOUTDRV reached !\n");
1127         return MMSYSERR_BADDEVICEID;
1128     }
1129
1130     memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1131     return MMSYSERR_NOERROR;
1132 }
1133
1134 /**************************************************************************
1135  *                              wodOpen                         [internal]
1136  */
1137 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1138 {
1139     WINE_WAVEOUT*       wwo;
1140
1141     TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
1142     if (lpDesc == NULL) {
1143         WARN("Invalid Parameter !\n");
1144         return MMSYSERR_INVALPARAM;
1145     }
1146     if (wDevID >= MAX_WAVEOUTDRV) {
1147         TRACE("MAX_WAVOUTDRV reached !\n");
1148         return MMSYSERR_BADDEVICEID;
1149     }
1150
1151     /* if this device is already open tell the app that it is allocated */
1152     if(WOutDev[wDevID].play_stream != (arts_stream_t*)-1)
1153     {
1154       TRACE("device already allocated\n");
1155       return MMSYSERR_ALLOCATED;
1156     }
1157
1158     /* only PCM format is supported so far... */
1159     if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1160         lpDesc->lpFormat->nChannels == 0 ||
1161         lpDesc->lpFormat->nSamplesPerSec < DSBFREQUENCY_MIN ||
1162         lpDesc->lpFormat->nSamplesPerSec > DSBFREQUENCY_MAX ||
1163         (lpDesc->lpFormat->wBitsPerSample!=8 && lpDesc->lpFormat->wBitsPerSample!=16)) {
1164         WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1165              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1166              lpDesc->lpFormat->nSamplesPerSec);
1167         return WAVERR_BADFORMAT;
1168     }
1169
1170     if (dwFlags & WAVE_FORMAT_QUERY) {
1171         TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1172              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1173              lpDesc->lpFormat->nSamplesPerSec);
1174         return MMSYSERR_NOERROR;
1175     }
1176
1177     wwo = &WOutDev[wDevID];
1178
1179     /* direct sound not supported, ignore the flag */
1180     dwFlags &= ~WAVE_DIRECTSOUND;
1181
1182     wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1183
1184     memcpy(&wwo->waveDesc, lpDesc,           sizeof(WAVEOPENDESC));
1185     memcpy(&wwo->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
1186
1187     if (wwo->format.wBitsPerSample == 0) {
1188         WARN("Resetting zeroed wBitsPerSample\n");
1189         wwo->format.wBitsPerSample = 8 *
1190             (wwo->format.wf.nAvgBytesPerSec /
1191              wwo->format.wf.nSamplesPerSec) /
1192             wwo->format.wf.nChannels;
1193     }
1194
1195     wwo->play_stream = arts_play_stream(wwo->format.wf.nSamplesPerSec,
1196         wwo->format.wBitsPerSample, wwo->format.wf.nChannels, "winearts");
1197
1198     /* clear these so we don't have any confusion ;-) */
1199     wwo->sound_buffer = 0;
1200     wwo->buffer_size = 0;
1201
1202     arts_stream_set(wwo->play_stream, ARTS_P_BLOCKING, 0);    /* disable blocking on this stream */
1203
1204     if(!wwo->play_stream) return MMSYSERR_ALLOCATED;
1205
1206     /* Try to set the packet settings from constant and store the value that it
1207        was actually set to for future use */
1208     wwo->packetSettings = arts_stream_set(wwo->play_stream, ARTS_P_PACKET_SETTINGS, WAVEOUT_PACKET_SETTINGS);
1209     TRACE("Tried to set ARTS_P_PACKET_SETTINGS to (%x), actually set to (%x)\n", WAVEOUT_PACKET_SETTINGS, wwo->packetSettings);
1210
1211     wwo->dwBufferSize = arts_stream_get(wwo->play_stream, ARTS_P_BUFFER_SIZE);
1212     TRACE("Buffer size is now (%d)\n",wwo->dwBufferSize);
1213
1214     wwo->dwPlayedTotal = 0;
1215     wwo->dwWrittenTotal = 0;
1216
1217     wwo->dwSleepTime = ((1 << (wwo->packetSettings & 0xFFFF)) * 1000 * BUFFER_REFILL_THRESHOLD) / wwo->format.wf.nAvgBytesPerSec;
1218
1219     /* Initialize volume to full level */
1220     wwo->volume_left = 100;
1221     wwo->volume_right = 100;
1222
1223     ARTS_InitRingMessage(&wwo->msgRing);
1224
1225     /* create player thread */
1226     if (!(dwFlags & WAVE_DIRECTSOUND)) {
1227         wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1228         wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD)wDevID, 0, &(wwo->dwThreadID));
1229         if (wwo->hThread)
1230             SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL);
1231         WaitForSingleObject(wwo->hStartUpEvent, INFINITE);
1232         CloseHandle(wwo->hStartUpEvent);
1233     } else {
1234         wwo->hThread = INVALID_HANDLE_VALUE;
1235         wwo->dwThreadID = 0;
1236     }
1237     wwo->hStartUpEvent = INVALID_HANDLE_VALUE;
1238
1239     TRACE("stream=0x%lx, dwBufferSize=%d\n",
1240           (long)wwo->play_stream, wwo->dwBufferSize);
1241
1242     TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
1243           wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,
1244           wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1245           wwo->format.wf.nBlockAlign);
1246
1247     return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
1248 }
1249
1250 /**************************************************************************
1251  *                              wodClose                        [internal]
1252  */
1253 static DWORD wodClose(WORD wDevID)
1254 {
1255     DWORD               ret = MMSYSERR_NOERROR;
1256     WINE_WAVEOUT*       wwo;
1257
1258     TRACE("(%u);\n", wDevID);
1259
1260     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream  ==
1261         (arts_stream_t*)-1)
1262     {
1263         WARN("bad device ID !\n");
1264         return MMSYSERR_BADDEVICEID;
1265     }
1266
1267     wwo = &WOutDev[wDevID];
1268     if (wwo->lpQueuePtr) {
1269         WARN("buffers still playing !\n");
1270         ret = WAVERR_STILLPLAYING;
1271     } else {
1272         TRACE("imhere[3-close]\n");
1273         if (wwo->hThread != INVALID_HANDLE_VALUE) {
1274             ARTS_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE);
1275         }
1276
1277         ARTS_DestroyRingMessage(&wwo->msgRing);
1278
1279         ARTS_CloseWaveOutDevice(wwo);   /* close the stream and clean things up */
1280
1281         ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
1282     }
1283     return ret;
1284 }
1285
1286 /**************************************************************************
1287  *                              wodWrite                        [internal]
1288  *
1289  */
1290 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1291 {
1292     TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
1293
1294     /* first, do the sanity checks... */
1295     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1296                 (arts_stream_t*)-1)
1297     {
1298         WARN("bad dev ID !\n");
1299         return MMSYSERR_BADDEVICEID;
1300     }
1301
1302     if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1303     {
1304         TRACE("unprepared\n");
1305         return WAVERR_UNPREPARED;
1306     }
1307
1308     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1309     {
1310         TRACE("still playing\n");
1311         return WAVERR_STILLPLAYING;
1312     }
1313
1314     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1315     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1316     lpWaveHdr->lpNext = 0;
1317
1318     TRACE("adding ring message\n");
1319     ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE);
1320
1321     return MMSYSERR_NOERROR;
1322 }
1323
1324 /**************************************************************************
1325  *                      wodPause                                [internal]
1326  */
1327 static DWORD wodPause(WORD wDevID)
1328 {
1329     TRACE("(%u);!\n", wDevID);
1330
1331     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1332                 (arts_stream_t*)-1)
1333     {
1334         WARN("bad device ID !\n");
1335         return MMSYSERR_BADDEVICEID;
1336     }
1337
1338     TRACE("imhere[3-PAUSING]\n");
1339     ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_PAUSING, 0, TRUE);
1340
1341     return MMSYSERR_NOERROR;
1342 }
1343
1344 /**************************************************************************
1345  *                      wodRestart                              [internal]
1346  */
1347 static DWORD wodRestart(WORD wDevID)
1348 {
1349     TRACE("(%u);\n", wDevID);
1350
1351     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1352                 (arts_stream_t*)-1)
1353     {
1354         WARN("bad device ID !\n");
1355         return MMSYSERR_BADDEVICEID;
1356     }
1357
1358     if (WOutDev[wDevID].state == WINE_WS_PAUSED) {
1359         TRACE("imhere[3-RESTARTING]\n");
1360         ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESTARTING, 0, TRUE);
1361     }
1362
1363     /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1364     /* FIXME: Myst crashes with this ... hmm -MM
1365        return wodNotifyClient(wwo, WOM_DONE, 0L, 0L);
1366     */
1367
1368     return MMSYSERR_NOERROR;
1369 }
1370
1371 /**************************************************************************
1372  *                      wodReset                                [internal]
1373  */
1374 static DWORD wodReset(WORD wDevID)
1375 {
1376     TRACE("(%u);\n", wDevID);
1377
1378     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1379         (arts_stream_t*)-1)
1380     {
1381         WARN("bad device ID !\n");
1382         return MMSYSERR_BADDEVICEID;
1383     }
1384
1385     TRACE("imhere[3-RESET]\n");
1386     ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
1387
1388     return MMSYSERR_NOERROR;
1389 }
1390
1391 /**************************************************************************
1392  *                              wodGetPosition                  [internal]
1393  */
1394 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1395 {
1396     WINE_WAVEOUT*       wwo;
1397
1398     TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
1399
1400     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1401         (arts_stream_t*)-1)
1402     {
1403         WARN("bad device ID !\n");
1404         return MMSYSERR_BADDEVICEID;
1405     }
1406
1407     if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1408
1409     wwo = &WOutDev[wDevID];
1410     ARTS_AddRingMessage(&wwo->msgRing, WINE_WM_UPDATE, 0, TRUE);
1411
1412     return bytes_to_mmtime(lpTime, wwo->dwPlayedTotal, &wwo->format);
1413 }
1414
1415 /**************************************************************************
1416  *                              wodBreakLoop                    [internal]
1417  */
1418 static DWORD wodBreakLoop(WORD wDevID)
1419 {
1420     TRACE("(%u);\n", wDevID);
1421
1422     if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].play_stream ==
1423                 (arts_stream_t*)-1)
1424     {
1425         WARN("bad device ID !\n");
1426         return MMSYSERR_BADDEVICEID;
1427     }
1428     ARTS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_BREAKLOOP, 0, TRUE);
1429     return MMSYSERR_NOERROR;
1430 }
1431
1432 /**************************************************************************
1433  *                              wodGetVolume                    [internal]
1434  */
1435 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1436 {
1437     DWORD left, right;
1438
1439     left = WOutDev[wDevID].volume_left;
1440     right = WOutDev[wDevID].volume_right;
1441
1442     TRACE("(%u, %p);\n", wDevID, lpdwVol);
1443
1444     *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) <<
1445                 16);
1446
1447     return MMSYSERR_NOERROR;
1448 }
1449
1450 /**************************************************************************
1451  *                              wodSetVolume                    [internal]
1452  */
1453 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1454 {
1455     DWORD left, right;
1456
1457     left  = (LOWORD(dwParam) * 100) / 0xFFFFl;
1458     right = (HIWORD(dwParam) * 100) / 0xFFFFl;
1459
1460     TRACE("(%u, %08X);\n", wDevID, dwParam);
1461
1462     WOutDev[wDevID].volume_left = left;
1463     WOutDev[wDevID].volume_right = right;
1464
1465     return MMSYSERR_NOERROR;
1466 }
1467
1468 /**************************************************************************
1469  *                              wodGetNumDevs                   [internal]
1470  */
1471 static  DWORD   wodGetNumDevs(void)
1472 {
1473     return MAX_WAVEOUTDRV;
1474 }
1475
1476 /**************************************************************************
1477  *                              wodDevInterfaceSize             [internal]
1478  */
1479 static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1480 {
1481     TRACE("(%u, %p)\n", wDevID, dwParam1);
1482                                                                                                        
1483     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1484                                     NULL, 0 ) * sizeof(WCHAR);
1485     return MMSYSERR_NOERROR;
1486 }
1487                                                                                                        
1488 /**************************************************************************
1489  *                              wodDevInterface                 [internal]
1490  */
1491 static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1492 {
1493     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1494                                         NULL, 0 ) * sizeof(WCHAR))
1495     {
1496         MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1497                             dwParam1, dwParam2 / sizeof(WCHAR));
1498         return MMSYSERR_NOERROR;
1499     }
1500     return MMSYSERR_INVALPARAM;
1501 }
1502                                                                                                        
1503 /**************************************************************************
1504  *                              wodMessage (WINEARTS.@)
1505  */
1506 DWORD WINAPI ARTS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1507                             DWORD dwParam1, DWORD dwParam2)
1508 {
1509     TRACE("(%u, %04X, %08X, %08X, %08X);\n",
1510           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1511
1512     switch (wMsg) {
1513     case DRVM_INIT:
1514     case DRVM_EXIT:
1515     case DRVM_ENABLE:
1516     case DRVM_DISABLE:
1517         /* FIXME: Pretend this is supported */
1518         return 0;
1519     case WODM_OPEN:             return wodOpen          (wDevID, (LPWAVEOPENDESC)dwParam1,      dwParam2);
1520     case WODM_CLOSE:            return wodClose         (wDevID);
1521     case WODM_WRITE:            return wodWrite         (wDevID, (LPWAVEHDR)dwParam1,           dwParam2);
1522     case WODM_PAUSE:            return wodPause         (wDevID);
1523     case WODM_GETPOS:           return wodGetPosition   (wDevID, (LPMMTIME)dwParam1,            dwParam2);
1524     case WODM_BREAKLOOP:        return wodBreakLoop     (wDevID);
1525     case WODM_PREPARE:          return MMSYSERR_NOTSUPPORTED;
1526     case WODM_UNPREPARE:        return MMSYSERR_NOTSUPPORTED;
1527     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (LPWAVEOUTCAPSW)dwParam1,      dwParam2);
1528     case WODM_GETNUMDEVS:       return wodGetNumDevs    ();
1529     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
1530     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
1531     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
1532     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
1533     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (LPDWORD)dwParam1);
1534     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, dwParam1);
1535     case WODM_RESTART:          return wodRestart       (wDevID);
1536     case WODM_RESET:            return wodReset         (wDevID);
1537
1538     case DRV_QUERYDEVICEINTERFACESIZE: return wodDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
1539     case DRV_QUERYDEVICEINTERFACE:     return wodDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
1540     case DRV_QUERYDSOUNDIFACE:  return wodDsCreate      (wDevID, (PIDSDRIVER*)dwParam1);
1541     case DRV_QUERYDSOUNDDESC:   return wodDsDesc        (wDevID, (PDSDRIVERDESC)dwParam1);
1542     default:
1543         FIXME("unknown message %d!\n", wMsg);
1544     }
1545     return MMSYSERR_NOTSUPPORTED;
1546 }
1547
1548 /*======================================================================*
1549  *                  Low level WAVE IN implementation                    *
1550  *======================================================================*/
1551
1552 /**************************************************************************
1553  *                              widGetNumDevs                   [internal]
1554  */
1555 static  DWORD   widGetNumDevs(void)
1556 {
1557     TRACE("%d\n", MAX_WAVEINDRV);
1558     return MAX_WAVEINDRV;
1559 }
1560
1561 /**************************************************************************
1562  *                              widDevInterfaceSize             [internal]
1563  */
1564 static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1565 {
1566     TRACE("(%u, %p)\n", wDevID, dwParam1);
1567                                                                                                        
1568                                                                                                        
1569     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
1570                                     NULL, 0 ) * sizeof(WCHAR);
1571     return MMSYSERR_NOERROR;
1572 }
1573
1574 /**************************************************************************
1575  *                              widDevInterface                 [internal]
1576  */
1577 static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1578 {
1579     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
1580                                         NULL, 0 ) * sizeof(WCHAR))
1581     {
1582         MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
1583                             dwParam1, dwParam2 / sizeof(WCHAR));
1584         return MMSYSERR_NOERROR;
1585     }
1586     return MMSYSERR_INVALPARAM;
1587 }
1588
1589 /**************************************************************************
1590  *                      widNotifyClient                 [internal]
1591  */
1592 static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
1593 {
1594     TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2);
1595
1596     switch (wMsg) {
1597     case WIM_OPEN:
1598     case WIM_CLOSE:
1599     case WIM_DATA:
1600         if (wwi->wFlags != DCB_NULL &&
1601             !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
1602                             (HDRVR)wwi->waveDesc.hWave, wMsg,
1603                             wwi->waveDesc.dwInstance, dwParam1, dwParam2)) {
1604             WARN("can't notify client !\n");
1605             return MMSYSERR_ERROR;
1606         }
1607         break;
1608     default:
1609         FIXME("Unknown callback message %u\n", wMsg);
1610         return MMSYSERR_INVALPARAM;
1611     }
1612     return MMSYSERR_NOERROR;
1613 }
1614
1615 /**************************************************************************
1616  *                      widGetDevCaps                           [internal]
1617  */
1618 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
1619 {
1620     TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
1621
1622     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1623
1624     if (wDevID >= MAX_WAVEINDRV) {
1625         TRACE("MAX_WAVINDRV reached !\n");
1626         return MMSYSERR_BADDEVICEID;
1627     }
1628
1629     memcpy(lpCaps, &WInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1630     return MMSYSERR_NOERROR;
1631 }
1632
1633 /**************************************************************************
1634  *                              widRecorder                     [internal]
1635  */
1636 static  DWORD   CALLBACK        widRecorder(LPVOID pmt)
1637 {
1638     WORD                uDevID = (DWORD)pmt;
1639     WINE_WAVEIN*        wwi = (WINE_WAVEIN*)&WInDev[uDevID];
1640     WAVEHDR*            lpWaveHdr;
1641     DWORD               dwSleepTime;
1642     DWORD               bytesRead;
1643     int                 dwBufferSpace;
1644     enum win_wm_message msg;
1645     DWORD               param;
1646     HANDLE              ev;
1647
1648     SetEvent(wwi->hStartUpEvent);
1649
1650     /* make sleep time to be # of ms to record one packet */
1651     dwSleepTime = ((1 << (wwi->packetSettings & 0xFFFF)) * 1000) / wwi->format.wf.nAvgBytesPerSec;
1652     TRACE("sleeptime=%d ms\n", dwSleepTime);
1653
1654     for(;;) {
1655         /* Oddly enough, dwBufferSpace is sometimes negative.... 
1656          * 
1657          * NOTE: If you remove this call to arts_stream_get() and
1658          * remove the && (dwBufferSpace > 0) the code will still
1659          * function correctly. I don't know which way is
1660          * faster/better.
1661          */
1662         dwBufferSpace = arts_stream_get(wwi->record_stream, ARTS_P_BUFFER_SPACE);
1663         TRACE("wwi->lpQueuePtr=(%p), wwi->state=(%d), dwBufferSpace=(%d)\n",wwi->lpQueuePtr,wwi->state,dwBufferSpace);
1664
1665         /* read all data is arts input buffer. */
1666         if ((wwi->lpQueuePtr != NULL) && (wwi->state == WINE_WS_PLAYING) && (dwBufferSpace > 0))
1667         {
1668             lpWaveHdr = wwi->lpQueuePtr;
1669                 
1670             TRACE("read as much as we can\n");
1671             while(wwi->lpQueuePtr)
1672             {
1673                 TRACE("attempt to read %d bytes\n",lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
1674                 bytesRead = arts_read(wwi->record_stream,
1675                                       lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
1676                                       lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
1677                 TRACE("bytesRead=%d\n",bytesRead);
1678                 if (bytesRead==0) break;
1679                 
1680                 lpWaveHdr->dwBytesRecorded      += bytesRead;
1681                 wwi->dwRecordedTotal            += bytesRead;
1682
1683                 /* buffer full. notify client */
1684                 if (lpWaveHdr->dwBytesRecorded >= lpWaveHdr->dwBufferLength)
1685                 {
1686                     /* must copy the value of next waveHdr, because we have no idea of what
1687                      * will be done with the content of lpWaveHdr in callback
1688                      */
1689                     LPWAVEHDR   lpNext = lpWaveHdr->lpNext;
1690
1691                     TRACE("waveHdr full.\n");
1692                     
1693                     lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1694                     lpWaveHdr->dwFlags |=  WHDR_DONE;
1695                     
1696                     widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
1697                     lpWaveHdr = wwi->lpQueuePtr = lpNext;
1698                 }
1699             }
1700         }
1701
1702         /* wait for dwSleepTime or an event in thread's queue */
1703         WaitForSingleObject(wwi->msgRing.msg_event, dwSleepTime);
1704
1705         while (ARTS_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev))
1706         {
1707             TRACE("msg=%s param=0x%x\n",wodPlayerCmdString[msg - WM_USER - 1], param);
1708             switch(msg) {
1709             case WINE_WM_PAUSING:
1710                 wwi->state = WINE_WS_PAUSED;
1711
1712                 /* Put code here to "pause" arts recording
1713                  */
1714
1715                 SetEvent(ev);
1716                 break;
1717             case WINE_WM_STARTING:
1718                 wwi->state = WINE_WS_PLAYING;
1719
1720                 /* Put code here to "start" arts recording
1721                  */
1722
1723                 SetEvent(ev);
1724                 break;
1725             case WINE_WM_HEADER:
1726                 lpWaveHdr = (LPWAVEHDR)param;
1727                 /* insert buffer at end of queue */
1728                 {
1729                     LPWAVEHDR* wh;
1730                     int num_headers = 0;
1731                     for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext))
1732                     {
1733                         num_headers++;
1734
1735                     }
1736                     *wh=lpWaveHdr;
1737                 }
1738                 break;
1739             case WINE_WM_STOPPING:
1740                 if (wwi->state != WINE_WS_STOPPED)
1741                 {
1742
1743                     /* Put code here to "stop" arts recording
1744                      */
1745
1746                     /* return current buffer to app */
1747                     lpWaveHdr = wwi->lpQueuePtr;
1748                     if (lpWaveHdr)
1749                     {
1750                         LPWAVEHDR lpNext = lpWaveHdr->lpNext;
1751                         TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
1752                         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1753                         lpWaveHdr->dwFlags |= WHDR_DONE;
1754                         widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
1755                         wwi->lpQueuePtr = lpNext;
1756                     }
1757                 }
1758                 wwi->state = WINE_WS_STOPPED;
1759                 SetEvent(ev);
1760                 break;
1761             case WINE_WM_RESETTING:
1762                 wwi->state = WINE_WS_STOPPED;
1763                 wwi->dwRecordedTotal = 0;
1764
1765                 /* return all buffers to the app */
1766                 for (lpWaveHdr = wwi->lpQueuePtr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext) {
1767                     TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
1768                     lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1769                     lpWaveHdr->dwFlags |= WHDR_DONE;
1770
1771                     widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
1772                 }
1773                 wwi->lpQueuePtr = NULL; 
1774                 SetEvent(ev);
1775                 break;
1776             case WINE_WM_CLOSING:
1777                 wwi->hThread = 0;
1778                 wwi->state = WINE_WS_CLOSED;
1779                 SetEvent(ev);
1780                 ExitThread(0);
1781                 /* shouldn't go here */
1782             default:
1783                 FIXME("unknown message %d\n", msg);
1784                 break;
1785             }
1786         }
1787     }
1788     ExitThread(0);
1789     /* just for not generating compilation warnings... should never be executed */
1790     return 0;
1791 }
1792
1793 /**************************************************************************
1794  *                              widOpen                         [internal]
1795  */
1796 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1797 {
1798     WINE_WAVEIN*        wwi;
1799
1800     TRACE("(%u, %p %08X);\n",wDevID, lpDesc, dwFlags);
1801     if (lpDesc == NULL) {
1802         WARN("Invalid Parametr (lpDesc == NULL)!\n");
1803         return MMSYSERR_INVALPARAM;
1804     }
1805
1806     if (wDevID >= MAX_WAVEINDRV) {
1807         TRACE ("MAX_WAVEINDRV reached !\n");
1808         return MMSYSERR_BADDEVICEID;
1809     }
1810
1811     /* if this device is already open tell the app that it is allocated */
1812     if(WInDev[wDevID].record_stream != (arts_stream_t*)-1)
1813     {
1814         TRACE("device already allocated\n");
1815         return MMSYSERR_ALLOCATED;
1816     }
1817
1818     /* only PCM format is support so far... */
1819     if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1820         lpDesc->lpFormat->nChannels == 0 ||
1821         lpDesc->lpFormat->nSamplesPerSec < DSBFREQUENCY_MIN ||
1822         lpDesc->lpFormat->nSamplesPerSec > DSBFREQUENCY_MAX ||
1823         (lpDesc->lpFormat->wBitsPerSample!=8 && lpDesc->lpFormat->wBitsPerSample!=16)) {
1824         WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1825              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1826              lpDesc->lpFormat->nSamplesPerSec);
1827         return WAVERR_BADFORMAT;
1828     }
1829
1830     if (dwFlags & WAVE_FORMAT_QUERY) {
1831         TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
1832              lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1833              lpDesc->lpFormat->nSamplesPerSec);
1834         return MMSYSERR_NOERROR;
1835     }
1836
1837     wwi = &WInDev[wDevID];
1838
1839     /* direct sound not supported, ignore the flag */
1840     dwFlags &= ~WAVE_DIRECTSOUND;
1841
1842     wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1843     
1844     memcpy(&wwi->waveDesc, lpDesc,           sizeof(WAVEOPENDESC));
1845     memcpy(&wwi->format,   lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
1846
1847     if (wwi->format.wBitsPerSample == 0) {
1848         WARN("Resetting zerod wBitsPerSample\n");
1849         wwi->format.wBitsPerSample = 8 *
1850             (wwi->format.wf.nAvgBytesPerSec /
1851              wwi->format.wf.nSamplesPerSec) /
1852             wwi->format.wf.nChannels;
1853     }
1854
1855     wwi->record_stream = arts_record_stream(wwi->format.wf.nSamplesPerSec,
1856                                             wwi->format.wBitsPerSample,
1857                                             wwi->format.wf.nChannels,
1858                                             "winearts");
1859     TRACE("(wwi->record_stream=%p)\n",wwi->record_stream);
1860     wwi->state = WINE_WS_STOPPED;
1861
1862     wwi->packetSettings = arts_stream_set(wwi->record_stream, ARTS_P_PACKET_SETTINGS, WAVEIN_PACKET_SETTINGS);
1863     TRACE("Tried to set ARTS_P_PACKET_SETTINGS to (%x), actually set to (%x)\n", WAVEIN_PACKET_SETTINGS, wwi->packetSettings);
1864     TRACE("Buffer size is now (%d)\n", arts_stream_get(wwi->record_stream, ARTS_P_BUFFER_SIZE));
1865
1866     if (wwi->lpQueuePtr) {
1867         WARN("Should have an empty queue (%p)\n", wwi->lpQueuePtr);
1868         wwi->lpQueuePtr = NULL;
1869     }
1870     arts_stream_set(wwi->record_stream, ARTS_P_BLOCKING, 0);    /* disable blocking on this stream */
1871
1872     if(!wwi->record_stream) return MMSYSERR_ALLOCATED;
1873
1874     wwi->dwRecordedTotal = 0;
1875     wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1876
1877     ARTS_InitRingMessage(&wwi->msgRing);
1878
1879     /* create recorder thread */
1880     if (!(dwFlags & WAVE_DIRECTSOUND)) {
1881         wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1882         wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD)wDevID, 0, &(wwi->dwThreadID));
1883         if (wwi->hThread)
1884             SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL);
1885         WaitForSingleObject(wwi->hStartUpEvent, INFINITE);
1886         CloseHandle(wwi->hStartUpEvent);
1887     } else {
1888         wwi->hThread = INVALID_HANDLE_VALUE;
1889         wwi->dwThreadID = 0;
1890     }
1891     wwi->hStartUpEvent = INVALID_HANDLE_VALUE;
1892
1893     TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
1894           wwi->format.wBitsPerSample, wwi->format.wf.nAvgBytesPerSec,
1895           wwi->format.wf.nSamplesPerSec, wwi->format.wf.nChannels,
1896           wwi->format.wf.nBlockAlign);
1897     return widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
1898 }
1899
1900 /**************************************************************************
1901  *                              widClose                        [internal]
1902  */
1903 static DWORD widClose(WORD wDevID)
1904 {
1905     WINE_WAVEIN*        wwi;
1906
1907     TRACE("(%u);\n", wDevID);
1908     if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
1909         WARN("can't close !\n");
1910         return MMSYSERR_INVALHANDLE;
1911     }
1912
1913     wwi = &WInDev[wDevID];
1914
1915     if (wwi->lpQueuePtr != NULL) {
1916         WARN("still buffers open !\n");
1917         return WAVERR_STILLPLAYING;
1918     }
1919
1920     ARTS_AddRingMessage(&wwi->msgRing, WINE_WM_CLOSING, 0, TRUE);
1921     ARTS_CloseWaveInDevice(wwi);
1922     wwi->state = WINE_WS_CLOSED;
1923     ARTS_DestroyRingMessage(&wwi->msgRing);
1924     return widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
1925 }
1926
1927 /**************************************************************************
1928  *                              widAddBuffer            [internal]
1929  */
1930 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1931 {
1932     TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
1933
1934     if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
1935         WARN("can't do it !\n");
1936         return MMSYSERR_INVALHANDLE;
1937     }
1938     if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1939         TRACE("never been prepared !\n");
1940         return WAVERR_UNPREPARED;
1941     }
1942     if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1943         TRACE("header already in use !\n");
1944         return WAVERR_STILLPLAYING;
1945     }
1946
1947     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1948     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1949     lpWaveHdr->dwBytesRecorded = 0;
1950     lpWaveHdr->lpNext = NULL;
1951
1952     ARTS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE);
1953     return MMSYSERR_NOERROR;
1954 }
1955
1956 /**************************************************************************
1957  *                      widStart                                [internal]
1958  */
1959 static DWORD widStart(WORD wDevID)
1960 {
1961     TRACE("(%u);\n", wDevID);
1962     if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
1963         WARN("can't start recording !\n");
1964         return MMSYSERR_INVALHANDLE;
1965     }
1966
1967     ARTS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STARTING, 0, TRUE);
1968     return MMSYSERR_NOERROR;
1969 }
1970
1971 /**************************************************************************
1972  *                      widStop                                 [internal]
1973  */
1974 static DWORD widStop(WORD wDevID)
1975 {
1976     TRACE("(%u);\n", wDevID);
1977     if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
1978         WARN("can't stop !\n");
1979         return MMSYSERR_INVALHANDLE;
1980     }
1981
1982     ARTS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STOPPING, 0, TRUE);
1983
1984     return MMSYSERR_NOERROR;
1985 }
1986
1987 /**************************************************************************
1988  *                      widReset                                [internal]
1989  */
1990 static DWORD widReset(WORD wDevID)
1991 {
1992     TRACE("(%u);\n", wDevID);
1993     if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
1994         WARN("can't reset !\n");
1995         return MMSYSERR_INVALHANDLE;
1996     }
1997     ARTS_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
1998     return MMSYSERR_NOERROR;
1999 }
2000
2001 /**************************************************************************
2002  *                              widMessage (WINEARTS.6)
2003  */
2004 DWORD WINAPI ARTS_widMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
2005                             DWORD dwParam1, DWORD dwParam2)
2006 {
2007     TRACE("(%u, %04X, %08X, %08X, %08X);\n",
2008           wDevID, wMsg, dwUser, dwParam1, dwParam2);
2009     switch (wMsg) {
2010     case DRVM_INIT:
2011     case DRVM_EXIT:
2012     case DRVM_ENABLE:
2013     case DRVM_DISABLE:
2014         /* FIXME: Pretend this is supported */
2015         return 0;
2016     case WIDM_OPEN:             return widOpen          (wDevID, (LPWAVEOPENDESC)dwParam1,      dwParam2);
2017     case WIDM_CLOSE:            return widClose         (wDevID);
2018     case WIDM_ADDBUFFER:        return widAddBuffer     (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
2019     case WIDM_PREPARE:          return MMSYSERR_NOTSUPPORTED;
2020     case WIDM_UNPREPARE:        return MMSYSERR_NOTSUPPORTED;
2021     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (LPWAVEINCAPSW)dwParam1,       dwParam2);
2022     case WIDM_GETNUMDEVS:       return widGetNumDevs    ();
2023     case WIDM_RESET:            return widReset         (wDevID);
2024     case WIDM_START:            return widStart         (wDevID);
2025     case WIDM_STOP:             return widStop          (wDevID);
2026     case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize       (wDevID, (LPDWORD)dwParam1);
2027     case DRV_QUERYDEVICEINTERFACE:     return widDevInterface           (wDevID, (PWCHAR)dwParam1, dwParam2);
2028     default:
2029         FIXME("unknown message %d!\n", wMsg);
2030     }
2031     return MMSYSERR_NOTSUPPORTED;
2032 }
2033
2034 /*======================================================================*
2035  *                  Low level DSOUND implementation                     *
2036  *======================================================================*/
2037 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
2038 {
2039     /* we can't perform memory mapping as we don't have a file stream
2040         interface with arts like we do with oss */
2041     MESSAGE("This sound card's driver does not support direct access\n");
2042     MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
2043     return MMSYSERR_NOTSUPPORTED;
2044 }
2045
2046 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
2047 {
2048     memset(desc, 0, sizeof(*desc));
2049     strcpy(desc->szDesc, "Wine aRts DirectSound Driver");
2050     strcpy(desc->szDrvname, "winearts.drv");
2051     return MMSYSERR_NOERROR;
2052 }
2053
2054 #else /* !HAVE_ARTS */
2055
2056 /**************************************************************************
2057  *                              wodMessage (WINEARTS.@)
2058  */
2059 DWORD WINAPI ARTS_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2060                             DWORD dwParam1, DWORD dwParam2)
2061 {
2062     FIXME("(%u, %04X, %08X, %08X, %08X):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2063     return MMSYSERR_NOTENABLED;
2064 }
2065
2066 /**************************************************************************
2067  *                              widMessage (WINEARTS.6)
2068  */
2069 DWORD WINAPI ARTS_widMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
2070                             DWORD dwParam1, DWORD dwParam2)
2071 {
2072     FIXME("(%u, %04X, %08X, %08X, %08X):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2073     return MMSYSERR_NOTENABLED;
2074 }
2075
2076 #endif /* HAVE_ARTS */