Correctly handle where waveOutGetPosition changes timepos.wType
[wine] / dlls / winmm / mciwave / mciwave.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * Sample Wine Driver for MCI wave forms
4  *
5  * Copyright    1994 Martin Ayotte
6  *              1999,2000 Eric Pouech
7  *              2000 Francois Jacques
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <stdarg.h>
25
26 #include "winerror.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "mmddk.h"
32 #include "wownt32.h"
33 #include "digitalv.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(mciwave);
38
39 typedef struct {
40     UINT                        wDevID;
41     HANDLE                      hWave;
42     int                         nUseCount;      /* Incremented for each shared open */
43     BOOL                        fShareable;     /* TRUE if first open was shareable */
44     HMMIO                       hFile;          /* mmio file handle open as Element */
45     MCI_WAVE_OPEN_PARMSW        openParms;
46     WAVEFORMATEX                wfxRef;
47     LPWAVEFORMATEX              lpWaveFormat;
48     BOOL                        fInput;         /* FALSE = Output, TRUE = Input */
49     volatile WORD               dwStatus;       /* one from MCI_MODE_xxxx */
50     DWORD                       dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
51     DWORD                       dwPosition;     /* position in bytes in chunk */
52     HANDLE                      hEvent;         /* for synchronization */
53     DWORD                       dwEventCount;   /* for synchronization */
54     BOOL                        bTemporaryFile; /* temporary file (MCI_RECORD) */
55     MMCKINFO                    ckMainRIFF;     /* main RIFF chunk */
56     MMCKINFO                    ckWaveData;     /* data chunk */
57 } WINE_MCIWAVE;
58
59 /* ===================================================================
60  * ===================================================================
61  * FIXME: should be using the new mmThreadXXXX functions from WINMM
62  * instead of those
63  * it would require to add a wine internal flag to mmThreadCreate
64  * in order to pass a 32 bit function instead of a 16 bit one
65  * ===================================================================
66  * =================================================================== */
67
68 struct SCA {
69     UINT        wDevID;
70     UINT        wMsg;
71     DWORD       dwParam1;
72     DWORD       dwParam2;
73 };
74
75 /**************************************************************************
76  *                              MCI_SCAStarter                  [internal]
77  */
78 static DWORD CALLBACK   MCI_SCAStarter(LPVOID arg)
79 {
80     struct SCA* sca = (struct SCA*)arg;
81     DWORD               ret;
82
83     TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
84           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
85     ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
86     TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
87           sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
88     HeapFree(GetProcessHeap(), 0, sca);
89     ExitThread(ret);
90     WARN("Should not happen ? what's wrong \n");
91     /* should not go after this point */
92     return ret;
93 }
94
95 /**************************************************************************
96  *                              MCI_SendCommandAsync            [internal]
97  */
98 static  DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
99                                    DWORD dwParam2, UINT size)
100 {
101     HANDLE handle;
102     struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
103
104     if (sca == 0)
105         return MCIERR_OUT_OF_MEMORY;
106
107     sca->wDevID   = wDevID;
108     sca->wMsg     = wMsg;
109     sca->dwParam1 = dwParam1;
110
111     if (size && dwParam2) {
112         sca->dwParam2 = (DWORD)sca + sizeof(struct SCA);
113         /* copy structure passed by program in dwParam2 to be sure
114          * we can still use it whatever the program does
115          */
116         memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
117     } else {
118         sca->dwParam2 = dwParam2;
119     }
120
121     if ((handle = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
122         WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
123         return MCI_SCAStarter(&sca);
124     }
125     CloseHandle(handle);
126     return 0;
127 }
128
129 /*======================================================================*
130  *                          MCI WAVE implemantation                     *
131  *======================================================================*/
132
133 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
134
135 /**************************************************************************
136  *                              MCIWAVE_drvOpen                 [internal]
137  */
138 static  DWORD   WAVE_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
139 {
140     WINE_MCIWAVE*       wmw;
141
142     if (modp == NULL) return 0xFFFFFFFF;
143
144     wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
145
146     if (!wmw)
147         return 0;
148
149     wmw->wDevID = modp->wDeviceID;
150     mciSetDriverData(wmw->wDevID, (DWORD)wmw);
151     modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
152     modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
153
154     wmw->wfxRef.wFormatTag      = WAVE_FORMAT_PCM;
155     wmw->wfxRef.nChannels       = 1;      /* MONO */
156     wmw->wfxRef.nSamplesPerSec  = 11025;
157     wmw->wfxRef.nAvgBytesPerSec = 11025;
158     wmw->wfxRef.nBlockAlign     = 1;
159     wmw->wfxRef.wBitsPerSample  = 8;
160     wmw->wfxRef.cbSize          = 0;      /* don't care */
161
162     return modp->wDeviceID;
163 }
164
165 /**************************************************************************
166  *                              MCIWAVE_drvClose                [internal]
167  */
168 static  DWORD   WAVE_drvClose(DWORD dwDevID)
169 {
170     WINE_MCIWAVE*  wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
171
172     if (wmw) {
173         HeapFree(GetProcessHeap(), 0, wmw);
174         mciSetDriverData(dwDevID, 0);
175         return 1;
176     }
177     return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
178 }
179
180 /**************************************************************************
181  *                              WAVE_mciGetOpenDev              [internal]
182  */
183 static WINE_MCIWAVE*  WAVE_mciGetOpenDev(UINT wDevID)
184 {
185     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
186
187     if (wmw == NULL || wmw->nUseCount == 0) {
188         WARN("Invalid wDevID=%u\n", wDevID);
189         return 0;
190     }
191     return wmw;
192 }
193
194 /**************************************************************************
195  *                              WAVE_ConvertByteToTimeFormat    [internal]
196  */
197 static  DWORD   WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
198 {
199     DWORD          ret = 0;
200
201     switch (wmw->dwMciTimeFormat) {
202     case MCI_FORMAT_MILLISECONDS:
203         ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec);
204         break;
205     case MCI_FORMAT_BYTES:
206         ret = val;
207         break;
208     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
209         ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
210         break;
211     default:
212         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
213     }
214     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
215     *lpRet = 0;
216     return ret;
217 }
218
219 /**************************************************************************
220  *                              WAVE_ConvertTimeFormatToByte    [internal]
221  */
222 static  DWORD   WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
223 {
224     DWORD       ret = 0;
225
226     switch (wmw->dwMciTimeFormat) {
227     case MCI_FORMAT_MILLISECONDS:
228         ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
229         break;
230     case MCI_FORMAT_BYTES:
231         ret = val;
232         break;
233     case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
234         ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
235         break;
236     default:
237         WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
238     }
239     TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
240     return ret;
241 }
242
243 /**************************************************************************
244  *                      WAVE_mciReadFmt                         [internal]
245  */
246 static  DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
247 {
248     MMCKINFO    mmckInfo;
249     long        r;
250
251     mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
252     if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
253         return MCIERR_INVALID_FILE;
254     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
255           (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
256
257     wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
258     if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
259     r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
260     if (r < sizeof(WAVEFORMAT))
261         return MCIERR_INVALID_FILE;
262
263     TRACE("wFormatTag=%04X !\n",   wmw->lpWaveFormat->wFormatTag);
264     TRACE("nChannels=%d \n",       wmw->lpWaveFormat->nChannels);
265     TRACE("nSamplesPerSec=%ld\n",  wmw->lpWaveFormat->nSamplesPerSec);
266     TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
267     TRACE("nBlockAlign=%d \n",     wmw->lpWaveFormat->nBlockAlign);
268     TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
269     if (r >= (long)sizeof(WAVEFORMATEX))
270         TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
271
272     mmioAscend(wmw->hFile, &mmckInfo, 0);
273     wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
274     if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
275         TRACE("can't find data chunk\n");
276         return MCIERR_INVALID_FILE;
277     }
278     TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
279           (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
280     TRACE("nChannels=%d nSamplesPerSec=%ld\n",
281           wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
282
283     return 0;
284 }
285
286 /**************************************************************************
287  *                      WAVE_mciCreateRIFFSkeleton              [internal]
288  */
289 static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
290 {
291    MMCKINFO     ckWaveFormat;
292    LPMMCKINFO   lpckRIFF     = &(wmw->ckMainRIFF);
293    LPMMCKINFO   lpckWaveData = &(wmw->ckWaveData);
294
295    lpckRIFF->ckid    = FOURCC_RIFF;
296    lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
297    lpckRIFF->cksize  = 0;
298
299    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF))
300         goto err;
301
302    ckWaveFormat.fccType = 0;
303    ckWaveFormat.ckid    = mmioFOURCC('f', 'm', 't', ' ');
304    ckWaveFormat.cksize  = sizeof(PCMWAVEFORMAT);
305
306    if (!wmw->lpWaveFormat)
307    {
308        wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmw->lpWaveFormat));
309        if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
310        memcpy(wmw->lpWaveFormat, &wmw->wfxRef, sizeof(wmw->wfxRef));
311    }
312
313    /* we can only record PCM files... there is no way in the MCI API to specify
314     * the necessary data to initialize the extra bytes of the WAVEFORMATEX
315     * structure
316     */
317    if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
318        goto err;
319
320    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
321         goto err;
322
323    if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, sizeof(PCMWAVEFORMAT)))
324         goto err;
325
326    if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
327         goto err;
328
329    lpckWaveData->cksize  = 0;
330    lpckWaveData->fccType = 0;
331    lpckWaveData->ckid    = mmioFOURCC('d', 'a', 't', 'a');
332
333    /* create data chunk */
334    if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
335         goto err;
336
337    return 0;
338
339 err:
340    HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
341    wmw->lpWaveFormat = NULL;
342    return MCIERR_INVALID_FILE;
343 }
344
345 /**************************************************************************
346  *                      WAVE_mciOpen                            [internal]
347  */
348 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSW lpOpenParms)
349 {
350     DWORD               dwRet = 0;
351     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
352     WCHAR*              pszTmpFileName = 0;
353
354     TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
355     if (lpOpenParms == NULL)    return MCIERR_NULL_PARAMETER_BLOCK;
356     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
357
358     if (dwFlags & MCI_OPEN_SHAREABLE)
359         return MCIERR_HARDWARE;
360
361     if (wmw->nUseCount > 0) {
362         /* The driver is already opened on this channel
363          * Wave driver cannot be shared
364          */
365         return MCIERR_DEVICE_OPEN;
366     }
367
368     wmw->nUseCount++;
369
370     wmw->fInput = FALSE;
371     wmw->hWave = 0;
372     wmw->dwStatus = MCI_MODE_NOT_READY;
373
374     TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
375
376     if (dwFlags & MCI_OPEN_ELEMENT) {
377         if (dwFlags & MCI_OPEN_ELEMENT_ID) {
378             /* could it be that (DWORD)lpOpenParms->lpstrElementName
379              * contains the hFile value ?
380              */
381             dwRet = MCIERR_UNRECOGNIZED_COMMAND;
382         } else {
383             if (strlenW(lpOpenParms->lpstrElementName) > 0) {
384                 lpOpenParms->lpstrElementName = lpOpenParms->lpstrElementName;
385
386                 /* FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
387                 TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpOpenParms->lpstrElementName));
388
389                 if (lpOpenParms->lpstrElementName && (strlenW(lpOpenParms->lpstrElementName) > 0)) {
390                     wmw->hFile = mmioOpenW((LPWSTR)lpOpenParms->lpstrElementName, NULL,
391                                            MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
392
393                     if (wmw->hFile == 0) {
394                         WARN("can't find file=%s!\n", debugstr_w(lpOpenParms->lpstrElementName));
395                         dwRet = MCIERR_FILE_NOT_FOUND;
396                     }
397                     else
398                     {
399                         LPMMCKINFO          lpckMainRIFF = &wmw->ckMainRIFF;
400
401                         /* make sure we're are the beginning of the file */
402                         mmioSeek(wmw->hFile, 0, SEEK_SET);
403
404                         /* first reading of this file. read the waveformat chunk */
405                         if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
406                             dwRet = MCIERR_INVALID_FILE;
407                         } else {
408                             TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
409                                 (LPSTR)&(lpckMainRIFF->ckid),
410                                 (LPSTR) &(lpckMainRIFF->fccType),
411                                 (lpckMainRIFF->cksize));
412
413                             if ((lpckMainRIFF->ckid    != FOURCC_RIFF) ||
414                                  lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
415                                 dwRet = MCIERR_INVALID_FILE;
416                             } else {
417                                 dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
418                             }
419                         }
420                     }
421                 }
422                 else {
423                     wmw->hFile = 0;
424                 }
425             }
426             else {
427                 WCHAR  szTmpPath[MAX_PATH];
428                 WCHAR  szPrefix[4];
429
430                 szPrefix[0] = 'T';
431                 szPrefix[1] = 'M';
432                 szPrefix[2] = 'P';
433                 szPrefix[3] = '\0';
434                 pszTmpFileName = HeapAlloc(GetProcessHeap(),
435                                            HEAP_ZERO_MEMORY,
436                                            MAX_PATH * sizeof(*pszTmpFileName));
437
438                 if (!GetTempPathW(sizeof(szTmpPath), szTmpPath)) {
439                     WARN("can't retrieve temp path!\n");
440                     HeapFree(GetProcessHeap(), 0, pszTmpFileName);
441                     return MCIERR_FILE_NOT_FOUND;
442                 }
443
444                 if (!GetTempFileNameW(szTmpPath, szPrefix, 0, pszTmpFileName)) {
445                     WARN("can't retrieve temp file name!\n");
446                     HeapFree(GetProcessHeap(), 0, pszTmpFileName);
447                     return MCIERR_FILE_NOT_FOUND;
448                 }
449
450                 wmw->bTemporaryFile = TRUE;
451
452                 TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(pszTmpFileName));
453
454                 if (pszTmpFileName && (strlenW(pszTmpFileName) > 0)) {
455
456                     wmw->hFile = mmioOpenW(pszTmpFileName, NULL,
457                                            MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
458
459                     if (wmw->hFile == 0) {
460                         WARN("can't create file=%s!\n", debugstr_w(pszTmpFileName));
461                         /* temporary file could not be created. clean filename. */
462                         HeapFree(GetProcessHeap(), 0, pszTmpFileName);
463                         dwRet = MCIERR_FILE_NOT_FOUND;
464                     }
465                 }
466             }
467         }
468     }
469
470     TRACE("hFile=%p\n", wmw->hFile);
471
472     memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
473
474     if (wmw->bTemporaryFile)
475     {
476             /* Additional openParms is temporary file's name */
477             wmw->openParms.lpstrElementName = pszTmpFileName;
478     }
479
480     if (dwRet == 0) {
481         if (wmw->lpWaveFormat) {
482             switch (wmw->lpWaveFormat->wFormatTag) {
483             case WAVE_FORMAT_PCM:
484                 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
485                     wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
486                     WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
487                         wmw->lpWaveFormat->nAvgBytesPerSec,
488                         wmw->lpWaveFormat->nSamplesPerSec *
489                          wmw->lpWaveFormat->nBlockAlign);
490                     wmw->lpWaveFormat->nAvgBytesPerSec =
491                         wmw->lpWaveFormat->nSamplesPerSec *
492                         wmw->lpWaveFormat->nBlockAlign;
493                 }
494                 break;
495             }
496         }
497         wmw->dwPosition = 0;
498
499         wmw->dwStatus = MCI_MODE_STOP;
500     } else {
501         wmw->nUseCount--;
502         if (wmw->hFile != 0)
503             mmioClose(wmw->hFile, 0);
504         wmw->hFile = 0;
505     }
506     return dwRet;
507 }
508
509 /**************************************************************************
510  *                               WAVE_mciCue             [internal]
511  */
512 static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
513 {
514     /*
515       FIXME
516
517       This routine is far from complete. At the moment only a check is done on the
518       MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
519       is the default.
520
521       The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
522       are ignored
523     */
524
525     DWORD               dwRet;
526     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
527
528     FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
529
530     if (wmw == NULL)    return MCIERR_INVALID_DEVICE_ID;
531
532     /* always close elements ? */
533     if (wmw->hFile != 0) {
534         mmioClose(wmw->hFile, 0);
535         wmw->hFile = 0;
536     }
537
538     dwRet = MMSYSERR_NOERROR;  /* assume success */
539
540     if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
541         dwRet = waveOutClose(wmw->hWave);
542         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
543         wmw->fInput = TRUE;
544     } else if (wmw->fInput) {
545         dwRet = waveInClose(wmw->hWave);
546         if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
547         wmw->fInput = FALSE;
548     }
549     wmw->hWave = 0;
550     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
551 }
552
553 /**************************************************************************
554  *                              WAVE_mciStop                    [internal]
555  */
556 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
557 {
558     DWORD               dwRet = 0;
559     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
560
561     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
562
563     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
564
565     /* wait for playback thread (if any) to exit before processing further */
566     switch (wmw->dwStatus) {
567     case MCI_MODE_PAUSE:
568     case MCI_MODE_PLAY:
569     case MCI_MODE_RECORD:
570         {
571             int oldStat = wmw->dwStatus;
572             wmw->dwStatus = MCI_MODE_NOT_READY;
573             if (oldStat == MCI_MODE_PAUSE)
574                 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
575         }
576         while (wmw->dwStatus != MCI_MODE_STOP)
577             Sleep(10);
578         break;
579     }
580
581     wmw->dwPosition = 0;
582
583     /* sanity resets */
584     wmw->dwStatus = MCI_MODE_STOP;
585
586     if ((dwFlags & MCI_NOTIFY) && lpParms) {
587         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
588                         wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
589     }
590
591     return dwRet;
592 }
593
594 /**************************************************************************
595  *                              WAVE_mciClose           [internal]
596  */
597 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
598 {
599     DWORD               dwRet = 0;
600     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
601
602     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
603
604     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
605
606     if (wmw->dwStatus != MCI_MODE_STOP) {
607         dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
608     }
609
610     wmw->nUseCount--;
611
612     if (wmw->nUseCount == 0) {
613         if (wmw->hFile != 0) {
614             mmioClose(wmw->hFile, 0);
615             wmw->hFile = 0;
616         }
617     }
618
619     /* That string got allocated in mciOpen because no filename was specified
620      * in MCI_OPEN_PARMS stucture. Cast-away const from string since it was
621      * allocated by mciOpen, *NOT* the application.
622      */
623     if (wmw->bTemporaryFile)
624     {
625         HeapFree(GetProcessHeap(), 0, (WCHAR*)wmw->openParms.lpstrElementName);
626         wmw->openParms.lpstrElementName = NULL;
627     }
628
629     HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
630     wmw->lpWaveFormat = NULL;
631
632     if ((dwFlags & MCI_NOTIFY) && lpParms) {
633         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
634                         wmw->openParms.wDeviceID,
635                         (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
636     }
637
638     return 0;
639 }
640
641 /**************************************************************************
642  *                              WAVE_mciPlayCallback            [internal]
643  */
644 static  void    CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
645                                               DWORD dwInstance,
646                                               DWORD dwParam1, DWORD dwParam2)
647 {
648     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
649
650     switch (uMsg) {
651     case WOM_OPEN:
652     case WOM_CLOSE:
653         break;
654     case WOM_DONE:
655         InterlockedIncrement(&wmw->dwEventCount);
656         TRACE("Returning waveHdr=%lx\n", dwParam1);
657         SetEvent(wmw->hEvent);
658         break;
659     default:
660         ERR("Unknown uMsg=%d\n", uMsg);
661     }
662 }
663
664 /******************************************************************
665  *              WAVE_mciPlayWaitDone
666  *
667  *
668  */
669 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
670 {
671     for (;;) {
672         ResetEvent(wmw->hEvent);
673         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
674             break;
675         }
676         InterlockedIncrement(&wmw->dwEventCount);
677
678         WaitForSingleObject(wmw->hEvent, INFINITE);
679     }
680 }
681
682 /**************************************************************************
683  *                              WAVE_mciPlay            [internal]
684  */
685 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
686 {
687     DWORD               end;
688     LONG                bufsize, count, left;
689     DWORD               dwRet = 0;
690     LPWAVEHDR           waveHdr = NULL;
691     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
692     int                 whidx;
693
694     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
695
696     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
697     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
698
699     /* FIXME : since there is no way to determine in which mode the device is
700      * open (recording/playback) automatically switch from a mode to another
701      */
702     wmw->fInput = FALSE;
703
704     if (wmw->fInput) {
705         WARN("cannot play on input device\n");
706         return MCIERR_NONAPPLICABLE_FUNCTION;
707     }
708
709     if (wmw->hFile == 0) {
710         WARN("Can't play: no file=%s!\n", debugstr_w(wmw->openParms.lpstrElementName));
711         return MCIERR_FILE_NOT_FOUND;
712     }
713
714     if (wmw->dwStatus == MCI_MODE_PAUSE) {
715         /* FIXME: parameters (start/end) in lpParams may not be used */
716         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
717     }
718
719     /** This function will be called again by a thread when async is used.
720      * We have to set MCI_MODE_PLAY before we do this so that the app can spin
721      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
722      */
723     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
724         return MCIERR_INTERNAL;
725     }
726
727     wmw->dwStatus = MCI_MODE_PLAY;
728
729     if (!(dwFlags & MCI_WAIT)) {
730         return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_PLAY, dwFlags,
731                                     (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
732     }
733
734     end = 0xFFFFFFFF;
735     if (lpParms && (dwFlags & MCI_FROM)) {
736         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
737     }
738     if (lpParms && (dwFlags & MCI_TO)) {
739         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
740     }
741
742     TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
743
744     if (end <= wmw->dwPosition)
745         return TRUE;
746
747
748 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
749 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
750
751     wmw->dwPosition        = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
752     wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
753
754     if (dwRet == 0) {
755         if (wmw->lpWaveFormat) {
756             switch (wmw->lpWaveFormat->wFormatTag) {
757             case WAVE_FORMAT_PCM:
758                 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
759                     wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
760                     WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
761                         wmw->lpWaveFormat->nAvgBytesPerSec,
762                         wmw->lpWaveFormat->nSamplesPerSec *
763                          wmw->lpWaveFormat->nBlockAlign);
764                     wmw->lpWaveFormat->nAvgBytesPerSec =
765                         wmw->lpWaveFormat->nSamplesPerSec *
766                         wmw->lpWaveFormat->nBlockAlign;
767                 }
768                 break;
769             }
770         }
771     } else {
772         TRACE("can't retrieve wave format %ld\n", dwRet);
773         goto cleanUp;
774     }
775
776
777     /* go back to beginning of chunk plus the requested position */
778     /* FIXME: I'm not sure this is correct, notably because some data linked to
779      * the decompression state machine will not be correcly initialized.
780      * try it this way (other way would be to decompress from 0 up to dwPosition
781      * and to start sending to hWave when dwPosition is reached)
782      */
783     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
784
785     /* By default the device will be opened for output, the MCI_CUE function is there to
786      * change from output to input and back
787      */
788     /* FIXME: how to choose between several output channels ? here mapper is forced */
789     dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
790                         (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
791
792     if (dwRet != 0) {
793         TRACE("Can't open low level audio device %ld\n", dwRet);
794         dwRet = MCIERR_DEVICE_OPEN;
795         wmw->hWave = 0;
796         goto cleanUp;
797     }
798
799     /* make it so that 3 buffers per second are needed */
800     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
801
802     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
803     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
804     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
805     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
806     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
807     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
808     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
809     if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
810         waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
811         dwRet = MCIERR_INTERNAL;
812         goto cleanUp;
813     }
814
815     whidx = 0;
816     left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition);
817     wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
818     wmw->dwEventCount = 1L; /* for first buffer */
819
820     TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
821
822     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
823     while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
824         count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
825         TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
826         if (count < 1)
827             break;
828         /* count is always <= bufsize, so this is correct regarding the
829          * waveOutPrepareHeader function
830          */
831         waveHdr[whidx].dwBufferLength = count;
832         waveHdr[whidx].dwFlags &= ~WHDR_DONE;
833         TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
834               &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
835               waveHdr[whidx].dwBytesRecorded);
836         dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
837         left -= count;
838         wmw->dwPosition += count;
839         TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
840
841         WAVE_mciPlayWaitDone(wmw);
842         whidx ^= 1;
843     }
844
845     WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
846
847     /* just to get rid of some race conditions between play, stop and pause */
848     waveOutReset(wmw->hWave);
849
850     waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
851     waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
852
853     dwRet = 0;
854
855 cleanUp:
856     HeapFree(GetProcessHeap(), 0, waveHdr);
857
858     if (wmw->hWave) {
859         waveOutClose(wmw->hWave);
860         wmw->hWave = 0;
861     }
862     CloseHandle(wmw->hEvent);
863
864     if (lpParms && (dwFlags & MCI_NOTIFY)) {
865         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
866                         wmw->openParms.wDeviceID,
867                         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
868     }
869
870     wmw->dwStatus = MCI_MODE_STOP;
871
872     return dwRet;
873 }
874
875 /**************************************************************************
876  *                              WAVE_mciPlayCallback            [internal]
877  */
878 static  void    CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
879                                                 DWORD dwInstance,
880                                                 DWORD dwParam1, DWORD dwParam2)
881 {
882     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
883     LPWAVEHDR           lpWaveHdr;
884     LONG                count = 0;
885
886     switch (uMsg) {
887     case WIM_OPEN:
888     case WIM_CLOSE:
889         break;
890     case WIM_DATA:
891         lpWaveHdr = (LPWAVEHDR) dwParam1;
892
893         InterlockedIncrement(&wmw->dwEventCount);
894
895         count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
896
897         lpWaveHdr->dwFlags &= ~WHDR_DONE;
898         if (count > 0)
899             wmw->dwPosition  += count;
900         /* else error reporting ?? */
901         if (wmw->dwStatus == MCI_MODE_RECORD)
902         {
903            /* Only queue up another buffer if we are recording.  We could receive this
904               message also when waveInReset() is called, since it notifies on all wave
905               buffers that are outstanding.  Queueing up more sometimes causes waveInClose
906               to fail. */
907            waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
908            TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
909         }
910
911         SetEvent(wmw->hEvent);
912         break;
913     default:
914         ERR("Unknown uMsg=%d\n", uMsg);
915     }
916 }
917
918 /******************************************************************
919  *              bWAVE_mciRecordWaitDone
920  *
921  */
922 static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
923 {
924     for (;;) {
925         ResetEvent(wmw->hEvent);
926         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
927             break;
928         }
929         InterlockedIncrement(&wmw->dwEventCount);
930
931         WaitForSingleObject(wmw->hEvent, INFINITE);
932     }
933 }
934
935 /**************************************************************************
936  *                              WAVE_mciRecord                  [internal]
937  */
938 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
939 {
940     DWORD               end;
941     DWORD               dwRet = MMSYSERR_NOERROR;
942     LONG                bufsize;
943     LPWAVEHDR           waveHdr = NULL;
944     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
945
946
947     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
948
949     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
950     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
951
952     /* FIXME : since there is no way to determine in which mode the device is
953      * open (recording/playback) automatically switch from a mode to another
954      */
955     wmw->fInput = TRUE;
956
957     if (!wmw->fInput) {
958         WARN("cannot record on output device\n");
959         return MCIERR_NONAPPLICABLE_FUNCTION;
960     }
961
962     if (wmw->dwStatus == MCI_MODE_PAUSE) {
963         /* FIXME: parameters (start/end) in lpParams may not be used */
964         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
965     }
966
967     /** This function will be called again by a thread when async is used.
968      * We have to set MCI_MODE_PLAY before we do this so that the app can spin
969      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
970      */
971     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
972         return MCIERR_INTERNAL;
973     }
974
975     wmw->dwStatus = MCI_MODE_RECORD;
976
977     if (!(dwFlags & MCI_WAIT)) {
978         return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_RECORD, dwFlags,
979                                     (DWORD)lpParms, sizeof(MCI_RECORD_PARMS));
980     }
981
982     if (!wmw->lpWaveFormat) {
983         /* new RIFF file */
984         dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
985     } else {
986         FIXME("Should descend into data chunk. Please report.\n");
987     }
988
989     end = 0xFFFFFFFF;
990     if (lpParms && (dwFlags & MCI_FROM)) {
991         wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
992     }
993
994     if (lpParms && (dwFlags & MCI_TO)) {
995         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
996     }
997
998     TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
999
1000     if (end <= wmw->dwPosition)
1001     {
1002         return TRUE;
1003     }
1004
1005 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1006 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1007
1008     wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
1009     wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1010
1011     /* go back to beginning of chunk plus the requested position */
1012     /* FIXME: I'm not sure this is correct, notably because some data linked to
1013      * the decompression state machine will not be correcly initialized.
1014      * try it this way (other way would be to decompress from 0 up to dwPosition
1015      * and to start sending to hWave when dwPosition is reached)
1016      */
1017     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1018
1019     /* By default the device will be opened for output, the MCI_CUE function is there to
1020      * change from output to input and back
1021      */
1022     /* FIXME: how to choose between several output channels ? here mapper is forced */
1023     dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
1024                         (DWORD)WAVE_mciRecordCallback, (DWORD)wmw, CALLBACK_FUNCTION);
1025
1026     if (dwRet != MMSYSERR_NOERROR) {
1027         TRACE("Can't open low level audio device %ld\n", dwRet);
1028         dwRet = MCIERR_DEVICE_OPEN;
1029         wmw->hWave = 0;
1030         goto cleanUp;
1031     }
1032
1033     /* make it so that 3 buffers per second are needed */
1034     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1035
1036     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1037     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1038     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1039     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
1040     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
1041     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
1042     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1043
1044     if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1045         waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1046         dwRet = MCIERR_INTERNAL;
1047         goto cleanUp;
1048     }
1049
1050     if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1051         waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1052         dwRet = MCIERR_INTERNAL;
1053         goto cleanUp;
1054     }
1055
1056     wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1057     wmw->dwEventCount = 1L; /* for first buffer */
1058
1059     TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1060
1061     dwRet = waveInStart(wmw->hWave);
1062
1063     while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1064         WAVE_mciRecordWaitDone(wmw);
1065     }
1066
1067     /* needed so that the callback above won't add again the buffers returned by the reset */
1068     wmw->dwStatus = MCI_MODE_STOP;
1069
1070     waveInReset(wmw->hWave);
1071
1072     waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1073     waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1074
1075     dwRet = 0;
1076
1077 cleanUp:
1078     HeapFree(GetProcessHeap(), 0, waveHdr);
1079
1080     if (wmw->hWave) {
1081         waveInClose(wmw->hWave);
1082         wmw->hWave = 0;
1083     }
1084     CloseHandle(wmw->hEvent);
1085
1086     /* need to update the size of the data chunk */
1087     if (mmioAscend(wmw->hFile, &wmw->ckWaveData, 0) != MMSYSERR_NOERROR) {
1088         TRACE("failed on ascend\n");
1089     }
1090
1091     if (lpParms && (dwFlags & MCI_NOTIFY)) {
1092         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1093                         wmw->openParms.wDeviceID,
1094                         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1095     }
1096
1097     wmw->dwStatus = MCI_MODE_STOP;
1098
1099     return dwRet;
1100
1101 }
1102
1103 /**************************************************************************
1104  *                              WAVE_mciPause                   [internal]
1105  */
1106 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1107 {
1108     DWORD               dwRet;
1109     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1110
1111     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1112
1113     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1114     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1115
1116     if (wmw->dwStatus == MCI_MODE_PLAY) {
1117         wmw->dwStatus = MCI_MODE_PAUSE;
1118     }
1119
1120     if (wmw->fInput)    dwRet = waveInStop(wmw->hWave);
1121     else                dwRet = waveOutPause(wmw->hWave);
1122
1123     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1124 }
1125
1126 /**************************************************************************
1127  *                              WAVE_mciResume                  [internal]
1128  */
1129 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1130 {
1131     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1132     DWORD               dwRet = 0;
1133
1134     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1135
1136     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1137
1138     if (wmw->dwStatus == MCI_MODE_PAUSE) {
1139         wmw->dwStatus = MCI_MODE_PLAY;
1140     }
1141
1142     if (wmw->fInput)    dwRet = waveInStart(wmw->hWave);
1143     else                dwRet = waveOutRestart(wmw->hWave);
1144     return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1145 }
1146
1147 /**************************************************************************
1148  *                              WAVE_mciSeek                    [internal]
1149  */
1150 static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1151 {
1152     DWORD               ret = 0;
1153     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1154
1155     TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1156
1157     if (lpParms == NULL) {
1158         ret = MCIERR_NULL_PARAMETER_BLOCK;
1159     } else if (wmw == NULL) {
1160         ret = MCIERR_INVALID_DEVICE_ID;
1161     } else {
1162         WAVE_mciStop(wDevID, MCI_WAIT, 0);
1163
1164         if (dwFlags & MCI_SEEK_TO_START) {
1165             wmw->dwPosition = 0;
1166         } else if (dwFlags & MCI_SEEK_TO_END) {
1167             wmw->dwPosition = wmw->ckWaveData.cksize;
1168         } else if (dwFlags & MCI_TO) {
1169             wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1170         } else {
1171             WARN("dwFlag doesn't tell where to seek to...\n");
1172             return MCIERR_MISSING_PARAMETER;
1173         }
1174
1175         TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
1176
1177         if (dwFlags & MCI_NOTIFY) {
1178             mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1179                             wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1180         }
1181     }
1182     return ret;
1183 }
1184
1185 /**************************************************************************
1186  *                              WAVE_mciSet                     [internal]
1187  */
1188 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1189 {
1190     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1191
1192     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1193
1194     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1195     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1196
1197     if (dwFlags & MCI_SET_TIME_FORMAT) {
1198         switch (lpParms->dwTimeFormat) {
1199         case MCI_FORMAT_MILLISECONDS:
1200             TRACE("MCI_FORMAT_MILLISECONDS !\n");
1201             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1202             break;
1203         case MCI_FORMAT_BYTES:
1204             TRACE("MCI_FORMAT_BYTES !\n");
1205             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1206             break;
1207         case MCI_FORMAT_SAMPLES:
1208             TRACE("MCI_FORMAT_SAMPLES !\n");
1209             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1210             break;
1211         default:
1212             WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
1213             return MCIERR_BAD_TIME_FORMAT;
1214         }
1215     }
1216     if (dwFlags & MCI_SET_VIDEO) {
1217         TRACE("No support for video !\n");
1218         return MCIERR_UNSUPPORTED_FUNCTION;
1219     }
1220     if (dwFlags & MCI_SET_DOOR_OPEN) {
1221         TRACE("No support for door open !\n");
1222         return MCIERR_UNSUPPORTED_FUNCTION;
1223     }
1224     if (dwFlags & MCI_SET_DOOR_CLOSED) {
1225         TRACE("No support for door close !\n");
1226         return MCIERR_UNSUPPORTED_FUNCTION;
1227     }
1228     if (dwFlags & MCI_SET_AUDIO) {
1229         if (dwFlags & MCI_SET_ON) {
1230             TRACE("MCI_SET_ON audio !\n");
1231         } else if (dwFlags & MCI_SET_OFF) {
1232             TRACE("MCI_SET_OFF audio !\n");
1233         } else {
1234             WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1235             return MCIERR_BAD_INTEGER;
1236         }
1237
1238         switch (lpParms->dwAudio)
1239         {
1240         case MCI_SET_AUDIO_ALL:         TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1241         case MCI_SET_AUDIO_LEFT:        TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1242         case MCI_SET_AUDIO_RIGHT:       TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1243         default:                        WARN("Unknown audio channel %lu\n", lpParms->dwAudio); break;
1244         }
1245     }
1246     if (dwFlags & MCI_WAVE_INPUT)
1247         TRACE("MCI_WAVE_INPUT !\n");
1248     if (dwFlags & MCI_WAVE_OUTPUT)
1249         TRACE("MCI_WAVE_OUTPUT !\n");
1250     if (dwFlags & MCI_WAVE_SET_ANYINPUT)
1251         TRACE("MCI_WAVE_SET_ANYINPUT !\n");
1252     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
1253         TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
1254     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1255         wmw->wfxRef.nAvgBytesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nAvgBytesPerSec;
1256         TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %ld\n", wmw->wfxRef.nAvgBytesPerSec);
1257     }
1258     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1259         wmw->wfxRef.wBitsPerSample = ((LPMCI_WAVE_SET_PARMS)lpParms)->wBitsPerSample;
1260         TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1261     }
1262     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1263         wmw->wfxRef.nBlockAlign = ((LPMCI_WAVE_SET_PARMS)lpParms)->nBlockAlign;
1264         TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1265     }
1266     if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1267         wmw->wfxRef.nChannels = ((LPMCI_WAVE_SET_PARMS)lpParms)->nChannels;
1268         TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1269     }
1270     if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1271         wmw->wfxRef.wFormatTag = ((LPMCI_WAVE_SET_PARMS)lpParms)->wFormatTag;
1272         TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", wmw->wfxRef.wFormatTag);
1273     }
1274     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1275         wmw->wfxRef.nSamplesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nSamplesPerSec;
1276         TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %ld\n", wmw->wfxRef.nSamplesPerSec);
1277     }
1278     return 0;
1279 }
1280
1281 /**************************************************************************
1282  *                              WAVE_mciSave            [internal]
1283  */
1284 static DWORD WAVE_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_SAVE_PARMSW lpParms)
1285 {
1286     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1287     DWORD               ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1288     WPARAM              wparam = MCI_NOTIFY_FAILURE;
1289
1290     TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1291     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1292     if (wmw     == NULL)        return MCIERR_INVALID_DEVICE_ID;
1293
1294     if (dwFlags & MCI_WAIT)
1295     {
1296         FIXME("MCI_WAIT not implemented\n");
1297     }
1298
1299     ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1300     ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1301
1302
1303     ret = mmioClose(wmw->hFile, 0);
1304
1305     /*
1306       If the destination file already exists, it has to be overwritten.  (Behaviour
1307       verified in Windows (2000)).  If it doesn't overwrite, it is breaking one of
1308       my applications.  We are making use of mmioRename, which WILL NOT overwrite
1309       the destination file (which is what Windows does, also verified in Win2K)
1310       So, lets delete the destination file before calling mmioRename.  If the
1311       destination file DOESN'T exist, the delete will fail silently.  Let's also be
1312       careful not to lose our previous error code.
1313     */
1314     tmpRet = GetLastError();
1315     DeleteFileW (lpParms->lpfilename);
1316     SetLastError(tmpRet);
1317
1318     if (0 == mmioRenameW(wmw->openParms.lpstrElementName, lpParms->lpfilename, 0, 0 )) {
1319         ret = ERROR_SUCCESS;
1320     }
1321
1322     if (dwFlags & MCI_NOTIFY) {
1323         if (ret == ERROR_SUCCESS) wparam = MCI_NOTIFY_SUCCESSFUL;
1324
1325         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1326                          wmw->openParms.wDeviceID, wparam);
1327     }
1328
1329     return ret;
1330 }
1331
1332 /**************************************************************************
1333  *                              WAVE_mciStatus          [internal]
1334  */
1335 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1336 {
1337     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1338     DWORD               ret = 0;
1339
1340     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1341     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1342     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1343
1344     if (dwFlags & MCI_STATUS_ITEM) {
1345         switch (lpParms->dwItem) {
1346         case MCI_STATUS_CURRENT_TRACK:
1347             lpParms->dwReturn = 1;
1348             TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1349             break;
1350         case MCI_STATUS_LENGTH:
1351             if (!wmw->hFile) {
1352                 lpParms->dwReturn = 0;
1353                 return MCIERR_UNSUPPORTED_FUNCTION;
1354             }
1355             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1356             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
1357             TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1358             break;
1359         case MCI_STATUS_MODE:
1360             TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1361             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1362             ret = MCI_RESOURCE_RETURNED;
1363             break;
1364         case MCI_STATUS_MEDIA_PRESENT:
1365             TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1366             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1367             ret = MCI_RESOURCE_RETURNED;
1368             break;
1369         case MCI_STATUS_NUMBER_OF_TRACKS:
1370             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1371             lpParms->dwReturn = 1;
1372             TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
1373             break;
1374         case MCI_STATUS_POSITION:
1375             if (!wmw->hFile) {
1376                 lpParms->dwReturn = 0;
1377                 return MCIERR_UNSUPPORTED_FUNCTION;
1378             }
1379             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1380             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1381                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
1382                                                              &ret);
1383             TRACE("MCI_STATUS_POSITION %s => %lu\n",
1384                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1385             break;
1386         case MCI_STATUS_READY:
1387             lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1388                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1389             TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1390             ret = MCI_RESOURCE_RETURNED;
1391             break;
1392         case MCI_STATUS_TIME_FORMAT:
1393             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, MCI_FORMAT_RETURN_BASE + wmw->dwMciTimeFormat);
1394             TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1395             ret = MCI_RESOURCE_RETURNED;
1396             break;
1397         case MCI_WAVE_INPUT:
1398             TRACE("MCI_WAVE_INPUT !\n");
1399             lpParms->dwReturn = 0;
1400             ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1401             break;
1402         case MCI_WAVE_OUTPUT:
1403             TRACE("MCI_WAVE_OUTPUT !\n");
1404             {
1405                 UINT    id;
1406                 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
1407                     lpParms->dwReturn = id;
1408                 } else {
1409                     lpParms->dwReturn = 0;
1410                     ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1411                 }
1412             }
1413             break;
1414         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1415             if (!wmw->hFile) {
1416                 lpParms->dwReturn = 0;
1417                 return MCIERR_UNSUPPORTED_FUNCTION;
1418             }
1419             lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1420             TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1421             break;
1422         case MCI_WAVE_STATUS_BITSPERSAMPLE:
1423             if (!wmw->hFile) {
1424                 lpParms->dwReturn = 0;
1425                 return MCIERR_UNSUPPORTED_FUNCTION;
1426             }
1427             lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1428             TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1429             break;
1430         case MCI_WAVE_STATUS_BLOCKALIGN:
1431             if (!wmw->hFile) {
1432                 lpParms->dwReturn = 0;
1433                 return MCIERR_UNSUPPORTED_FUNCTION;
1434             }
1435             lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1436             TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1437             break;
1438         case MCI_WAVE_STATUS_CHANNELS:
1439             if (!wmw->hFile) {
1440                 lpParms->dwReturn = 0;
1441                 return MCIERR_UNSUPPORTED_FUNCTION;
1442             }
1443             lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1444             TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1445             break;
1446         case MCI_WAVE_STATUS_FORMATTAG:
1447             if (!wmw->hFile) {
1448                 lpParms->dwReturn = 0;
1449                 return MCIERR_UNSUPPORTED_FUNCTION;
1450             }
1451             lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1452             TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1453             break;
1454         case MCI_WAVE_STATUS_LEVEL:
1455             TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1456             lpParms->dwReturn = 0xAAAA5555;
1457             break;
1458         case MCI_WAVE_STATUS_SAMPLESPERSEC:
1459             if (!wmw->hFile) {
1460                 lpParms->dwReturn = 0;
1461                 return MCIERR_UNSUPPORTED_FUNCTION;
1462             }
1463             lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1464             TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1465             break;
1466         default:
1467             WARN("unknown command %08lX !\n", lpParms->dwItem);
1468             return MCIERR_UNRECOGNIZED_COMMAND;
1469         }
1470     }
1471     if (dwFlags & MCI_NOTIFY) {
1472         mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1473                         wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1474     }
1475     return ret;
1476 }
1477
1478 /**************************************************************************
1479  *                              WAVE_mciGetDevCaps              [internal]
1480  */
1481 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1482                                 LPMCI_GETDEVCAPS_PARMS lpParms)
1483 {
1484     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1485     DWORD               ret = 0;
1486
1487     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1488
1489     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1490     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1491
1492     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1493         switch(lpParms->dwItem) {
1494         case MCI_GETDEVCAPS_DEVICE_TYPE:
1495             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1496             ret = MCI_RESOURCE_RETURNED;
1497             break;
1498         case MCI_GETDEVCAPS_HAS_AUDIO:
1499             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1500             ret = MCI_RESOURCE_RETURNED;
1501             break;
1502         case MCI_GETDEVCAPS_HAS_VIDEO:
1503             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1504             ret = MCI_RESOURCE_RETURNED;
1505             break;
1506         case MCI_GETDEVCAPS_USES_FILES:
1507             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1508             ret = MCI_RESOURCE_RETURNED;
1509             break;
1510         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1511             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1512             ret = MCI_RESOURCE_RETURNED;
1513             break;
1514         case MCI_GETDEVCAPS_CAN_RECORD:
1515             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1516             ret = MCI_RESOURCE_RETURNED;
1517             break;
1518         case MCI_GETDEVCAPS_CAN_EJECT:
1519             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1520             ret = MCI_RESOURCE_RETURNED;
1521             break;
1522         case MCI_GETDEVCAPS_CAN_PLAY:
1523             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1524             ret = MCI_RESOURCE_RETURNED;
1525             break;
1526         case MCI_GETDEVCAPS_CAN_SAVE:
1527             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1528             ret = MCI_RESOURCE_RETURNED;
1529             break;
1530         case MCI_WAVE_GETDEVCAPS_INPUTS:
1531             lpParms->dwReturn = 1;
1532             break;
1533         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1534             lpParms->dwReturn = 1;
1535             break;
1536         default:
1537             FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1538             return MCIERR_UNRECOGNIZED_COMMAND;
1539         }
1540     } else {
1541         WARN("No GetDevCaps-Item !\n");
1542         return MCIERR_UNRECOGNIZED_COMMAND;
1543     }
1544     return ret;
1545 }
1546
1547 /**************************************************************************
1548  *                              WAVE_mciInfo                    [internal]
1549  */
1550 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
1551 {
1552     DWORD               ret = 0;
1553     LPCWSTR             str = 0;
1554     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1555
1556     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1557
1558     if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1559         ret = MCIERR_NULL_PARAMETER_BLOCK;
1560     } else if (wmw == NULL) {
1561         ret = MCIERR_INVALID_DEVICE_ID;
1562     } else {
1563         static const WCHAR wszAudio  [] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','p','l','a','y','e','r',0};
1564         static const WCHAR wszWaveIn [] = {'W','i','n','e',' ','W','a','v','e',' ','I','n',0};
1565         static const WCHAR wszWaveOut[] = {'W','i','n','e',' ','W','a','v','e',' ','O','u','t',0};
1566
1567         TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1568
1569         switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1570         case MCI_INFO_PRODUCT: str = wszAudio; break;
1571         case MCI_INFO_FILE:    str = wmw->openParms.lpstrElementName; break;
1572         case MCI_WAVE_INPUT:   str = wszWaveIn; break;
1573         case MCI_WAVE_OUTPUT:  str = wszWaveOut; break;
1574         default:
1575             WARN("Don't know this info command (%lu)\n", dwFlags);
1576             ret = MCIERR_UNRECOGNIZED_COMMAND;
1577         }
1578     }
1579     if (str) {
1580         if (strlenW(str) + 1 > lpParms->dwRetSize) {
1581             ret = MCIERR_PARAM_OVERFLOW;
1582         } else {
1583             lstrcpynW(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1584         }
1585     } else {
1586         lpParms->lpstrReturn[0] = 0;
1587     }
1588
1589     return ret;
1590 }
1591
1592 /**************************************************************************
1593  *                              DriverProc (MCIWAVE.@)
1594  */
1595 LONG CALLBACK   MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1596                                    DWORD dwParam1, DWORD dwParam2)
1597 {
1598     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1599           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1600
1601     switch (wMsg) {
1602     case DRV_LOAD:              return 1;
1603     case DRV_FREE:              return 1;
1604     case DRV_OPEN:              return WAVE_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1605     case DRV_CLOSE:             return WAVE_drvClose(dwDevID);
1606     case DRV_ENABLE:            return 1;
1607     case DRV_DISABLE:           return 1;
1608     case DRV_QUERYCONFIGURE:    return 1;
1609     case DRV_CONFIGURE:         MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK);      return 1;
1610     case DRV_INSTALL:           return DRVCNF_RESTART;
1611     case DRV_REMOVE:            return DRVCNF_RESTART;
1612     }
1613
1614     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1615
1616     switch (wMsg) {
1617     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSW)  dwParam2);
1618     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1619     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1620     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, (LPMCI_PLAY_PARMS)        dwParam2);
1621     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, (LPMCI_RECORD_PARMS)      dwParam2);
1622     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1623     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_SET_PARMS)         dwParam2);
1624     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1625     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1626     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
1627     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
1628     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMSW)       dwParam2);
1629     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);
1630     case MCI_SAVE:              return WAVE_mciSave      (dwDevID, dwParam1, (LPMCI_SAVE_PARMSW)       dwParam2);
1631         /* commands that should be supported */
1632     case MCI_LOAD:
1633     case MCI_FREEZE:
1634     case MCI_PUT:
1635     case MCI_REALIZE:
1636     case MCI_UNFREEZE:
1637     case MCI_UPDATE:
1638     case MCI_WHERE:
1639     case MCI_STEP:
1640     case MCI_SPIN:
1641     case MCI_ESCAPE:
1642     case MCI_COPY:
1643     case MCI_CUT:
1644     case MCI_DELETE:
1645     case MCI_PASTE:
1646         FIXME("Unsupported yet command [%lu]\n", wMsg);
1647         break;
1648     case MCI_WINDOW:
1649         TRACE("Unsupported command [%lu]\n", wMsg);
1650         break;
1651         /* option which can be silenced */
1652     case MCI_CONFIGURE:
1653         return 0;
1654     case MCI_OPEN:
1655     case MCI_CLOSE:
1656         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1657         break;
1658     default:
1659         FIXME("is probably wrong msg [%lu]\n", wMsg);
1660         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1661     }
1662     return MCIERR_UNRECOGNIZED_COMMAND;
1663 }