When flipping backbuffer -> frontbuffer, first exchange surfaces, then
[wine] / multimedia / mciwave.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 "winuser.h"
18 #include "driver.h"
19 #include "multimedia.h"
20 #include "heap.h"
21 #include "debugtools.h"
22
23 DEFAULT_DEBUG_CHANNEL(mciwave)
24
25 typedef struct {
26     UINT16                      wDevID;
27     UINT16                      wWavID;
28     int                         nUseCount;      /* Incremented for each shared open */
29     BOOL16                      fShareable;     /* TRUE if first open was shareable */
30     WORD                        wNotifyDeviceID;/* MCI device ID with a pending notification */
31     HANDLE16                    hCallback;      /* Callback handle for pending notification */
32     HMMIO                       hFile;          /* mmio file handle open as Element */
33     MCI_WAVE_OPEN_PARMSA        openParms;
34     WAVEOPENDESC                waveDesc;
35     PCMWAVEFORMAT               WaveFormat;
36     WAVEHDR                     WaveHdr;
37     BOOL16                      fInput;         /* FALSE = Output, TRUE = Input */
38     WORD                        dwStatus;       /* one from MCI_MODE_xxxx */
39     DWORD                       dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
40     DWORD                       dwFileOffset;   /* Offset of chunk in mmio file */
41     DWORD                       dwLength;       /* number of bytes in chunk for playing */
42     DWORD                       dwPosition;     /* position in bytes in chunk for playing */
43 } WINE_MCIWAVE;
44
45 /*======================================================================*
46  *                          MCI WAVE implemantation                     *
47  *======================================================================*/
48
49 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
50
51 /**************************************************************************
52  *                              MCIWAVE_drvOpen                 [internal]      
53  */
54 static  DWORD   WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
55 {
56     WINE_MCIWAVE*       wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
57
58     if (!wmw)
59         return 0;
60
61     wmw->wDevID = modp->wDeviceID;
62     mciSetDriverData(wmw->wDevID, (DWORD)wmw);
63     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
64     modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
65     return modp->wDeviceID;
66 }
67
68 /**************************************************************************
69  *                              MCIWAVE_drvClose                [internal]      
70  */
71 static  DWORD   WAVE_drvClose(DWORD dwDevID)
72 {
73     WINE_MCIWAVE*  wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
74
75     if (wmw) {
76         HeapFree(GetProcessHeap(), 0, wmw);     
77         mciSetDriverData(dwDevID, 0);
78         return 1;
79     }
80     return 0;
81 }
82
83 /**************************************************************************
84  *                              WAVE_mciGetOpenDev              [internal]      
85  */
86 static WINE_MCIWAVE*  WAVE_mciGetOpenDev(UINT16 wDevID)
87 {
88     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
89     
90     if (wmw == NULL || wmw->nUseCount == 0) {
91         WARN("Invalid wDevID=%u\n", wDevID);
92         return 0;
93     }
94     return wmw;
95 }
96
97 /**************************************************************************
98  *                              WAVE_ConvertByteToTimeFormat    [internal]      
99  */
100 static  DWORD   WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
101 {
102     DWORD       ret = 0;
103     
104     switch (wmw->dwMciTimeFormat) {
105     case MCI_FORMAT_MILLISECONDS:
106         ret = (val * 1000) / wmw->WaveFormat.wf.nAvgBytesPerSec;
107         break;
108     case MCI_FORMAT_BYTES:
109         ret = val;
110         break;
111     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
112         ret = (val * 8) / wmw->WaveFormat.wBitsPerSample;
113         break;
114     default:
115         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
116     }
117     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
118     *lpRet = 0;
119     return ret;
120 }
121
122 /**************************************************************************
123  *                              WAVE_ConvertTimeFormatToByte    [internal]      
124  */
125 static  DWORD   WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
126 {
127     DWORD       ret = 0;
128     
129     switch (wmw->dwMciTimeFormat) {
130     case MCI_FORMAT_MILLISECONDS:
131         ret = (val * wmw->WaveFormat.wf.nAvgBytesPerSec) / 1000;
132         break;
133     case MCI_FORMAT_BYTES:
134         ret = val;
135         break;
136     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
137         ret = (val * wmw->WaveFormat.wBitsPerSample) / 8;
138         break;
139     default:
140         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
141     }
142     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
143     return ret;
144 }
145
146 /**************************************************************************
147  *                      WAVE_mciReadFmt                         [internal]
148  */
149 static  DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
150 {
151     MMCKINFO    mmckInfo;
152     
153     mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
154     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
155         return MCIERR_INVALID_FILE;
156     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
157           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
158     if (mmioRead(wmw->hFile, (HPSTR)&wmw->WaveFormat,
159                  (long)sizeof(PCMWAVEFORMAT)) != (long)sizeof(PCMWAVEFORMAT))
160         return MCIERR_INVALID_FILE;
161     
162     TRACE("wFormatTag=%04X !\n",   wmw->WaveFormat.wf.wFormatTag);
163     TRACE("nChannels=%d \n",       wmw->WaveFormat.wf.nChannels);
164     TRACE("nSamplesPerSec=%ld\n",  wmw->WaveFormat.wf.nSamplesPerSec);
165     TRACE("nAvgBytesPerSec=%ld\n", wmw->WaveFormat.wf.nAvgBytesPerSec);
166     TRACE("nBlockAlign=%d \n",     wmw->WaveFormat.wf.nBlockAlign);
167     TRACE("wBitsPerSample=%u !\n", wmw->WaveFormat.wBitsPerSample);
168
169     mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
170     mmioSeek(wmw->hFile, mmckInfo.dwDataOffset + ((mmckInfo.cksize + 1) & ~1), SEEK_SET);
171     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
172         TRACE("can't find data chunk\n");
173         return MCIERR_INVALID_FILE;
174     }
175     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
176           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
177     TRACE("nChannels=%d nSamplesPerSec=%ld\n",
178           wmw->WaveFormat.wf.nChannels, wmw->WaveFormat.wf.nSamplesPerSec);
179     wmw->dwLength = mmckInfo.cksize;
180     wmw->dwFileOffset = mmioSeek(wmw->hFile, 0, SEEK_CUR); /* >= 0 */
181     return 0;
182 }
183
184 /**************************************************************************
185  *                      WAVE_mciOpen                            [internal]
186  */
187 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
188 {
189     DWORD               dwRet = 0;
190     DWORD               dwDeviceID;
191     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
192     
193     TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
194     if (lpOpenParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
195     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
196
197     if (dwFlags & MCI_OPEN_SHAREABLE)
198         return MCIERR_HARDWARE;
199     
200     if (wmw->nUseCount > 0) {
201         /* The driver is already opened on this channel
202          * Wave driver cannot be shared
203          */
204         return MCIERR_DEVICE_OPEN;
205     }
206     wmw->nUseCount++;
207     
208     dwDeviceID = lpOpenParms->wDeviceID;
209     
210     wmw->fInput = FALSE;
211     wmw->wWavID = 0;
212
213     TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
214     
215     if (dwFlags & MCI_OPEN_ELEMENT) {
216         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
217             /* could it be that (DWORD)lpOpenParms->lpstrElementName 
218              * contains the hFile value ? 
219              */
220             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
221         } else {
222             LPCSTR      lpstrElementName = lpOpenParms->lpstrElementName;
223             
224             /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
225             TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
226             if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
227                 wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL, 
228                                        MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
229                 if (wmw->hFile == 0) {
230                     WARN("can't find file='%s' !\n", lpstrElementName);
231                     dwRet = MCIERR_FILE_NOT_FOUND;
232                 }
233             } else {
234                 wmw->hFile = 0;
235             }
236         }
237     }
238     TRACE("hFile=%u\n", wmw->hFile);
239     
240     memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
241     wmw->wNotifyDeviceID = dwDeviceID;
242     wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
243     
244     wmw->waveDesc.hWave = 0;
245     
246     if (dwRet == 0 && wmw->hFile != 0) {
247         MMCKINFO        ckMainRIFF;
248         
249         if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
250             dwRet = MCIERR_INVALID_FILE;
251         } else {
252             TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
253                   (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
254             if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
255                 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
256                 dwRet = MCIERR_INVALID_FILE;
257             } else {
258                 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
259             }
260         }
261     } else {
262         wmw->dwLength = 0;
263     }
264     if (dwRet == 0) {
265         wmw->WaveFormat.wf.nAvgBytesPerSec = 
266             wmw->WaveFormat.wf.nSamplesPerSec * wmw->WaveFormat.wf.nBlockAlign;
267         wmw->waveDesc.lpFormat = (LPWAVEFORMAT)&wmw->WaveFormat;
268         wmw->dwPosition = 0;
269         
270         wmw->dwStatus = MCI_MODE_STOP;
271     } else {
272         wmw->nUseCount--;
273         if (wmw->hFile != 0)
274             mmioClose(wmw->hFile, 0);
275         wmw->hFile = 0;
276     }
277     return dwRet;
278 }
279
280 /**************************************************************************
281  *                               WAVE_mciCue             [internal]
282  */
283 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
284 {
285     /*
286       FIXME
287       
288       This routine is far from complete. At the moment only a check is done on the
289       MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
290       is the default.
291       
292       The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
293       are ignored
294     */
295     
296     DWORD               dwRet;
297     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
298     
299     TRACE("(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
300     
301     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
302     
303     /* always close elements ? */    
304     if (wmw->hFile != 0) {
305         mmioClose(wmw->hFile, 0);
306         wmw->hFile = 0;
307     }
308     
309     dwRet = MMSYSERR_NOERROR;  /* assume success */
310     
311     if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
312         dwRet = wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
313         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
314         dwRet = widMessage(wmw->wWavID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
315         wmw->fInput = TRUE;
316     } else if (wmw->fInput) {
317         dwRet = widMessage(wmw->wWavID, WIDM_CLOSE, 0, 0L, 0L);
318         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
319         dwRet = wodMessage(wmw->wWavID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
320         wmw->fInput = FALSE;
321     }
322     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
323 }
324
325 /**************************************************************************
326  *                              WAVE_mciStop                    [internal]
327  */
328 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
329 {
330     DWORD               dwRet;
331     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
332     
333     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
334     
335     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
336     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
337     
338     wmw->dwStatus = MCI_MODE_STOP;
339     wmw->dwPosition = 0;
340     TRACE("wmw->dwStatus=%d\n", wmw->dwStatus);
341     
342     if (wmw->fInput)
343         dwRet = widMessage(wmw->wWavID, WIDM_RESET, 0, dwFlags, (DWORD)lpParms);
344     else
345         dwRet = wodMessage(wmw->wWavID, WODM_RESET, 0, dwFlags, (DWORD)lpParms);
346     
347     if (dwFlags & MCI_NOTIFY) {
348         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
349         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
350                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
351     }
352     
353     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
354 }
355
356 /**************************************************************************
357  *                              WAVE_mciClose           [internal]
358  */
359 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
360 {
361     DWORD               dwRet = 0;
362     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
363     
364     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
365     
366     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
367     
368     if (wmw->dwStatus != MCI_MODE_STOP) {
369         dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
370     }
371     
372     wmw->nUseCount--;
373     
374     if (wmw->nUseCount == 0) {
375         DWORD   mmRet;
376         if (wmw->hFile != 0) {
377             mmioClose(wmw->hFile, 0);
378             wmw->hFile = 0;
379         }
380         mmRet = (wmw->fInput) ? widMessage(wmw->wWavID, WIDM_CLOSE, 0, 0L, 0L) :
381             wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
382         
383         if (mmRet != MMSYSERR_NOERROR) dwRet = MCIERR_INTERNAL;
384     }
385     
386     if ((dwFlags & MCI_NOTIFY) && lpParms) {
387         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
388         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
389                           wmw->wNotifyDeviceID,
390                           (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
391     }
392     return 0;
393 }
394
395 /**************************************************************************
396  *                              WAVE_mciPlay            [internal]
397  */
398 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
399 {
400     DWORD               end;
401     LONG                bufsize, count;
402     HGLOBAL16           hData;
403     DWORD               dwRet;
404     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
405     
406     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
407     
408     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
409     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
410     
411     if (wmw->fInput) {
412         WARN("cannot play on input device\n");
413         return MCIERR_NONAPPLICABLE_FUNCTION;
414     }
415     
416     if (wmw->hFile == 0) {
417         WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
418         return MCIERR_FILE_NOT_FOUND;
419     }
420     
421     if (!(dwFlags & MCI_WAIT)) {
422         return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags, 
423                                     (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
424     }
425
426     if (wmw->dwStatus != MCI_MODE_STOP) {
427         if (wmw->dwStatus == MCI_MODE_PAUSE) {
428             /* FIXME: parameters (start/end) in lpParams may not be used */
429             return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
430         }
431         return MCIERR_INTERNAL;
432     }
433
434     end = 0xFFFFFFFF;
435     if (lpParms && (dwFlags & MCI_FROM)) {
436         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom); 
437     }
438     if (lpParms && (dwFlags & MCI_TO)) {
439         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
440     }
441     
442     TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
443     
444     /* go back to begining of chunk */
445     mmioSeek(wmw->hFile, wmw->dwFileOffset, SEEK_SET); /* >= 0 */
446     
447     /* By default the device will be opened for output, the MCI_CUE function is there to
448      * change from output to input and back
449      */
450     /* FIXME: how to choose between several output channels ? here 0 is forced */
451     dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
452     if (dwRet != 0) {
453         TRACE("Can't open low level audio device %ld\n", dwRet);
454         return MCIERR_DEVICE_OPEN;
455     }
456
457     /* at 22050 bytes per sec => 30 ms by block */
458     bufsize = 10240;
459     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
460     wmw->WaveHdr.lpData = (LPSTR)GlobalLock16(hData);
461     
462     wmw->dwStatus = MCI_MODE_PLAY;
463     
464     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
465     /* FIXME: use several WaveHdr for smoother playback */
466     /* FIXME: use only regular MMSYS functions, not calling directly the driver */
467     while (wmw->dwStatus != MCI_MODE_STOP) {
468         wmw->WaveHdr.dwUser = 0L;
469         wmw->WaveHdr.dwFlags = 0L;
470         wmw->WaveHdr.dwLoops = 0L;
471         count = mmioRead(wmw->hFile, wmw->WaveHdr.lpData, bufsize);
472         TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
473         if (count < 1) 
474             break;
475         dwRet = wodMessage(wmw->wWavID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
476         wmw->WaveHdr.dwBufferLength = count;
477         wmw->WaveHdr.dwBytesRecorded = 0;
478         /* FIXME */
479         wmw->WaveHdr.reserved = (DWORD)&wmw->WaveHdr;
480         TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
481               &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
482         dwRet = wodMessage(wmw->wWavID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
483         /* FIXME: should use callback mechanisms from audio driver */
484 #if 1
485         while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
486             Sleep(1);
487 #endif
488         wmw->dwPosition += count;
489         TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
490         dwRet = wodMessage(wmw->wWavID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
491     }
492     
493     if (wmw->WaveHdr.lpData != NULL) {
494         GlobalUnlock16(hData);
495         GlobalFree16(hData);
496         wmw->WaveHdr.lpData = NULL;
497     }
498
499     wodMessage(wmw->wWavID, WODM_RESET,  0, 0L, 0L);
500     wodMessage(wmw->wWavID, WODM_CLOSE, 0, 0L, 0L);
501
502     wmw->dwStatus = MCI_MODE_STOP;
503     if (lpParms && (dwFlags & MCI_NOTIFY)) {
504         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
505         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
506                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
507     }
508     return 0;
509 }
510
511 /**************************************************************************
512  *                              WAVE_mciRecord                  [internal]
513  */
514 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
515 {
516     int                 start, end;
517     LONG                bufsize;
518     HGLOBAL16           hData;
519     LPWAVEHDR           lpWaveHdr;
520     DWORD               dwRet;
521     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
522     
523     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
524     
525     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
526     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
527     
528     if (!wmw->fInput) {
529         WARN("cannot record on output device\n");
530         return MCIERR_NONAPPLICABLE_FUNCTION;
531     }
532     
533     if (wmw->hFile == 0) {
534         WARN("can't find file='%s' !\n", 
535              wmw->openParms.lpstrElementName);
536         return MCIERR_FILE_NOT_FOUND;
537     }
538     start = 1;  end = 99999;
539     if (dwFlags & MCI_FROM) {
540         start = lpParms->dwFrom; 
541         TRACE("MCI_FROM=%d \n", start);
542     }
543     if (dwFlags & MCI_TO) {
544         end = lpParms->dwTo;
545         TRACE("MCI_TO=%d \n", end);
546     }
547     bufsize = 64000;
548     lpWaveHdr = &wmw->WaveHdr;
549     hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
550     lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
551     lpWaveHdr->dwBufferLength = bufsize;
552     lpWaveHdr->dwUser = 0L;
553     lpWaveHdr->dwFlags = 0L;
554     lpWaveHdr->dwLoops = 0L;
555     dwRet = widMessage(wmw->wWavID, WIDM_PREPARE, 0, (DWORD)lpWaveHdr, sizeof(WAVEHDR));
556     TRACE("after WIDM_PREPARE \n");
557     while (TRUE) {
558         lpWaveHdr->dwBytesRecorded = 0;
559         dwRet = widMessage(wmw->wWavID, WIDM_START, 0, 0L, 0L);
560         TRACE("after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
561               lpWaveHdr, lpWaveHdr->dwBytesRecorded);
562         if (lpWaveHdr->dwBytesRecorded == 0) break;
563     }
564     TRACE("before WIDM_UNPREPARE \n");
565     dwRet = widMessage(wmw->wWavID, WIDM_UNPREPARE, 0, (DWORD)lpWaveHdr, sizeof(WAVEHDR));
566     TRACE("after WIDM_UNPREPARE \n");
567     if (lpWaveHdr->lpData != NULL) {
568         GlobalUnlock16(hData);
569         GlobalFree16(hData);
570         lpWaveHdr->lpData = NULL;
571     }
572     if (dwFlags & MCI_NOTIFY) {
573         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
574         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
575                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
576     }
577     return 0;
578 }
579
580 /**************************************************************************
581  *                              WAVE_mciPause                   [internal]
582  */
583 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
584 {
585     DWORD               dwRet;
586     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
587     
588     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
589     
590     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
591     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
592     
593     if (wmw->dwStatus == MCI_MODE_PLAY) {
594         wmw->dwStatus = MCI_MODE_PAUSE;
595     } 
596     
597     if (wmw->fInput)    dwRet = widMessage(wmw->wWavID, WIDM_PAUSE, 0, 0L, 0L);
598     else                dwRet = wodMessage(wmw->wWavID, WODM_PAUSE, 0, 0L, 0L);
599     
600     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
601 }
602
603 /**************************************************************************
604  *                              WAVE_mciResume                  [internal]
605  */
606 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
607 {
608     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
609     DWORD               dwRet = 0;
610     
611     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
612     
613     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
614     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
615     
616     if (wmw->dwStatus == MCI_MODE_PAUSE) {
617         wmw->dwStatus = MCI_MODE_PLAY;
618     } 
619     
620     /* FIXME: I doubt WIDM_START is correct */
621     if (wmw->fInput)    dwRet = widMessage(wmw->wWavID, WIDM_START, 0, 0L, 0L);
622     else                dwRet = wodMessage(wmw->wWavID, WODM_RESTART, 0, 0L, 0L);
623     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
624 }
625
626 /**************************************************************************
627  *                              WAVE_mciSeek                    [internal]
628  */
629 static DWORD WAVE_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
630 {
631     DWORD               ret = 0;
632     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
633     
634     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
635     
636     if (lpParms == NULL) {
637         ret = MCIERR_NULL_PARAMETER_BLOCK;
638     } else if (wmw == NULL) {
639         ret = MCIERR_INVALID_DEVICE_ID;
640     } else {
641         WAVE_mciStop(wDevID, MCI_WAIT, 0);
642         
643         if (dwFlags & MCI_SEEK_TO_START) {
644             wmw->dwPosition = 0;
645         } else if (dwFlags & MCI_SEEK_TO_END) {
646             wmw->dwPosition = 0xFFFFFFFF; /* fixme */
647         } else if (dwFlags & MCI_TO) {
648             wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
649         } else {
650             WARN("dwFlag doesn't tell where to seek to...\n");
651             return MCIERR_MISSING_PARAMETER;
652         }
653         
654         TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
655         
656         if (dwFlags & MCI_NOTIFY) {
657             TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
658             mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
659                               wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
660         }
661     }
662     return ret; 
663 }    
664
665 /**************************************************************************
666  *                              WAVE_mciSet                     [internal]
667  */
668 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
669 {
670     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
671     
672     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
673     
674     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
675     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
676     
677     if (dwFlags & MCI_SET_TIME_FORMAT) {
678         switch (lpParms->dwTimeFormat) {
679         case MCI_FORMAT_MILLISECONDS:
680             TRACE("MCI_FORMAT_MILLISECONDS !\n");
681             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
682             break;
683         case MCI_FORMAT_BYTES:
684             TRACE("MCI_FORMAT_BYTES !\n");
685             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
686             break;
687         case MCI_FORMAT_SAMPLES:
688             TRACE("MCI_FORMAT_SAMPLES !\n");
689             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
690             break;
691         default:
692             WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
693             return MCIERR_BAD_TIME_FORMAT;
694         }
695     }
696     if (dwFlags & MCI_SET_VIDEO) {
697         TRACE("No support for video !\n");
698         return MCIERR_UNSUPPORTED_FUNCTION;
699     }
700     if (dwFlags & MCI_SET_DOOR_OPEN) {
701         TRACE("No support for door open !\n");
702         return MCIERR_UNSUPPORTED_FUNCTION;
703     }
704     if (dwFlags & MCI_SET_DOOR_CLOSED) {
705         TRACE("No support for door close !\n");
706         return MCIERR_UNSUPPORTED_FUNCTION;
707     }
708     if (dwFlags & MCI_SET_AUDIO) {
709         if (dwFlags & MCI_SET_ON) {
710             TRACE("MCI_SET_ON audio !\n");
711         } else if (dwFlags & MCI_SET_OFF) {
712             TRACE("MCI_SET_OFF audio !\n");
713         } else {
714             WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
715             return MCIERR_BAD_INTEGER;
716         }
717         
718         if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
719             TRACE("MCI_SET_AUDIO_ALL !\n");
720         if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
721             TRACE("MCI_SET_AUDIO_LEFT !\n");
722         if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
723             TRACE("MCI_SET_AUDIO_RIGHT !\n");
724     }
725     if (dwFlags & MCI_WAVE_INPUT) 
726         TRACE("MCI_WAVE_INPUT !\n");
727     if (dwFlags & MCI_WAVE_OUTPUT) 
728         TRACE("MCI_WAVE_OUTPUT !\n");
729     if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
730         TRACE("MCI_WAVE_SET_ANYINPUT !\n");
731     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
732         TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
733     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
734         TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
735     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
736         TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
737     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
738         TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
739     if (dwFlags & MCI_WAVE_SET_CHANNELS) 
740         TRACE("MCI_WAVE_SET_CHANNELS !\n");
741     if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
742         TRACE("MCI_WAVE_SET_FORMATTAG !\n");
743     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
744         TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
745     return 0;
746 }
747
748 /**************************************************************************
749  *                              WAVE_mciStatus          [internal]
750  */
751 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
752 {
753     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
754     DWORD               ret;
755
756     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
757     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
758     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
759     
760     if (dwFlags & MCI_STATUS_ITEM) {
761         switch(lpParms->dwItem) {
762         case MCI_STATUS_CURRENT_TRACK:
763             lpParms->dwReturn = 1;
764             TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
765             break;
766         case MCI_STATUS_LENGTH:
767             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
768             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
769             TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
770             break;
771         case MCI_STATUS_MODE:
772             TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
773             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
774             ret = MCI_RESOURCE_RETURNED;
775             break;
776         case MCI_STATUS_MEDIA_PRESENT:
777             TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
778             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
779             ret = MCI_RESOURCE_RETURNED;
780             break;
781         case MCI_STATUS_NUMBER_OF_TRACKS:
782             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
783             lpParms->dwReturn = 1;
784             TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
785             break;
786         case MCI_STATUS_POSITION:
787             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
788             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, 
789                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
790                                                              &ret);
791             TRACE("MCI_STATUS_POSITION %s => %lu\n", 
792                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
793             break;
794         case MCI_STATUS_READY:
795             lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
796                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
797             TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
798             ret = MCI_RESOURCE_RETURNED;
799             break;
800         case MCI_STATUS_TIME_FORMAT:
801             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
802             TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
803             ret = MCI_RESOURCE_RETURNED;
804             break;
805         case MCI_WAVE_INPUT:
806             TRACE("MCI_WAVE_INPUT !\n");
807             lpParms->dwReturn = 0;
808             break;
809         case MCI_WAVE_OUTPUT:
810             TRACE("MCI_WAVE_OUTPUT !\n");
811             lpParms->dwReturn = 0;
812             break;
813         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
814             lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
815             TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
816             break;
817         case MCI_WAVE_STATUS_BITSPERSAMPLE:
818             lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
819             TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
820             break;
821         case MCI_WAVE_STATUS_BLOCKALIGN:
822             lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
823             TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
824             break;
825         case MCI_WAVE_STATUS_CHANNELS:
826             lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
827             TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
828             break;
829         case MCI_WAVE_STATUS_FORMATTAG:
830             lpParms->dwReturn = wmw->WaveFormat.wf.wFormatTag;
831             TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
832             break;
833         case MCI_WAVE_STATUS_LEVEL:
834             TRACE("MCI_WAVE_STATUS_LEVEL !\n");
835             lpParms->dwReturn = 0xAAAA5555;
836             break;
837         case MCI_WAVE_STATUS_SAMPLESPERSEC:
838             lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
839             TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
840             break;
841         default:
842             WARN("unknown command %08lX !\n", lpParms->dwItem);
843             return MCIERR_UNRECOGNIZED_COMMAND;
844         }
845     }
846     if (dwFlags & MCI_NOTIFY) {
847         TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
848         mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback), 
849                           wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
850     }
851     return ret;
852 }
853
854 /**************************************************************************
855  *                              WAVE_mciGetDevCaps              [internal]
856  */
857 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
858                                 LPMCI_GETDEVCAPS_PARMS lpParms)
859 {
860     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
861     DWORD               ret = 0;
862
863     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
864     
865     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
866     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
867     
868     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
869         switch(lpParms->dwItem) {
870         case MCI_GETDEVCAPS_DEVICE_TYPE:
871             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
872             ret = MCI_RESOURCE_RETURNED;
873             break;
874         case MCI_GETDEVCAPS_HAS_AUDIO:
875             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
876             ret = MCI_RESOURCE_RETURNED;
877             break;
878         case MCI_GETDEVCAPS_HAS_VIDEO:
879             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
880             ret = MCI_RESOURCE_RETURNED;
881             break;
882         case MCI_GETDEVCAPS_USES_FILES:
883             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
884             ret = MCI_RESOURCE_RETURNED;
885             break;
886         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
887             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
888             ret = MCI_RESOURCE_RETURNED;
889             break;
890         case MCI_GETDEVCAPS_CAN_RECORD:
891             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
892             ret = MCI_RESOURCE_RETURNED;
893             break;
894         case MCI_GETDEVCAPS_CAN_EJECT:
895             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
896             ret = MCI_RESOURCE_RETURNED;
897             break;
898         case MCI_GETDEVCAPS_CAN_PLAY:
899             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
900             ret = MCI_RESOURCE_RETURNED;
901             break;
902         case MCI_GETDEVCAPS_CAN_SAVE:
903             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
904             ret = MCI_RESOURCE_RETURNED;
905             break;
906         case MCI_WAVE_GETDEVCAPS_INPUTS:
907             lpParms->dwReturn = 1;
908             break;
909         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
910             lpParms->dwReturn = 1;
911             break;
912         default:
913             FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
914             return MCIERR_UNRECOGNIZED_COMMAND;
915         }
916     } else {
917         WARN("No GetDevCaps-Item !\n");
918         return MCIERR_UNRECOGNIZED_COMMAND;
919     }
920     return ret;
921 }
922
923 /**************************************************************************
924  *                              WAVE_mciInfo                    [internal]
925  */
926 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
927 {
928     DWORD               ret = 0;
929     LPCSTR              str = 0;
930     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
931     
932     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
933     
934     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
935         ret = MCIERR_NULL_PARAMETER_BLOCK;
936     } else if (wmw == NULL) {
937         ret = MCIERR_INVALID_DEVICE_ID;
938     } else {
939         TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
940         
941         switch(dwFlags) {
942         case MCI_INFO_PRODUCT:
943             str = "Wine's audio player";
944             break;
945         case MCI_INFO_FILE:
946             str = wmw->openParms.lpstrElementName;
947             break;
948         case MCI_WAVE_INPUT:
949             str = "Wine Wave In";
950             break;
951         case MCI_WAVE_OUTPUT:
952             str = "Wine Wave Out";
953             break;
954         default:
955             WARN("Don't know this info command (%lu)\n", dwFlags);
956             ret = MCIERR_UNRECOGNIZED_COMMAND;
957         }
958     }
959     if (str) {
960         if (strlen(str) + 1 > lpParms->dwRetSize) {
961             ret = MCIERR_PARAM_OVERFLOW;
962         } else {
963             lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
964         }
965     } else {
966         lpParms->lpstrReturn[0] = 0;
967     }
968     
969     return ret;
970 }
971
972 /**************************************************************************
973  *                              MCIWAVE_DriverProc              [sample driver]
974  */
975 LONG CALLBACK   MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
976                                    DWORD dwParam1, DWORD dwParam2)
977 {
978     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", 
979           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
980     
981     switch(wMsg) {
982     case DRV_LOAD:              return 1;
983     case DRV_FREE:              return 1;
984     case DRV_OPEN:              return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
985     case DRV_CLOSE:             return WAVE_drvClose(dwDevID);
986     case DRV_ENABLE:            return 1;
987     case DRV_DISABLE:           return 1;
988     case DRV_QUERYCONFIGURE:    return 1;
989     case DRV_CONFIGURE:         MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK);      return 1;
990     case DRV_INSTALL:           return DRVCNF_RESTART;
991     case DRV_REMOVE:            return DRVCNF_RESTART;
992     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA)  dwParam2);
993     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
994     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
995     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)        dwParam2);
996     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, (LPMCI_RECORD_PARMS)      dwParam2);
997     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
998     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_SET_PARMS)         dwParam2);
999     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1000     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1001     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
1002     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
1003     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMS16)      dwParam2);
1004     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);               
1005         /* commands that should be supported */
1006     case MCI_LOAD:              
1007     case MCI_SAVE:              
1008     case MCI_FREEZE:            
1009     case MCI_PUT:               
1010     case MCI_REALIZE:           
1011     case MCI_UNFREEZE:          
1012     case MCI_UPDATE:            
1013     case MCI_WHERE:             
1014     case MCI_STEP:              
1015     case MCI_SPIN:              
1016     case MCI_ESCAPE:            
1017     case MCI_COPY:              
1018     case MCI_CUT:               
1019     case MCI_DELETE:            
1020     case MCI_PASTE:             
1021         FIXME("Unsupported yet command=%s\n", MCI_MessageToString(wMsg));
1022         break;
1023     case MCI_WINDOW:            
1024         TRACE("Unsupported command=%s\n", MCI_MessageToString(wMsg));
1025         break;
1026     case MCI_OPEN:
1027     case MCI_CLOSE:
1028         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1029         break;
1030     default:
1031         FIXME("is probably wrong msg=%s\n", MCI_MessageToString(wMsg));
1032         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1033     }
1034     return MCIERR_UNRECOGNIZED_COMMAND;
1035 }