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