Started coding 32 bit MCI handling.
[wine] / multimedia / audio.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*                                 
3  * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
4  *
5  * Copyright 1994 Martin Ayotte
6  */
7 /*
8  * FIXME:
9  *      - record/play should and must be done asynchronous
10  *      - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
11  */
12
13 #define EMULATE_SB16
14
15 #define DEBUG_MCIWAVE
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include "windows.h"
23 #include "user.h"
24 #include "driver.h"
25 #include "mmsystem.h"
26 #include "heap.h"
27 #include "ldt.h"
28 #include "debug.h"
29
30 #ifdef HAVE_OSS
31
32 #ifdef HAVE_MACHINE_SOUNDCARD_H
33 # include <machine/soundcard.h>
34 #endif
35 #ifdef HAVE_SYS_SOUNDCARD_H
36 # include <sys/soundcard.h>
37 #endif
38
39 #define SOUND_DEV "/dev/dsp"
40 #define MIXER_DEV "/dev/mixer"
41
42 #ifdef SOUND_VERSION
43 #define IOCTL(a,b,c)            ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
44 #else
45 #define IOCTL(a,b,c)            (c = ioctl(a,b,c) )
46 #endif
47
48 #define MAX_WAVOUTDRV   (1)
49 #define MAX_WAVINDRV    (1)
50 #define MAX_MCIWAVDRV   (1)
51
52 typedef struct {
53     int                         unixdev;
54     int                         state;
55     DWORD                       bufsize;
56     WAVEOPENDESC                waveDesc;
57     WORD                        wFlags;
58     PCMWAVEFORMAT               Format;
59     LPWAVEHDR                   lpQueueHdr;
60     DWORD                       dwTotalPlayed;
61 } WINE_WAVEOUT;
62
63 typedef struct {
64     int                         unixdev;
65     int                         state;
66     DWORD                       bufsize;        /* OpenSound '/dev/dsp' give us that size */
67     WAVEOPENDESC                waveDesc;
68     WORD                        wFlags;
69     PCMWAVEFORMAT               Format;
70     LPWAVEHDR                   lpQueueHdr;
71     DWORD                       dwTotalRecorded;
72 } WINE_WAVEIN;
73
74 typedef struct {
75         int                     nUseCount;      /* Incremented for each shared open */
76         BOOL16                  fShareable;     /* TRUE if first open was shareable */
77         WORD                    wNotifyDeviceID;/* MCI device ID with a pending notification */
78         HANDLE16                hCallback;      /* Callback handle for pending notification */
79         HMMIO32                 hFile;          /* mmio file handle open as Element */
80         MCI_WAVE_OPEN_PARMS16   openParms;
81         PCMWAVEFORMAT           WaveFormat;
82         WAVEHDR                 WaveHdr;
83         BOOL16                  fInput;         /* FALSE = Output, TRUE = Input */
84 } WINE_MCIWAVE;
85
86 static WINE_WAVEOUT     WOutDev[MAX_WAVOUTDRV];
87 static WINE_WAVEIN      WInDev[MAX_WAVOUTDRV];
88 static WINE_MCIWAVE     MCIWavDev[MAX_MCIWAVDRV];
89
90 /**************************************************************************
91  *                      WAVE_NotifyClient                       [internal]
92  */
93 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg, 
94                                DWORD dwParam1, DWORD dwParam2)
95 {
96     TRACE(mciwave,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
97     
98     switch (wMsg) {
99     case WOM_OPEN:
100     case WOM_CLOSE:
101     case WOM_DONE:
102         if (wDevID > MAX_WAVOUTDRV) return MCIERR_INTERNAL;
103         
104         if (WOutDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
105                                                                   WOutDev[wDevID].waveDesc.dwCallBack, 
106                                                                   WOutDev[wDevID].wFlags, 
107                                                                   WOutDev[wDevID].waveDesc.hWave, 
108                                                                   wMsg, 
109                                                                   WOutDev[wDevID].waveDesc.dwInstance, 
110                                                                   dwParam1, 
111                                                                   dwParam2)) {
112             WARN(mciwave, "can't notify client !\n");
113             return MMSYSERR_NOERROR;
114         }
115         break;
116         
117     case WIM_OPEN:
118     case WIM_CLOSE:
119     case WIM_DATA:
120         if (wDevID > MAX_WAVINDRV) return MCIERR_INTERNAL;
121         
122         if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
123                                                                  WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, 
124                                                                  WInDev[wDevID].waveDesc.hWave, wMsg, 
125                                                                  WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) {
126             WARN(mciwave, "can't notify client !\n");
127             return MMSYSERR_NOERROR;
128         }
129         break;
130     }
131     return 0;
132 }
133
134
135 /**************************************************************************
136  *                      WAVE_mciOpen                            [internal]
137  */
138 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, void* lp, BOOL32 is32)
139 {
140     LPPCMWAVEFORMAT     lpWaveFormat;
141     WAVEOPENDESC        waveDesc;
142     DWORD               dwRet;
143     DWORD               dwDeviceID;
144     
145     TRACE(mciwave,"(%04X, %08lX, %p)\n", wDevID, dwFlags, lp);
146     if (lp == NULL) return MCIERR_INTERNAL;
147     
148     if (is32)   dwDeviceID = ((LPMCI_OPEN_PARMS32A)lp)->wDeviceID;
149     else        dwDeviceID = ((LPMCI_OPEN_PARMS16)lp)->wDeviceID;
150     
151     if (MCIWavDev[wDevID].nUseCount > 0) {
152         /* The driver already open on this channel */
153         /* If the driver was opened shareable before and this open specifies */
154         /* shareable then increment the use count */
155         if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
156             ++MCIWavDev[wDevID].nUseCount;
157         else
158             return MCIERR_MUST_USE_SHAREABLE;
159     } else {
160         MCIWavDev[wDevID].nUseCount = 1;
161         MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
162     }
163     
164     MCIWavDev[wDevID].fInput = FALSE;
165     
166     TRACE(mciwave,"wDevID=%04X\n", wDevID);
167     TRACE(mciwave,"before OPEN_ELEMENT\n");
168     if (dwFlags & MCI_OPEN_ELEMENT) {
169         LPSTR                                   lpstrElementName;       
170         
171         if (is32)       lpstrElementName = ((LPMCI_WAVE_OPEN_PARMS32A)lp)->lpstrElementName;
172         else                    lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(((LPMCI_WAVE_OPEN_PARMS16)lp)->lpstrElementName);
173         
174         TRACE(mciwave,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
175         if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
176             MCIWavDev[wDevID].hFile = mmioOpen32A(lpstrElementName, NULL, 
177                                                   MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
178             if (MCIWavDev[wDevID].hFile == 0) {
179                 WARN(mciwave, "can't find file='%s' !\n", lpstrElementName);
180                 return MCIERR_FILE_NOT_FOUND;
181             }
182         }
183         else 
184             MCIWavDev[wDevID].hFile = 0;
185     }
186     TRACE(mciwave,"hFile=%u\n", MCIWavDev[wDevID].hFile);
187     memcpy(&MCIWavDev[wDevID].openParms, lp, sizeof(MCI_WAVE_OPEN_PARMS16));
188     MCIWavDev[wDevID].wNotifyDeviceID = dwDeviceID;
189     lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
190     
191     waveDesc.hWave = 0;
192     /*
193       lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
194       lpWaveFormat->wBitsPerSample = 8;
195       lpWaveFormat->wf.nChannels = 1;
196       lpWaveFormat->wf.nSamplesPerSec = 11025;
197       lpWaveFormat->wf.nAvgBytesPerSec = 11025;
198       lpWaveFormat->wf.nBlockAlign = 1;
199     */
200     if (MCIWavDev[wDevID].hFile != 0) {
201         MMCKINFO        mmckInfo;
202         MMCKINFO        ckMainRIFF;
203         if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0)
204             return MCIERR_INTERNAL;
205         TRACE(mciwave, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
206               (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
207               ckMainRIFF.cksize);
208         if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
209             (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
210             return MCIERR_INTERNAL;
211         mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
212         if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
213             return MCIERR_INTERNAL;
214         TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
215               (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
216               mmckInfo.cksize);
217         if (mmioRead32(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
218                        (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT))
219             return MCIERR_INTERNAL;
220         mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
221         if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
222             return MCIERR_INTERNAL;
223         TRACE(mciwave,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
224               (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
225               mmckInfo.cksize);
226         TRACE(mciwave, "nChannels=%d nSamplesPerSec=%ld\n",
227               lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
228         lpWaveFormat->wBitsPerSample = 0;
229     }
230     lpWaveFormat->wf.nAvgBytesPerSec = 
231         lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
232     waveDesc.lpFormat = (LPWAVEFORMAT)lpWaveFormat;
233     
234     /*
235       By default the device will be opened for output, the MCI_CUE function is there to
236       change from output to input and back
237     */
238     
239     dwRet=wodMessage(wDevID,WODM_OPEN,0,(DWORD)&waveDesc,CALLBACK_NULL);
240     return 0;
241 }
242
243 /**************************************************************************
244  *                               WAVE_mciCue             [internal]
245  */
246
247 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
248 {
249     /*
250       FIXME
251       
252       This routine is far from complete. At the moment only a check is done on the
253       MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
254       is the default.
255       
256       The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
257       are ignored
258     */
259     
260     DWORD               dwRet;
261     WAVEOPENDESC        waveDesc;
262     
263     TRACE(mciwave,"(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
264     
265     /* always close elements ? */
266     
267     if (MCIWavDev[wDevID].hFile != 0) {
268         mmioClose32(MCIWavDev[wDevID].hFile, 0);
269         MCIWavDev[wDevID].hFile = 0;
270     }
271     
272     dwRet = MMSYSERR_NOERROR;  /* assume success */
273     if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
274         /* FIXME this is just a hack WOutDev should be hidden here */
275         memcpy(&waveDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
276         
277         dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
278         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
279         dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
280         MCIWavDev[wDevID].fInput = TRUE;
281     }
282     else if (MCIWavDev[wDevID].fInput) {
283         /* FIXME this is just a hack WInDev should be hidden here */
284         memcpy(&waveDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
285         
286         dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
287         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
288         dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
289         MCIWavDev[wDevID].fInput = FALSE;
290     }
291     return dwRet;
292 }
293
294 /**************************************************************************
295  *                              WAVE_mciClose           [internal]
296  */
297 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
298 {
299     DWORD               dwRet;
300     
301     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
302     MCIWavDev[wDevID].nUseCount--;
303     if (MCIWavDev[wDevID].nUseCount == 0) {
304         if (MCIWavDev[wDevID].hFile != 0) {
305             mmioClose32(MCIWavDev[wDevID].hFile, 0);
306             MCIWavDev[wDevID].hFile = 0;
307         }
308         if (MCIWavDev[wDevID].fInput)
309             dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
310         else
311             dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
312         
313         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
314     }
315     return 0;
316 }
317
318
319 /**************************************************************************
320  *                              WAVE_mciPlay            [internal]
321  */
322 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
323 {
324     int         start, end;
325     LONG                bufsize, count;
326     HGLOBAL16   hData;
327     LPWAVEHDR   lpWaveHdr;
328     DWORD               dwRet;
329     
330     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
331     
332     if (MCIWavDev[wDevID].fInput) {
333         WARN(mciwave, "cannot play on input device\n");
334         return MCIERR_NONAPPLICABLE_FUNCTION;
335     }
336     
337     if (MCIWavDev[wDevID].hFile == 0) {
338         WARN(mciwave, "can't find file='%08lx' !\n",
339              MCIWavDev[wDevID].openParms.lpstrElementName);
340         return MCIERR_FILE_NOT_FOUND;
341     }
342     start = 1;          end = 99999;
343     if (dwFlags & MCI_FROM) {
344         start = lpParms->dwFrom; 
345         TRACE(mciwave, "MCI_FROM=%d \n", start);
346     }
347     if (dwFlags & MCI_TO) {
348         end = lpParms->dwTo;
349         TRACE(mciwave,"MCI_TO=%d \n", end);
350     }
351 #if 0
352     if (dwFlags & MCI_NOTIFY) {
353         TRACE(mciwave, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
354         switch(fork()) {
355         case -1:
356             WARN(mciwave, "Can't 'fork' process !\n");
357             break;
358         case 0:
359             break;         
360         default:
361             TRACE(mciwave,"process started ! return to caller...\n");
362             return 0;
363         }
364     }
365 #endif
366     bufsize = 64000;
367     lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
368     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
369     lpWaveHdr->lpData = (LPSTR) GlobalLock16(hData);
370     lpWaveHdr->dwUser = 0L;
371     lpWaveHdr->dwFlags = 0L;
372     lpWaveHdr->dwLoops = 0L;
373     dwRet=wodMessage(wDevID,WODM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
374     while(TRUE) {
375         count = mmioRead32(MCIWavDev[wDevID].hFile, lpWaveHdr->lpData, bufsize);
376         TRACE(mciwave,"mmioRead bufsize=%ld count=%ld\n", bufsize, count);
377         if (count < 1) break;
378         lpWaveHdr->dwBufferLength = count;
379         /*              lpWaveHdr->dwBytesRecorded = count; */
380         TRACE(mciwave,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
381               lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
382         dwRet=wodMessage(wDevID,WODM_WRITE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
383     }
384     dwRet = wodMessage(wDevID,WODM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
385     if (lpWaveHdr->lpData != NULL) {
386         GlobalUnlock16(hData);
387         GlobalFree16(hData);
388         lpWaveHdr->lpData = NULL;
389     }
390     if (dwFlags & MCI_NOTIFY) {
391         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
392         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
393                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
394     }
395     return 0;
396 }
397
398
399 /**************************************************************************
400  *                              WAVE_mciRecord                  [internal]
401  */
402 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
403 {
404     int                 start, end;
405     LONG                bufsize;
406     HGLOBAL16           hData;
407     LPWAVEHDR           lpWaveHdr;
408     DWORD               dwRet;
409     
410     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
411     
412     if (!MCIWavDev[wDevID].fInput) {
413         WARN(mciwave, "cannot record on output device\n");
414         return MCIERR_NONAPPLICABLE_FUNCTION;
415     }
416     
417     if (MCIWavDev[wDevID].hFile == 0) {
418         WARN(mciwave, "can't find file='%08lx' !\n", 
419              MCIWavDev[wDevID].openParms.lpstrElementName);
420         return MCIERR_FILE_NOT_FOUND;
421     }
422     start = 1;  end = 99999;
423     if (dwFlags & MCI_FROM) {
424         start = lpParms->dwFrom; 
425         TRACE(mciwave, "MCI_FROM=%d \n", start);
426     }
427     if (dwFlags & MCI_TO) {
428         end = lpParms->dwTo;
429         TRACE(mciwave,"MCI_TO=%d \n", end);
430     }
431     bufsize = 64000;
432     lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
433     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
434     lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
435     lpWaveHdr->dwBufferLength = bufsize;
436     lpWaveHdr->dwUser = 0L;
437     lpWaveHdr->dwFlags = 0L;
438     lpWaveHdr->dwLoops = 0L;
439     dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
440     TRACE(mciwave,"after WIDM_PREPARE \n");
441     while(TRUE) {
442         lpWaveHdr->dwBytesRecorded = 0;
443         dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
444         TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
445               lpWaveHdr, lpWaveHdr->dwBytesRecorded);
446         if (lpWaveHdr->dwBytesRecorded == 0) break;
447     }
448     TRACE(mciwave,"before WIDM_UNPREPARE \n");
449     dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
450     TRACE(mciwave,"after WIDM_UNPREPARE \n");
451     if (lpWaveHdr->lpData != NULL) {
452         GlobalUnlock16(hData);
453         GlobalFree16(hData);
454         lpWaveHdr->lpData = NULL;
455     }
456     if (dwFlags & MCI_NOTIFY) {
457         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
458         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
459                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
460     }
461     return 0;
462 }
463
464
465 /**************************************************************************
466  *                              WAVE_mciStop                    [internal]
467  */
468 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
469 {
470     DWORD dwRet;
471     
472     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
473     if (lpParms == NULL) return MCIERR_INTERNAL;
474     if (MCIWavDev[wDevID].fInput)
475         dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
476     else
477         dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
478     
479     return dwRet;
480 }
481
482
483 /**************************************************************************
484  *                              WAVE_mciPause                   [internal]
485  */
486 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
487 {
488     DWORD dwRet;
489     
490     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
491     if (lpParms == NULL) return MCIERR_INTERNAL;
492     if (MCIWavDev[wDevID].fInput)
493         dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
494     else
495         dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
496     
497     return dwRet;
498 }
499
500
501 /**************************************************************************
502  *                              WAVE_mciResume                  [internal]
503  */
504 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
505 {
506     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
507     if (lpParms == NULL) return MCIERR_INTERNAL;
508     return 0;
509 }
510
511
512 /**************************************************************************
513  *                              WAVE_mciSet                     [internal]
514  */
515 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
516 {
517     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
518     if (lpParms == NULL) return MCIERR_INTERNAL;
519     TRACE(mciwave, "dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
520     TRACE(mciwave, "dwAudio=%08lX\n", lpParms->dwAudio);
521     if (dwFlags & MCI_SET_TIME_FORMAT) {
522         switch (lpParms->dwTimeFormat) {
523         case MCI_FORMAT_MILLISECONDS:
524             TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
525             break;
526         case MCI_FORMAT_BYTES:
527             TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
528             break;
529         case MCI_FORMAT_SAMPLES:
530             TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
531             break;
532         default:
533             WARN(mciwave, "bad time format !\n");
534             return MCIERR_BAD_TIME_FORMAT;
535         }
536     }
537     if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
538     if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
539     if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
540     if (dwFlags & MCI_SET_AUDIO) 
541         TRACE(mciwave,"MCI_SET_AUDIO !\n");
542     if (dwFlags && MCI_SET_ON) {
543         TRACE(mciwave,"MCI_SET_ON !\n");
544         if (dwFlags && MCI_SET_AUDIO_LEFT) 
545             TRACE(mciwave,"MCI_SET_AUDIO_LEFT !\n");
546         if (dwFlags && MCI_SET_AUDIO_RIGHT) 
547             TRACE(mciwave,"MCI_SET_AUDIO_RIGHT !\n");
548     }
549     if (dwFlags & MCI_SET_OFF) 
550         TRACE(mciwave,"MCI_SET_OFF !\n");
551     if (dwFlags & MCI_WAVE_INPUT) 
552         TRACE(mciwave,"MCI_WAVE_INPUT !\n");
553     if (dwFlags & MCI_WAVE_OUTPUT) 
554         TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
555     if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
556         TRACE(mciwave,"MCI_WAVE_SET_ANYINPUT !\n");
557     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
558         TRACE(mciwave,"MCI_WAVE_SET_ANYOUTPUT !\n");
559     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
560         TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
561     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
562         TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
563     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
564         TRACE(mciwave,"MCI_WAVE_SET_BLOCKALIGN !\n");
565     if (dwFlags & MCI_WAVE_SET_CHANNELS) 
566         TRACE(mciwave,"MCI_WAVE_SET_CHANNELS !\n");
567     if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
568         TRACE(mciwave,"MCI_WAVE_SET_FORMATTAG !\n");
569     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
570         TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
571     return 0;
572 }
573
574
575 /**************************************************************************
576  *                              WAVE_mciStatus          [internal]
577  */
578 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
579 {
580     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
581     if (lpParms == NULL) return MCIERR_INTERNAL;
582     if (dwFlags & MCI_STATUS_ITEM) {
583         switch(lpParms->dwItem) {
584         case MCI_STATUS_CURRENT_TRACK:
585             lpParms->dwReturn = 1;
586             break;
587         case MCI_STATUS_LENGTH:
588             lpParms->dwReturn = 5555;
589             if (dwFlags & MCI_TRACK) {
590                 lpParms->dwTrack = 1;
591                 lpParms->dwReturn = 2222;
592             }
593             break;
594         case MCI_STATUS_MODE:
595             lpParms->dwReturn = MCI_MODE_STOP;
596             break;
597         case MCI_STATUS_MEDIA_PRESENT:
598             TRACE(mciwave,"MCI_STATUS_MEDIA_PRESENT !\n");
599             lpParms->dwReturn = TRUE;
600             break;
601         case MCI_STATUS_NUMBER_OF_TRACKS:
602             lpParms->dwReturn = 1;
603             break;
604         case MCI_STATUS_POSITION:
605             lpParms->dwReturn = 3333;
606             if (dwFlags & MCI_STATUS_START)
607                 lpParms->dwItem = 1;
608             if (dwFlags & MCI_TRACK) {
609                 lpParms->dwTrack = 1;
610                 lpParms->dwReturn = 777;
611             }
612             break;
613         case MCI_STATUS_READY:
614             TRACE(mciwave,"MCI_STATUS_READY !\n");
615             lpParms->dwReturn = TRUE;
616             break;
617         case MCI_STATUS_TIME_FORMAT:
618             TRACE(mciwave,"MCI_STATUS_TIME_FORMAT !\n");
619             lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
620             break;
621         case MCI_WAVE_INPUT:
622             TRACE(mciwave,"MCI_WAVE_INPUT !\n");
623             lpParms->dwReturn = 0;
624             break;
625         case MCI_WAVE_OUTPUT:
626             TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
627             lpParms->dwReturn = 0;
628             break;
629         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
630             TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
631             lpParms->dwReturn = 22050;
632             break;
633         case MCI_WAVE_STATUS_BITSPERSAMPLE:
634             TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
635             lpParms->dwReturn = 8;
636             break;
637         case MCI_WAVE_STATUS_BLOCKALIGN:
638             TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN !\n");
639             lpParms->dwReturn = 1;
640             break;
641         case MCI_WAVE_STATUS_CHANNELS:
642             TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS !\n");
643             lpParms->dwReturn = 1;
644             break;
645         case MCI_WAVE_STATUS_FORMATTAG:
646             TRACE(mciwave,"MCI_WAVE_FORMATTAG !\n");
647             lpParms->dwReturn = WAVE_FORMAT_PCM;
648             break;
649         case MCI_WAVE_STATUS_LEVEL:
650             TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
651             lpParms->dwReturn = 0xAAAA5555;
652             break;
653         case MCI_WAVE_STATUS_SAMPLESPERSEC:
654             TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
655             lpParms->dwReturn = 22050;
656             break;
657         default:
658             WARN(mciwave,"unknown command %08lX !\n", lpParms->dwItem);
659             return MCIERR_UNRECOGNIZED_COMMAND;
660         }
661     }
662     if (dwFlags & MCI_NOTIFY) {
663         TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
664         mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
665                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
666     }
667     return 0;
668 }
669
670 /**************************************************************************
671  *                              WAVE_mciGetDevCaps              [internal]
672  */
673 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
674                                 LPMCI_GETDEVCAPS_PARMS lpParms)
675 {
676     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
677     if (lpParms == NULL) return MCIERR_INTERNAL;
678     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
679         switch(lpParms->dwItem) {
680         case MCI_GETDEVCAPS_CAN_RECORD:
681             lpParms->dwReturn = TRUE;
682             break;
683         case MCI_GETDEVCAPS_HAS_AUDIO:
684             lpParms->dwReturn = TRUE;
685             break;
686         case MCI_GETDEVCAPS_HAS_VIDEO:
687             lpParms->dwReturn = FALSE;
688             break;
689         case MCI_GETDEVCAPS_DEVICE_TYPE:
690             lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
691             break;
692         case MCI_GETDEVCAPS_USES_FILES:
693             lpParms->dwReturn = TRUE;
694             break;
695         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
696             lpParms->dwReturn = TRUE;
697             break;
698         case MCI_GETDEVCAPS_CAN_EJECT:
699             lpParms->dwReturn = FALSE;
700             break;
701         case MCI_GETDEVCAPS_CAN_PLAY:
702             lpParms->dwReturn = TRUE;
703             break;
704         case MCI_GETDEVCAPS_CAN_SAVE:
705             lpParms->dwReturn = TRUE;
706             break;
707         case MCI_WAVE_GETDEVCAPS_INPUTS:
708             lpParms->dwReturn = 1;
709             break;
710         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
711             lpParms->dwReturn = 1;
712             break;
713         default:
714             return MCIERR_UNRECOGNIZED_COMMAND;
715         }
716     }
717     return 0;
718 }
719
720 /**************************************************************************
721  *                              WAVE_mciInfo                    [internal]
722  */
723 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
724 {
725     TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
726     if (lpParms == NULL) return MCIERR_INTERNAL;
727     lpParms->lpstrReturn = NULL;
728     switch(dwFlags) {
729     case MCI_INFO_PRODUCT:
730         lpParms->lpstrReturn = "Open Sound System 0.5";
731         break;
732     case MCI_INFO_FILE:
733         lpParms->lpstrReturn = 
734             (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
735         break;
736     case MCI_WAVE_INPUT:
737         lpParms->lpstrReturn = "Open Sound System 0.5";
738         break;
739     case MCI_WAVE_OUTPUT:
740         lpParms->lpstrReturn = "Open Sound System 0.5";
741         break;
742     default:
743         return MCIERR_UNRECOGNIZED_COMMAND;
744     }
745     if (lpParms->lpstrReturn != NULL)
746         lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
747     else
748         lpParms->dwRetSize = 0;
749     return 0;
750 }
751
752
753 /*-----------------------------------------------------------------------*/
754
755
756 /**************************************************************************
757  *                      wodGetDevCaps                           [internal]
758  */
759 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
760 {
761     int         audio;
762     int         smplrate;
763     int         samplesize = 16;
764     int         dsp_stereo = 1;
765     int         bytespersmpl;
766     
767     TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
768     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
769     if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
770     audio = open (SOUND_DEV, O_WRONLY, 0);
771     if (audio == -1) return MMSYSERR_ALLOCATED ;
772 #ifdef EMULATE_SB16
773     lpCaps->wMid = 0x0002;
774     lpCaps->wPid = 0x0104;
775     strcpy(lpCaps->szPname, "SB16 Wave Out");
776 #else
777     lpCaps->wMid = 0x00FF;      /* Manufac ID */
778     lpCaps->wPid = 0x0001;      /* Product ID */
779     strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
780 #endif
781     lpCaps->vDriverVersion = 0x0100;
782     lpCaps->dwFormats = 0x00000000;
783     lpCaps->dwSupport = WAVECAPS_VOLUME;
784     
785     /* First bytespersampl, then stereo */
786     bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
787     
788     lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
789     if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
790     
791     smplrate = 44100;
792     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
793         lpCaps->dwFormats |= WAVE_FORMAT_4M08;
794         if (lpCaps->wChannels > 1)
795             lpCaps->dwFormats |= WAVE_FORMAT_4S08;
796         if (bytespersmpl > 1) {
797             lpCaps->dwFormats |= WAVE_FORMAT_4M16;
798             if (lpCaps->wChannels > 1)
799                 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
800         }
801     }
802     smplrate = 22050;
803     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
804         lpCaps->dwFormats |= WAVE_FORMAT_2M08;
805         if (lpCaps->wChannels > 1)
806             lpCaps->dwFormats |= WAVE_FORMAT_2S08;
807         if (bytespersmpl > 1) {
808             lpCaps->dwFormats |= WAVE_FORMAT_2M16;
809             if (lpCaps->wChannels > 1)
810                 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
811         }
812     }
813     smplrate = 11025;
814     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
815         lpCaps->dwFormats |= WAVE_FORMAT_1M08;
816         if (lpCaps->wChannels > 1)
817             lpCaps->dwFormats |= WAVE_FORMAT_1S08;
818         if (bytespersmpl > 1) {
819             lpCaps->dwFormats |= WAVE_FORMAT_1M16;
820             if (lpCaps->wChannels > 1)
821                 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
822         }
823     }
824     close(audio);
825     TRACE(mciwave, "dwFormats = %08lX\n", lpCaps->dwFormats);
826     return MMSYSERR_NOERROR;
827 }
828
829
830 /**************************************************************************
831  *                              wodOpen                         [internal]
832  */
833 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
834 {
835     int                 audio,abuf_size,smplrate,samplesize,dsp_stereo;
836     LPWAVEFORMAT        lpFormat;
837     
838     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
839     if (lpDesc == NULL) {
840         WARN(mciwave, "Invalid Parameter !\n");
841         return MMSYSERR_INVALPARAM;
842     }
843     if (wDevID >= MAX_WAVOUTDRV) {
844         TRACE(mciwave,"MAX_WAVOUTDRV reached !\n");
845         return MMSYSERR_ALLOCATED;
846     }
847     WOutDev[wDevID].unixdev = 0;
848     if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
849     audio = open (SOUND_DEV, O_WRONLY, 0);
850     if (audio == -1) {
851         WARN(mciwave, "can't open !\n");
852         return MMSYSERR_ALLOCATED ;
853     }
854     IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
855     if (abuf_size < 1024 || abuf_size > 65536) {
856         if (abuf_size == -1)
857             WARN(mciwave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
858         else
859             WARN(mciwave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
860         return MMSYSERR_NOTENABLED;
861     }
862     WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
863     switch(WOutDev[wDevID].wFlags) {
864     case DCB_NULL:
865         TRACE(mciwave, "CALLBACK_NULL !\n");
866         break;
867     case DCB_WINDOW:
868         TRACE(mciwave, "CALLBACK_WINDOW !\n");
869         break;
870     case DCB_TASK:
871         TRACE(mciwave, "CALLBACK_TASK !\n");
872         break;
873     case DCB_FUNCTION:
874         TRACE(mciwave, "CALLBACK_FUNCTION !\n");
875         break;
876     }
877     WOutDev[wDevID].lpQueueHdr = NULL;
878     WOutDev[wDevID].unixdev = audio;
879     WOutDev[wDevID].dwTotalPlayed = 0;
880     WOutDev[wDevID].bufsize = abuf_size;
881     /* FIXME: copy lpFormat too? */
882     memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
883     TRACE(mciwave,"lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
884     lpFormat = lpDesc->lpFormat; 
885     TRACE(mciwave,"lpFormat = %p\n",lpFormat);
886     if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
887         WARN(mciwave,"Bad format %04X !\n",
888              lpFormat->wFormatTag);
889         WARN(mciwave,"Bad nChannels %d !\n",
890              lpFormat->nChannels);
891         WARN(mciwave,"Bad nSamplesPerSec %ld !\n",
892              lpFormat->nSamplesPerSec);
893         return WAVERR_BADFORMAT;
894     }
895     memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
896     if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
897     if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
898     TRACE(mciwave,"wBitsPerSample=%u !\n",
899           WOutDev[wDevID].Format.wBitsPerSample);
900     if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
901         WOutDev[wDevID].Format.wBitsPerSample = 8 *
902             (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
903              WOutDev[wDevID].Format.wf.nSamplesPerSec) /
904             WOutDev[wDevID].Format.wf.nChannels;
905     }
906     samplesize = WOutDev[wDevID].Format.wBitsPerSample;
907     smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
908     dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
909     
910     /* First size and stereo then samplerate */
911     IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
912     IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
913     IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
914     
915     TRACE(mciwave,"wBitsPerSample=%u !\n",
916           WOutDev[wDevID].Format.wBitsPerSample);
917     TRACE(mciwave,"nAvgBytesPerSec=%lu !\n",
918           WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
919     TRACE(mciwave,"nSamplesPerSec=%lu !\n",
920           WOutDev[wDevID].Format.wf.nSamplesPerSec);
921     TRACE(mciwave,"nChannels=%u !\n",
922           WOutDev[wDevID].Format.wf.nChannels);
923     if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
924         WARN(mciwave, "can't notify client !\n");
925         return MMSYSERR_INVALPARAM;
926     }
927     return MMSYSERR_NOERROR;
928 }
929
930 /**************************************************************************
931  *                              wodClose                        [internal]
932  */
933 static DWORD wodClose(WORD wDevID)
934 {
935     TRACE(mciwave,"(%u);\n", wDevID);
936     if (wDevID > MAX_WAVOUTDRV) return MMSYSERR_INVALPARAM;
937     if (WOutDev[wDevID].unixdev == 0) {
938         WARN(mciwave, "can't close !\n");
939         return MMSYSERR_NOTENABLED;
940     }
941     if (WOutDev[wDevID].lpQueueHdr != NULL) {
942         WARN(mciwave, "still buffers open !\n");
943         /* Don't care. Who needs those buffers anyway */
944         /*return WAVERR_STILLPLAYING; */
945     }
946     close(WOutDev[wDevID].unixdev);
947     WOutDev[wDevID].unixdev = 0;
948     WOutDev[wDevID].bufsize = 0;
949     WOutDev[wDevID].lpQueueHdr = NULL;
950     if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
951         WARN(mciwave, "can't notify client !\n");
952         return MMSYSERR_INVALPARAM;
953     }
954     return MMSYSERR_NOERROR;
955 }
956
957 /**************************************************************************
958  *                              wodWrite                        [internal]
959  * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
960  * device, and initiate async playing.
961  */
962 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
963 {
964     int         count;
965     LPSTR               lpData;
966     LPWAVEHDR   xwavehdr;
967     
968     TRACE(mciwave,"(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
969     if (WOutDev[wDevID].unixdev == 0) {
970         WARN(mciwave, "can't play !\n");
971         return MMSYSERR_NOTENABLED;
972     }
973     if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
974     if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
975     if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
976     lpWaveHdr->dwFlags &= ~WHDR_DONE;
977     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
978     TRACE(mciwave, "dwBufferLength %lu !\n", 
979           lpWaveHdr->dwBufferLength);
980     TRACE(mciwave, "WOutDev[%u].unixdev %u !\n", 
981           wDevID, WOutDev[wDevID].unixdev);
982     lpData = lpWaveHdr->lpData;
983     count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
984     TRACE(mciwave,"write returned count %u !\n",count);
985     if (count != lpWaveHdr->dwBufferLength) {
986         WARN(mciwave, " error writting !\n");
987         return MMSYSERR_NOTENABLED;
988     }
989     WOutDev[wDevID].dwTotalPlayed += count;
990     lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
991     lpWaveHdr->dwFlags |= WHDR_DONE;
992     if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
993         /* FIXME: what if it expects it's OWN lpwavehdr back? */
994         xwavehdr = SEGPTR_NEW(WAVEHDR);
995         memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
996         xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
997         if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
998             WARN(mciwave, "can't notify client !\n");
999             SEGPTR_FREE(xwavehdr);
1000             return MMSYSERR_INVALPARAM;
1001         }
1002         SEGPTR_FREE(xwavehdr);
1003     } else {
1004         if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
1005             WARN(mciwave, "can't notify client !\n");
1006             return MMSYSERR_INVALPARAM;
1007         }
1008     }
1009     return MMSYSERR_NOERROR;
1010 }
1011
1012 /**************************************************************************
1013  *                              wodPrepare                      [internal]
1014  */
1015 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1016 {
1017     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1018     if (WOutDev[wDevID].unixdev == 0) {
1019         WARN(mciwave, "can't prepare !\n");
1020         return MMSYSERR_NOTENABLED;
1021     }
1022     /* don't append to queue, wodWrite does that */
1023     WOutDev[wDevID].dwTotalPlayed = 0;
1024     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1025         return WAVERR_STILLPLAYING;
1026     lpWaveHdr->dwFlags |= WHDR_PREPARED;
1027     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1028     return MMSYSERR_NOERROR;
1029 }
1030
1031 /**************************************************************************
1032  *                              wodUnprepare                    [internal]
1033  */
1034 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1035 {
1036     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1037     if (WOutDev[wDevID].unixdev == 0) {
1038         WARN(mciwave, "can't unprepare !\n");
1039         return MMSYSERR_NOTENABLED;
1040     }
1041     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1042         return WAVERR_STILLPLAYING;
1043     
1044     lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1045     lpWaveHdr->dwFlags |= WHDR_DONE;
1046     TRACE(mciwave, "all headers unprepared !\n");
1047     return MMSYSERR_NOERROR;
1048 }
1049
1050 /**************************************************************************
1051  *                      wodRestart                              [internal]
1052  */
1053 static DWORD wodRestart(WORD wDevID)
1054 {
1055     TRACE(mciwave,"(%u);\n", wDevID);
1056     if (WOutDev[wDevID].unixdev == 0) {
1057         WARN(mciwave, "can't restart !\n");
1058         return MMSYSERR_NOTENABLED;
1059     }
1060     /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1061     /* FIXME: Myst crashes with this ... hmm -MM
1062        if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1063        WARN(mciwave, "can't notify client !\n");
1064        return MMSYSERR_INVALPARAM;
1065        }
1066     */
1067     
1068     return MMSYSERR_NOERROR;
1069 }
1070
1071 /**************************************************************************
1072  *                      wodReset                                [internal]
1073  */
1074 static DWORD wodReset(WORD wDevID)
1075 {
1076     TRACE(mciwave,"(%u);\n", wDevID);
1077     if (WOutDev[wDevID].unixdev == 0) {
1078         WARN(mciwave, "can't reset !\n");
1079         return MMSYSERR_NOTENABLED;
1080     }
1081     return MMSYSERR_NOERROR;
1082 }
1083
1084
1085 /**************************************************************************
1086  *                              wodGetPosition                  [internal]
1087  */
1088 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1089 {
1090     int         time;
1091     TRACE(mciwave,"(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1092     if (WOutDev[wDevID].unixdev == 0) {
1093         WARN(mciwave, "can't get pos !\n");
1094         return MMSYSERR_NOTENABLED;
1095     }
1096     if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1097     TRACE(mciwave,"wType=%04X !\n", 
1098           lpTime->wType);
1099     TRACE(mciwave,"wBitsPerSample=%u\n",
1100           WOutDev[wDevID].Format.wBitsPerSample); 
1101     TRACE(mciwave,"nSamplesPerSec=%lu\n",
1102           WOutDev[wDevID].Format.wf.nSamplesPerSec); 
1103     TRACE(mciwave,"nChannels=%u\n",
1104           WOutDev[wDevID].Format.wf.nChannels); 
1105     TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1106           WOutDev[wDevID].Format.wf.nAvgBytesPerSec); 
1107     switch(lpTime->wType) {
1108     case TIME_BYTES:
1109         lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1110         TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1111         break;
1112     case TIME_SAMPLES:
1113         TRACE(mciwave,"dwTotalPlayed=%lu\n", 
1114               WOutDev[wDevID].dwTotalPlayed);
1115         TRACE(mciwave,"wBitsPerSample=%u\n", 
1116               WOutDev[wDevID].Format.wBitsPerSample);
1117         lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1118             WOutDev[wDevID].Format.wBitsPerSample;
1119         TRACE(mciwave,"TIME_SAMPLES=%lu\n", lpTime->u.sample);
1120         break;
1121     case TIME_SMPTE:
1122         time = WOutDev[wDevID].dwTotalPlayed /
1123             (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1124         lpTime->u.smpte.hour = time / 108000;
1125         time -= lpTime->u.smpte.hour * 108000;
1126         lpTime->u.smpte.min = time / 1800;
1127         time -= lpTime->u.smpte.min * 1800;
1128         lpTime->u.smpte.sec = time / 30;
1129         time -= lpTime->u.smpte.sec * 30;
1130         lpTime->u.smpte.frame = time;
1131         lpTime->u.smpte.fps = 30;
1132         TRACE(mciwave,
1133               "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1134               lpTime->u.smpte.hour, lpTime->u.smpte.min,
1135               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1136         break;
1137     default:
1138         FIXME(mciwave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
1139         lpTime->wType = TIME_MS;
1140     case TIME_MS:
1141         lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1142             (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1143         TRACE(mciwave,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1144         break;
1145     }
1146     return MMSYSERR_NOERROR;
1147 }
1148
1149 /**************************************************************************
1150  *                              wodGetVolume                    [internal]
1151  */
1152 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1153 {
1154     int         mixer;
1155     int         volume, left, right;
1156     TRACE(mciwave,"(%u, %p);\n", wDevID, lpdwVol);
1157     if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1158     if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
1159         WARN(mciwave, "mixer device not available !\n");
1160         return MMSYSERR_NOTENABLED;
1161     }
1162     if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1163         WARN(mciwave, "unable read mixer !\n");
1164         return MMSYSERR_NOTENABLED;
1165     }
1166     close(mixer);
1167     left = volume & 0x7F;
1168     right = (volume >> 8) & 0x7F;
1169     TRACE(mciwave,"left=%d right=%d !\n", left, right);
1170     *lpdwVol = MAKELONG(left << 9, right << 9);
1171     return MMSYSERR_NOERROR;
1172 }
1173
1174
1175 /**************************************************************************
1176  *                              wodSetVolume                    [internal]
1177  */
1178 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1179 {
1180     int         mixer;
1181     int         volume;
1182     TRACE(mciwave,"(%u, %08lX);\n", wDevID, dwParam);
1183     volume = (LOWORD(dwParam) >> 9 & 0x7F) + 
1184         ((HIWORD(dwParam) >> 9  & 0x7F) << 8);
1185     if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
1186         WARN(mciwave,   "mixer device not available !\n");
1187         return MMSYSERR_NOTENABLED;
1188     }
1189     if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1190         WARN(mciwave, "unable set mixer !\n");
1191         return MMSYSERR_NOTENABLED;
1192     }
1193     close(mixer);
1194     return MMSYSERR_NOERROR;
1195 }
1196
1197 /**************************************************************************
1198  *                              wodMessage                      [sample driver]
1199  */
1200 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1201                         DWORD dwParam1, DWORD dwParam2)
1202 {
1203     int audio;
1204     TRACE(mciwave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1205           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1206     switch(wMsg) {
1207     case WODM_OPEN:
1208         return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1209     case WODM_CLOSE:
1210         return wodClose(wDevID);
1211     case WODM_WRITE:
1212         return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1213     case WODM_PAUSE:
1214         return MMSYSERR_NOTSUPPORTED;
1215     case WODM_STOP:
1216         return MMSYSERR_NOTSUPPORTED;
1217     case WODM_GETPOS:
1218         return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1219     case WODM_BREAKLOOP:
1220         return MMSYSERR_NOTSUPPORTED;
1221     case WODM_PREPARE:
1222         return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1223     case WODM_UNPREPARE:
1224         return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1225     case WODM_GETDEVCAPS:
1226         return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
1227     case WODM_GETNUMDEVS:
1228         /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1229         audio = open (SOUND_DEV, O_WRONLY, 0);
1230         if (audio == -1)
1231             if (errno == EBUSY)
1232                 return 1;
1233             else
1234                 return 0;
1235         close (audio);
1236         return 1;
1237     case WODM_GETPITCH:
1238         return MMSYSERR_NOTSUPPORTED;
1239     case WODM_SETPITCH:
1240         return MMSYSERR_NOTSUPPORTED;
1241     case WODM_GETPLAYBACKRATE:
1242         return MMSYSERR_NOTSUPPORTED;
1243     case WODM_SETPLAYBACKRATE:
1244         return MMSYSERR_NOTSUPPORTED;
1245     case WODM_GETVOLUME:
1246         return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1247     case WODM_SETVOLUME:
1248         return wodSetVolume(wDevID, dwParam1);
1249     case WODM_RESTART:
1250         return wodRestart(wDevID);
1251     case WODM_RESET:
1252         return wodReset(wDevID);
1253     default:
1254         WARN(mciwave,"unknown message !\n");
1255     }
1256     return MMSYSERR_NOTSUPPORTED;
1257 }
1258
1259
1260 /*-----------------------------------------------------------------------*/
1261
1262 /**************************************************************************
1263  *                      widGetDevCaps                           [internal]
1264  */
1265 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
1266 {
1267     int         audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
1268     
1269     TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1270     if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1271     if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1272     audio = open (SOUND_DEV, O_RDONLY, 0);
1273     if (audio == -1) return MMSYSERR_ALLOCATED ;
1274 #ifdef EMULATE_SB16
1275     lpCaps->wMid = 0x0002;
1276     lpCaps->wPid = 0x0004;
1277     strcpy(lpCaps->szPname, "SB16 Wave In");
1278 #else
1279     lpCaps->wMid = 0x00FF;      /* Manufac ID */
1280     lpCaps->wPid = 0x0001;      /* Product ID */
1281     strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
1282 #endif
1283     lpCaps->dwFormats = 0x00000000;
1284     lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1285     bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1286     smplrate = 44100;
1287     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1288         lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1289         if (lpCaps->wChannels > 1)
1290             lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1291         if (bytespersmpl > 1) {
1292             lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1293             if (lpCaps->wChannels > 1)
1294                 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1295         }
1296     }
1297     smplrate = 22050;
1298     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1299         lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1300         if (lpCaps->wChannels > 1)
1301             lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1302         if (bytespersmpl > 1) {
1303             lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1304             if (lpCaps->wChannels > 1)
1305                 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1306         }
1307     }
1308     smplrate = 11025;
1309     if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1310         lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1311         if (lpCaps->wChannels > 1)
1312             lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1313         if (bytespersmpl > 1) {
1314             lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1315             if (lpCaps->wChannels > 1)
1316                 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1317         }
1318     }
1319     close(audio);
1320     TRACE(mciwave, "dwFormats = %08lX\n", lpCaps->dwFormats);
1321     return MMSYSERR_NOERROR;
1322 }
1323
1324
1325 /**************************************************************************
1326  *                              widOpen                         [internal]
1327  */
1328 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1329 {
1330     int                 audio,abuf_size,smplrate,samplesize,dsp_stereo;
1331     LPWAVEFORMAT        lpFormat;
1332     
1333     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1334     if (lpDesc == NULL) {
1335         WARN(mciwave, "Invalid Parameter !\n");
1336         return MMSYSERR_INVALPARAM;
1337     }
1338     if (wDevID >= MAX_WAVINDRV) {
1339         TRACE(mciwave,"MAX_WAVINDRV reached !\n");
1340         return MMSYSERR_ALLOCATED;
1341     }
1342     WInDev[wDevID].unixdev = 0;
1343     if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1344     audio = open (SOUND_DEV, O_RDONLY, 0);
1345     if (audio == -1) {
1346         WARN(mciwave,"can't open !\n");
1347         return MMSYSERR_ALLOCATED;
1348     }
1349     IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1350     if (abuf_size < 1024 || abuf_size > 65536) {
1351         if (abuf_size == -1)
1352             WARN(mciwave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1353         else
1354             WARN(mciwave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1355         return MMSYSERR_NOTENABLED;
1356     }
1357     WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1358     switch(WInDev[wDevID].wFlags) {
1359     case DCB_NULL:
1360         TRACE(mciwave,"CALLBACK_NULL!\n");
1361         break;
1362     case DCB_WINDOW:
1363         TRACE(mciwave,"CALLBACK_WINDOW!\n");
1364         break;
1365     case DCB_TASK:
1366         TRACE(mciwave,"CALLBACK_TASK!\n");
1367         break;
1368     case DCB_FUNCTION:
1369         TRACE(mciwave,"CALLBACK_FUNCTION!\n");
1370         break;
1371     }
1372     if (WInDev[wDevID].lpQueueHdr) {
1373         HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
1374         WInDev[wDevID].lpQueueHdr = NULL;
1375     }
1376     WInDev[wDevID].unixdev = audio;
1377     WInDev[wDevID].bufsize = abuf_size;
1378     WInDev[wDevID].dwTotalRecorded = 0;
1379     memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1380     lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat; 
1381     if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1382         WARN(mciwave, "Bad format %04X !\n",
1383              lpFormat->wFormatTag);
1384         return WAVERR_BADFORMAT;
1385     }
1386     memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1387     WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1388     if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1389     if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1390     if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1391         WInDev[wDevID].Format.wBitsPerSample = 8 *
1392             (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1393              WInDev[wDevID].Format.wf.nSamplesPerSec) /
1394             WInDev[wDevID].Format.wf.nChannels;
1395     }
1396     samplesize = WInDev[wDevID].Format.wBitsPerSample;
1397     smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1398     dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1399     IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1400     IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1401     IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1402     TRACE(mciwave,"wBitsPerSample=%u !\n",
1403           WInDev[wDevID].Format.wBitsPerSample);
1404     TRACE(mciwave,"nSamplesPerSec=%lu !\n",
1405           WInDev[wDevID].Format.wf.nSamplesPerSec);
1406     TRACE(mciwave,"nChannels=%u !\n",
1407           WInDev[wDevID].Format.wf.nChannels);
1408     TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1409           WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1410     if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1411         WARN(mciwave,"can't notify client !\n");
1412         return MMSYSERR_INVALPARAM;
1413     }
1414     return MMSYSERR_NOERROR;
1415 }
1416
1417 /**************************************************************************
1418  *                              widClose                        [internal]
1419  */
1420 static DWORD widClose(WORD wDevID)
1421 {
1422     TRACE(mciwave,"(%u);\n", wDevID);
1423     if (wDevID > MAX_WAVINDRV) return MMSYSERR_INVALPARAM;
1424     if (WInDev[wDevID].unixdev == 0) {
1425         WARN(mciwave,"can't close !\n");
1426         return MMSYSERR_NOTENABLED;
1427     }
1428     if (WInDev[wDevID].lpQueueHdr != NULL) {
1429         WARN(mciwave, "still buffers open !\n");
1430         return WAVERR_STILLPLAYING;
1431     }
1432     close(WInDev[wDevID].unixdev);
1433     WInDev[wDevID].unixdev = 0;
1434     WInDev[wDevID].bufsize = 0;
1435     if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1436         WARN(mciwave,"can't notify client !\n");
1437         return MMSYSERR_INVALPARAM;
1438     }
1439     return MMSYSERR_NOERROR;
1440 }
1441
1442 /**************************************************************************
1443  *                              widAddBuffer            [internal]
1444  */
1445 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1446 {
1447     int         count   = 1;
1448     LPWAVEHDR   lpWIHdr;
1449     
1450     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1451     if (WInDev[wDevID].unixdev == 0) {
1452         WARN(mciwave,"can't do it !\n");
1453         return MMSYSERR_NOTENABLED;
1454     }
1455     if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1456         TRACE(mciwave, "never been prepared !\n");
1457         return WAVERR_UNPREPARED;
1458     }
1459     if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1460         TRACE(mciwave,  "header already in use !\n");
1461         return WAVERR_STILLPLAYING;
1462     }
1463     lpWaveHdr->dwFlags |= WHDR_PREPARED;
1464     lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1465     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1466     lpWaveHdr->dwBytesRecorded = 0;
1467     if (WInDev[wDevID].lpQueueHdr == NULL) {
1468         WInDev[wDevID].lpQueueHdr = lpWaveHdr;
1469     } else {
1470         lpWIHdr = WInDev[wDevID].lpQueueHdr;
1471         while (lpWIHdr->lpNext != NULL) {
1472             lpWIHdr = lpWIHdr->lpNext;
1473             count++;
1474         }
1475         lpWIHdr->lpNext = lpWaveHdr;
1476         lpWaveHdr->lpNext = NULL;
1477         count++;
1478     }
1479     TRACE(mciwave, "buffer added ! (now %u in queue)\n", count);
1480     return MMSYSERR_NOERROR;
1481 }
1482
1483 /**************************************************************************
1484  *                              widPrepare                      [internal]
1485  */
1486 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1487 {
1488     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1489     if (WInDev[wDevID].unixdev == 0) {
1490         WARN(mciwave,"can't prepare !\n");
1491         return MMSYSERR_NOTENABLED;
1492     }
1493     if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1494         return WAVERR_STILLPLAYING;
1495     lpWaveHdr->dwFlags |= WHDR_PREPARED;
1496     lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1497     lpWaveHdr->dwFlags &= ~WHDR_DONE;
1498     lpWaveHdr->dwBytesRecorded = 0;
1499     TRACE(mciwave,"header prepared !\n");
1500     return MMSYSERR_NOERROR;
1501 }
1502
1503 /**************************************************************************
1504  *                              widUnprepare                    [internal]
1505  */
1506 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1507 {
1508     TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1509     if (WInDev[wDevID].unixdev == 0) {
1510         WARN(mciwave,"can't unprepare !\n");
1511         return MMSYSERR_NOTENABLED;
1512     }
1513     lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1514     lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1515     lpWaveHdr->dwFlags |= WHDR_DONE;
1516     
1517     TRACE(mciwave, "all headers unprepared !\n");
1518     return MMSYSERR_NOERROR;
1519 }
1520
1521 /**************************************************************************
1522  *                      widStart                                [internal]
1523  */
1524 static DWORD widStart(WORD wDevID)
1525 {
1526     int         count   = 1;
1527     int            bytesRead;
1528     LPWAVEHDR   lpWIHdr;
1529     LPWAVEHDR   *lpWaveHdr;
1530     
1531     TRACE(mciwave,"(%u);\n", wDevID);
1532     if (WInDev[wDevID].unixdev == 0) {
1533         WARN(mciwave, "can't start recording !\n");
1534         return MMSYSERR_NOTENABLED;
1535     }
1536     
1537     lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
1538     TRACE(mciwave,"lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
1539     if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
1540         TRACE(mciwave,"never been prepared !\n");
1541         return WAVERR_UNPREPARED;
1542     }
1543     
1544     while(*lpWaveHdr != NULL) {
1545         lpWIHdr = *lpWaveHdr;
1546         TRACE(mciwave, "recording buf#%u=%p size=%lu \n",
1547               count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1548         fflush(stddeb);
1549         bytesRead = read (WInDev[wDevID].unixdev, 
1550                           lpWIHdr->lpData,
1551                           lpWIHdr->dwBufferLength);
1552         if (bytesRead==-1)
1553             perror("read from audio device");
1554         TRACE(mciwave,"bytesread=%d (%ld)\n",
1555               bytesRead,lpWIHdr->dwBufferLength);
1556         lpWIHdr->dwBytesRecorded = bytesRead;
1557         WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1558         lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1559         lpWIHdr->dwFlags |= WHDR_DONE;
1560         
1561         /* FIXME: should pass segmented pointer here, do we need that?*/
1562         if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
1563             WARN(mciwave, "can't notify client !\n");
1564             return MMSYSERR_INVALPARAM;
1565         }
1566         /* removes the current block from the queue */
1567         *lpWaveHdr = lpWIHdr->lpNext;
1568         count++;
1569     }
1570     TRACE(mciwave,"end of recording !\n");
1571     fflush(stddeb);
1572     return MMSYSERR_NOERROR;
1573 }
1574
1575 /**************************************************************************
1576  *                      widStop                                 [internal]
1577  */
1578 static DWORD widStop(WORD wDevID)
1579 {
1580     TRACE(mciwave,"(%u);\n", wDevID);
1581     if (WInDev[wDevID].unixdev == 0) {
1582         WARN(mciwave,"can't stop !\n");
1583         return MMSYSERR_NOTENABLED;
1584     }
1585     return MMSYSERR_NOERROR;
1586 }
1587
1588 /**************************************************************************
1589  *                      widReset                                [internal]
1590  */
1591 static DWORD widReset(WORD wDevID)
1592 {
1593     TRACE(mciwave,"(%u);\n", wDevID);
1594     if (WInDev[wDevID].unixdev == 0) {
1595         WARN(mciwave,"can't reset !\n");
1596         return MMSYSERR_NOTENABLED;
1597     }
1598     return MMSYSERR_NOERROR;
1599 }
1600
1601 /**************************************************************************
1602  *                              widGetPosition                  [internal]
1603  */
1604 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1605 {
1606     int         time;
1607     
1608     TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1609     if (WInDev[wDevID].unixdev == 0) {
1610         WARN(mciwave,"can't get pos !\n");
1611         return MMSYSERR_NOTENABLED;
1612     }
1613     if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1614     TRACE(mciwave,"wType=%04X !\n", 
1615           lpTime->wType);
1616     TRACE(mciwave,"wBitsPerSample=%u\n",
1617           WInDev[wDevID].Format.wBitsPerSample); 
1618     TRACE(mciwave,"nSamplesPerSec=%lu\n",
1619           WInDev[wDevID].Format.wf.nSamplesPerSec); 
1620     TRACE(mciwave,"nChannels=%u\n",
1621           WInDev[wDevID].Format.wf.nChannels); 
1622     TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1623           WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1624     fflush(stddeb);
1625     switch(lpTime->wType) {
1626     case TIME_BYTES:
1627         lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1628         TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1629         break;
1630     case TIME_SAMPLES:
1631         lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1632             WInDev[wDevID].Format.wBitsPerSample;
1633         TRACE(mciwave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
1634         break;
1635     case TIME_SMPTE:
1636         time = WInDev[wDevID].dwTotalRecorded /
1637             (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1638         lpTime->u.smpte.hour = time / 108000;
1639         time -= lpTime->u.smpte.hour * 108000;
1640         lpTime->u.smpte.min = time / 1800;
1641         time -= lpTime->u.smpte.min * 1800;
1642         lpTime->u.smpte.sec = time / 30;
1643         time -= lpTime->u.smpte.sec * 30;
1644         lpTime->u.smpte.frame = time;
1645         lpTime->u.smpte.fps = 30;
1646         TRACE(mciwave,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1647               lpTime->u.smpte.hour, lpTime->u.smpte.min,
1648               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1649         break;
1650     default:
1651         FIXME(mciwave, "format not supported ! use TIME_MS !\n");
1652         lpTime->wType = TIME_MS;
1653     case TIME_MS:
1654         lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1655             (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1656         TRACE(mciwave, "TIME_MS=%lu\n", lpTime->u.ms);
1657         break;
1658     }
1659     return MMSYSERR_NOERROR;
1660 }
1661
1662 /**************************************************************************
1663  *                              widMessage                      [sample driver]
1664  */
1665 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1666                         DWORD dwParam1, DWORD dwParam2)
1667 {
1668     int audio;
1669     TRACE(mciwave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1670           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1671     switch(wMsg) {
1672     case WIDM_OPEN:
1673         return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1674     case WIDM_CLOSE:
1675         return widClose(wDevID);
1676     case WIDM_ADDBUFFER:
1677         return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1678     case WIDM_PREPARE:
1679         return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1680     case WIDM_UNPREPARE:
1681         return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1682     case WIDM_GETDEVCAPS:
1683         return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1684     case WIDM_GETNUMDEVS:
1685         /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1686         audio = open (SOUND_DEV, O_RDONLY, 0);
1687         if (audio == -1)
1688             if (errno == EBUSY)
1689                 return 1;
1690             else
1691                 return 0;
1692         close (audio);
1693         return 1;
1694     case WIDM_GETPOS:
1695         return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1696     case WIDM_RESET:
1697         return widReset(wDevID);
1698     case WIDM_START:
1699         return widStart(wDevID);
1700     case WIDM_PAUSE:
1701         return widStop(wDevID);
1702     case WIDM_STOP:
1703         return widStop(wDevID);
1704     default:
1705         WARN(mciwave,"unknown message !\n");
1706     }
1707     return MMSYSERR_NOTSUPPORTED;
1708 }
1709
1710
1711 /**************************************************************************
1712  *                              WAVE_DriverProc16               [sample driver]
1713  */
1714 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
1715                        DWORD dwParam1, DWORD dwParam2)
1716 {
1717     TRACE(mciwave,"(%08lX, %04X, %04X, %08lX, %08lX)\n", 
1718           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1719     switch(wMsg) {
1720     case DRV_LOAD:              return 1;
1721     case DRV_FREE:              return 1;
1722     case DRV_OPEN:              return 1;
1723     case DRV_CLOSE:             return 1;
1724     case DRV_ENABLE:            return 1;
1725     case DRV_DISABLE:           return 1;
1726     case DRV_QUERYCONFIGURE:    return 1;
1727     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK);   return 1;
1728     case DRV_INSTALL:           return DRVCNF_RESTART;
1729     case DRV_REMOVE:            return DRVCNF_RESTART;
1730     case MCI_OPEN_DRIVER:       
1731     case MCI_OPEN:              return WAVE_mciOpen(dwDevID, dwParam1, PTR_SEG_TO_LIN(dwParam2), FALSE);
1732     case MCI_CUE:               return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1733     case MCI_CLOSE_DRIVER:
1734     case MCI_CLOSE:             return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1735     case MCI_PLAY:              return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1736     case MCI_RECORD:            return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1737     case MCI_STOP:              return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1738     case MCI_SET:               return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1739     case MCI_PAUSE:             return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1740     case MCI_RESUME:            return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1741     case MCI_STATUS:            return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1742     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1743     case MCI_INFO:              return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1744     case MCI_LOAD:              return MMSYSERR_NOTSUPPORTED;
1745     case MCI_SAVE:              return MMSYSERR_NOTSUPPORTED;
1746     case MCI_SEEK:              return MMSYSERR_NOTSUPPORTED;
1747     case MCI_FREEZE:            return MMSYSERR_NOTSUPPORTED;
1748     case MCI_PUT:               return MMSYSERR_NOTSUPPORTED;
1749     case MCI_REALIZE:           return MMSYSERR_NOTSUPPORTED;
1750     case MCI_UNFREEZE:          return MMSYSERR_NOTSUPPORTED;
1751     case MCI_UPDATE:            return MMSYSERR_NOTSUPPORTED;
1752     case MCI_WHERE:             return MMSYSERR_NOTSUPPORTED;
1753     case MCI_WINDOW:            return MMSYSERR_NOTSUPPORTED;
1754     case MCI_STEP:              return MMSYSERR_NOTSUPPORTED;
1755     case MCI_SPIN:              return MMSYSERR_NOTSUPPORTED;
1756     case MCI_ESCAPE:            return MMSYSERR_NOTSUPPORTED;
1757     case MCI_COPY:              return MMSYSERR_NOTSUPPORTED;
1758     case MCI_CUT:               return MMSYSERR_NOTSUPPORTED;
1759     case MCI_DELETE:            return MMSYSERR_NOTSUPPORTED;
1760     case MCI_PASTE:             return MMSYSERR_NOTSUPPORTED;
1761         
1762     default:
1763         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1764     }
1765     return MMSYSERR_NOTENABLED;
1766 }
1767 /**************************************************************************
1768  *                              WAVE_DriverProc32               [sample driver]
1769  */
1770 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
1771                        DWORD dwParam1, DWORD dwParam2)
1772 {
1773     TRACE(mciwave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
1774           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1775     switch(wMsg) {
1776     case DRV_LOAD:              return 1;
1777     case DRV_FREE:              return 1;
1778     case DRV_OPEN:              return 1;
1779     case DRV_CLOSE:             return 1;
1780     case DRV_ENABLE:            return 1;
1781     case DRV_DISABLE:           return 1;
1782     case DRV_QUERYCONFIGURE:    return 1;
1783     case DRV_CONFIGURE:         MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK);   return 1;
1784     case DRV_INSTALL:           return DRVCNF_RESTART;
1785     case DRV_REMOVE:            return DRVCNF_RESTART;
1786     case MCI_OPEN_DRIVER:       
1787     case MCI_OPEN:              return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS32A)dwParam2, TRUE);
1788     case MCI_CUE:               return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1789     case MCI_CLOSE_DRIVER:
1790     case MCI_CLOSE:             return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1791     case MCI_PLAY:              return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
1792     case MCI_RECORD:            return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)dwParam2);
1793     case MCI_STOP:              return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1794     case MCI_SET:               return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
1795     case MCI_PAUSE:             return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1796     case MCI_RESUME:            return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1797     case MCI_STATUS:            return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
1798     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1799     case MCI_INFO:              return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
1800     case MCI_LOAD:              return MMSYSERR_NOTSUPPORTED;
1801     case MCI_SAVE:              return MMSYSERR_NOTSUPPORTED;
1802     case MCI_SEEK:              return MMSYSERR_NOTSUPPORTED;
1803     case MCI_FREEZE:            return MMSYSERR_NOTSUPPORTED;
1804     case MCI_PUT:               return MMSYSERR_NOTSUPPORTED;
1805     case MCI_REALIZE:           return MMSYSERR_NOTSUPPORTED;
1806     case MCI_UNFREEZE:          return MMSYSERR_NOTSUPPORTED;
1807     case MCI_UPDATE:            return MMSYSERR_NOTSUPPORTED;
1808     case MCI_WHERE:             return MMSYSERR_NOTSUPPORTED;
1809     case MCI_WINDOW:            return MMSYSERR_NOTSUPPORTED;
1810     case MCI_STEP:              return MMSYSERR_NOTSUPPORTED;
1811     case MCI_SPIN:              return MMSYSERR_NOTSUPPORTED;
1812     case MCI_ESCAPE:            return MMSYSERR_NOTSUPPORTED;
1813     case MCI_COPY:              return MMSYSERR_NOTSUPPORTED;
1814     case MCI_CUT:               return MMSYSERR_NOTSUPPORTED;
1815     case MCI_DELETE:            return MMSYSERR_NOTSUPPORTED;
1816     case MCI_PASTE:             return MMSYSERR_NOTSUPPORTED;
1817         
1818     default:
1819         FIXME(mciwave, "is probably wrong\n");
1820         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1821     }
1822     return MMSYSERR_NOTENABLED;
1823 }
1824
1825 #else /* !HAVE_OSS */
1826
1827 /**************************************************************************
1828  *                              wodMessage                      [sample driver]
1829  */
1830 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1831                         DWORD dwParam1, DWORD dwParam2)
1832 {
1833     FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1834           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1835     return MMSYSERR_NOTENABLED;
1836 }
1837
1838 /**************************************************************************
1839  *                              widMessage                      [sample driver]
1840  */
1841 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1842                         DWORD dwParam1, DWORD dwParam2)
1843 {
1844     FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1845           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1846     return MMSYSERR_NOTENABLED;
1847 }
1848
1849 /**************************************************************************
1850  *                              WAVE_DriverProc16               [sample driver]
1851  */
1852 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
1853                        DWORD dwParam1, DWORD dwParam2)
1854 {
1855     return MMSYSERR_NOTENABLED;
1856 }
1857
1858 /**************************************************************************
1859  *                              WAVE_DriverProc32               [sample driver]
1860  */
1861 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg, 
1862                        DWORD dwParam1, DWORD dwParam2)
1863 {
1864     return MMSYSERR_NOTENABLED;
1865 }
1866 #endif /* HAVE_OSS */