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