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