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