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