d3dx9_36/tests: Move surface tests into surface.c.
[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 >= (long)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, (void*)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 are 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     }
572     return dwRet;
573 }
574
575 /**************************************************************************
576  *                               WAVE_mciCue             [internal]
577  */
578 static DWORD WAVE_mciCue(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
579 {
580     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
581
582     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
583
584     /* Tests on systems without sound drivers show that Cue, like
585      * Record and Play, opens winmm, returning MCIERR_WAVE_xyPUTSUNSUITABLE.
586      * The first Cue Notify does not immediately return the
587      * notification, as if a player or recorder thread is started.
588      * PAUSE mode is reported when successful, but this mode is
589      * different from the normal Pause, because a) Pause then returns
590      * NONAPPLICABLE_FUNCTION instead of 0 and b) Set Channels etc. is
591      * still accepted, returning the original notification as ABORTED.
592      * I.e. Cue allows subsequent format changes, unlike Record or
593      * Open file, closes winmm if the format changes and stops this
594      * thread.
595      * Wine creates one player or recorder thread per async. Play or
596      * Record command.  Notification behaviour suggests that MS-W*
597      * reuses a single thread to improve response times.  Having Cue
598      * start this thread early helps to improve Play/Record's initial
599      * response time.  In effect, Cue is a performance hint, which
600      * justifies our almost no-op implementation.
601      */
602
603     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
604     if (wmw->dwStatus != MCI_MODE_STOP) return MCIERR_NONAPPLICABLE_FUNCTION;
605
606     if ((dwFlags & MCI_NOTIFY) && lpParms)
607         WAVE_mciNotify(lpParms->dwCallback,wmw,MCI_NOTIFY_SUCCESSFUL);
608
609     return MMSYSERR_NOERROR;
610 }
611
612 /**************************************************************************
613  *                              WAVE_mciStop                    [internal]
614  */
615 static DWORD WAVE_mciStop(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
616 {
617     DWORD               dwRet = 0;
618     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
619
620     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
621
622     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
623
624     if (wmw->dwStatus != MCI_MODE_STOP) {
625         HANDLE old = InterlockedExchangePointer(&wmw->hCallback, NULL);
626         if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_ABORTED);
627     }
628
629     /* wait for playback thread (if any) to exit before processing further */
630     switch (wmw->dwStatus) {
631     case MCI_MODE_PAUSE:
632     case MCI_MODE_PLAY:
633     case MCI_MODE_RECORD:
634         {
635             int oldStat = wmw->dwStatus;
636             wmw->dwStatus = MCI_MODE_NOT_READY;
637             if (oldStat == MCI_MODE_PAUSE)
638                 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
639         }
640         while (wmw->dwStatus != MCI_MODE_STOP)
641             Sleep(10);
642         break;
643     }
644
645     /* sanity resets */
646     wmw->dwStatus = MCI_MODE_STOP;
647
648     if ((dwFlags & MCI_NOTIFY) && lpParms && MMSYSERR_NOERROR==dwRet)
649         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
650
651     return dwRet;
652 }
653
654 /**************************************************************************
655  *                              WAVE_mciClose           [internal]
656  */
657 static DWORD WAVE_mciClose(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
658 {
659     DWORD               dwRet = 0;
660     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
661
662     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
663
664     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
665
666     if (wmw->dwStatus != MCI_MODE_STOP) {
667         /* mciStop handles MCI_NOTIFY_ABORTED */
668         dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
669     }
670
671     wmw->nUseCount--;
672
673     if (wmw->nUseCount == 0) {
674         if (wmw->hFile != 0) {
675             mmioClose(wmw->hFile, 0);
676             wmw->hFile = 0;
677         }
678     }
679
680     if (wmw->lpWaveFormat != &wmw->wfxRef)
681         HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
682     wmw->lpWaveFormat = &wmw->wfxRef;
683     HeapFree(GetProcessHeap(), 0, (void*)wmw->lpFileName);
684     wmw->lpFileName = NULL;
685
686     if ((dwFlags & MCI_NOTIFY) && lpParms) {
687         WAVE_mciNotify(lpParms->dwCallback, wmw,
688             (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
689     }
690
691     return 0;
692 }
693
694 /**************************************************************************
695  *                              WAVE_mciPlayCallback            [internal]
696  */
697 static  void    CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
698                                               DWORD_PTR dwInstance,
699                                               LPARAM dwParam1, LPARAM dwParam2)
700 {
701     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
702
703     switch (uMsg) {
704     case WOM_OPEN:
705     case WOM_CLOSE:
706         break;
707     case WOM_DONE:
708         InterlockedIncrement(&wmw->dwEventCount);
709         TRACE("Returning waveHdr=%lx\n", dwParam1);
710         SetEvent(wmw->hEvent);
711         break;
712     default:
713         ERR("Unknown uMsg=%d\n", uMsg);
714     }
715 }
716
717 /******************************************************************
718  *                      WAVE_mciPlayWaitDone            [internal]
719  */
720 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
721 {
722     for (;;) {
723         ResetEvent(wmw->hEvent);
724         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
725             break;
726         }
727         InterlockedIncrement(&wmw->dwEventCount);
728
729         WaitForSingleObject(wmw->hEvent, INFINITE);
730     }
731 }
732
733 /**************************************************************************
734  *                              WAVE_mciPlay            [internal]
735  */
736 static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
737 {
738     LPMCI_PLAY_PARMS    lpParms = (void*)pmt;
739     DWORD               end;
740     LONG                bufsize, count, left;
741     DWORD               dwRet;
742     LPWAVEHDR           waveHdr = NULL;
743     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
744     HANDLE              oldcb;
745     int                 whidx;
746
747     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
748
749     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
750     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
751
752     if (wmw->hFile == 0) {
753         WARN("Can't play: no file=%s!\n", debugstr_w(wmw->lpFileName));
754         return MCIERR_FILE_NOT_FOUND;
755     }
756
757     if (wmw->dwStatus == MCI_MODE_PAUSE && !wmw->fInput) {
758         /* FIXME: parameters (start/end) in lpParams may not be used */
759         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
760     }
761
762     /** This function will be called again by a thread when async is used.
763      * We have to set MCI_MODE_PLAY before we do this so that the app can spin
764      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
765      */
766     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
767         return MCIERR_INTERNAL;
768     }
769
770     if (wmw->lpWaveFormat->wFormatTag == WAVE_FORMAT_PCM) {
771         if (wmw->lpWaveFormat->nBlockAlign !=
772             wmw->lpWaveFormat->nChannels * wmw->lpWaveFormat->wBitsPerSample/8) {
773             WARN("Incorrect nBlockAlign (%d), setting it to %d\n",
774                 wmw->lpWaveFormat->nBlockAlign,
775                 wmw->lpWaveFormat->nChannels *
776                  wmw->lpWaveFormat->wBitsPerSample/8);
777             wmw->lpWaveFormat->nBlockAlign =
778                 wmw->lpWaveFormat->nChannels *
779                 wmw->lpWaveFormat->wBitsPerSample/8;
780         }
781         if (wmw->lpWaveFormat->nAvgBytesPerSec !=
782             wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
783             WARN("Incorrect nAvgBytesPerSec (%d), setting it to %d\n",
784                 wmw->lpWaveFormat->nAvgBytesPerSec,
785                 wmw->lpWaveFormat->nSamplesPerSec *
786                  wmw->lpWaveFormat->nBlockAlign);
787             wmw->lpWaveFormat->nAvgBytesPerSec =
788                 wmw->lpWaveFormat->nSamplesPerSec *
789                 wmw->lpWaveFormat->nBlockAlign;
790         }
791     }
792
793     end = wmw->ckWaveData.cksize;
794     if (lpParms && (dwFlags & MCI_TO)) {
795         DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
796         if (position > end)             return MCIERR_OUTOFRANGE;
797         end = position;
798     }
799     if (lpParms && (dwFlags & MCI_FROM)) {
800         DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
801         if (position > end)             return MCIERR_OUTOFRANGE;
802         /* Seek rounds down, so do we. */
803         position /= wmw->lpWaveFormat->nBlockAlign;
804         position *= wmw->lpWaveFormat->nBlockAlign;
805         wmw->dwPosition = position;
806     }
807     if (end < wmw->dwPosition) return MCIERR_OUTOFRANGE;
808     left = end - wmw->dwPosition;
809     if (0==left) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
810
811     wmw->fInput = FALSE; /* FIXME: waveInOpen may have been called. */
812     wmw->dwStatus = MCI_MODE_PLAY;
813
814     if (!(dwFlags & MCI_WAIT)) {
815         return MCI_SendCommandAsync(wDevID, WAVE_mciPlay, dwFlags,
816                                     (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS));
817     }
818
819     TRACE("Playing from byte=%u to byte=%u\n", wmw->dwPosition, end);
820
821     oldcb = InterlockedExchangePointer(&wmw->hCallback,
822         (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
823     if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
824     oldcb = NULL;
825
826 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
827 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
828
829     /* go back to beginning of chunk plus the requested position */
830     /* FIXME: I'm not sure this is correct, notably because some data linked to
831      * the decompression state machine will not be correctly initialized.
832      * try it this way (other way would be to decompress from 0 up to dwPosition
833      * and to start sending to hWave when dwPosition is reached)
834      */
835     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
836
837     dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, wmw->wOutput, wmw->lpWaveFormat,
838                         (DWORD_PTR)WAVE_mciPlayCallback, (DWORD_PTR)wmw, CALLBACK_FUNCTION);
839
840     if (dwRet != 0) {
841         TRACE("Can't open low level audio device %d\n", dwRet);
842         dwRet = MCIERR_DEVICE_OPEN;
843         wmw->hWave = 0;
844         goto cleanUp;
845     }
846
847     /* make it so that 3 buffers per second are needed */
848     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
849
850     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
851     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
852     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
853     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
854     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
855     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
856     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
857     if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
858         waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
859         dwRet = MCIERR_INTERNAL;
860         goto cleanUp;
861     }
862
863     whidx = 0;
864     wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
865     wmw->dwEventCount = 1L; /* for first buffer */
866
867     TRACE("Playing (normalized) from byte=%u for %u bytes\n", wmw->dwPosition, left);
868     if (hEvent) SetEvent(hEvent);
869
870     /* FIXME: this doesn't work if wmw->dwPosition != 0 */
871     while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
872         count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
873         TRACE("mmioRead bufsize=%d count=%d\n", bufsize, count);
874         if (count < 1)
875             break;
876         /* count is always <= bufsize, so this is correct regarding the
877          * waveOutPrepareHeader function
878          */
879         waveHdr[whidx].dwBufferLength = count;
880         waveHdr[whidx].dwFlags &= ~WHDR_DONE;
881         TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%u\n",
882               &waveHdr[whidx], waveHdr[whidx].dwBufferLength);
883         dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
884         if (dwRet) {
885             ERR("Aborting play loop, WODM_WRITE error %d\n", dwRet);
886             dwRet = MCIERR_HARDWARE;
887             break;
888         }
889         left -= count;
890         wmw->dwPosition += count;
891         TRACE("after WODM_WRITE dwPosition=%u\n", wmw->dwPosition);
892         /* InterlockedDecrement if and only if waveOutWrite is successful */
893         WAVE_mciPlayWaitDone(wmw);
894         whidx ^= 1;
895     }
896
897     WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
898
899     /* just to get rid of some race conditions between play, stop and pause */
900     waveOutReset(wmw->hWave);
901
902     waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
903     waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
904
905 cleanUp:
906     if (dwFlags & MCI_NOTIFY)
907         oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
908
909     HeapFree(GetProcessHeap(), 0, waveHdr);
910
911     if (wmw->hWave) {
912         waveOutClose(wmw->hWave);
913         wmw->hWave = 0;
914     }
915     CloseHandle(wmw->hEvent);
916
917     wmw->dwStatus = MCI_MODE_STOP;
918
919     /* Let the potentically asynchronous commands support FAILURE notification. */
920     if (oldcb) mciDriverNotify(oldcb, wDevID,
921         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
922
923     return dwRet;
924 }
925
926 /**************************************************************************
927  *                              WAVE_mciRecordCallback          [internal]
928  */
929 static  void    CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
930                                                 DWORD_PTR dwInstance,
931                                                 LPARAM dwParam1, LPARAM dwParam2)
932 {
933     WINE_MCIWAVE*       wmw = (WINE_MCIWAVE*)dwInstance;
934     LPWAVEHDR           lpWaveHdr;
935     LONG                count = 0;
936
937     switch (uMsg) {
938     case WIM_OPEN:
939     case WIM_CLOSE:
940         break;
941     case WIM_DATA:
942         lpWaveHdr = (LPWAVEHDR) dwParam1;
943
944         InterlockedIncrement(&wmw->dwEventCount);
945
946         count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
947
948         lpWaveHdr->dwFlags &= ~WHDR_DONE;
949         if (count > 0)
950             wmw->dwPosition  += count;
951         /* else error reporting ?? */
952         if (wmw->dwStatus == MCI_MODE_RECORD)
953         {
954            /* Only queue up another buffer if we are recording.  We could receive this
955               message also when waveInReset() is called, since it notifies on all wave
956               buffers that are outstanding.  Queueing up more sometimes causes waveInClose
957               to fail. */
958            waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
959            TRACE("after mmioWrite dwPosition=%u\n", wmw->dwPosition);
960         }
961
962         SetEvent(wmw->hEvent);
963         break;
964     default:
965         ERR("Unknown uMsg=%d\n", uMsg);
966     }
967 }
968
969 /******************************************************************
970  *                      WAVE_mciRecordWaitDone          [internal]
971  */
972 static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
973 {
974     for (;;) {
975         ResetEvent(wmw->hEvent);
976         if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
977             break;
978         }
979         InterlockedIncrement(&wmw->dwEventCount);
980
981         WaitForSingleObject(wmw->hEvent, INFINITE);
982     }
983 }
984
985 /**************************************************************************
986  *                              WAVE_mciRecord                  [internal]
987  */
988 static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
989 {
990     LPMCI_RECORD_PARMS  lpParms = (void*)pmt;
991     DWORD               end;
992     DWORD               dwRet = MMSYSERR_NOERROR;
993     LONG                bufsize;
994     LPWAVEHDR           waveHdr = NULL;
995     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
996     HANDLE              oldcb;
997
998     TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
999
1000     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1001     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1002
1003     if (wmw->dwStatus == MCI_MODE_PAUSE && wmw->fInput) {
1004         /* FIXME: parameters (start/end) in lpParams may not be used */
1005         return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
1006     }
1007
1008     /** This function will be called again by a thread when async is used.
1009      * We have to set MCI_MODE_RECORD before we do this so that the app can spin
1010      * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
1011      */
1012     if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
1013         return MCIERR_INTERNAL;
1014     }
1015
1016     wmw->fInput = TRUE; /* FIXME: waveOutOpen may have been called. */
1017     wmw->dwStatus = MCI_MODE_RECORD;
1018
1019     if (!(dwFlags & MCI_WAIT)) {
1020         return MCI_SendCommandAsync(wDevID, WAVE_mciRecord, dwFlags,
1021                                     (DWORD_PTR)lpParms, sizeof(MCI_RECORD_PARMS));
1022     }
1023
1024     /* FIXME: we only re-create the RIFF structure from an existing file (if any)
1025      * we don't modify the wave part of an existing file (ie. we always erase an
1026      * existing content, we don't overwrite)
1027      */
1028     HeapFree(GetProcessHeap(), 0, (void*)wmw->lpFileName);
1029     dwRet = create_tmp_file(&wmw->hFile, (WCHAR**)&wmw->lpFileName);
1030     if (dwRet != 0) return dwRet;
1031
1032     /* new RIFF file, lpWaveFormat now valid */
1033     dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
1034     if (dwRet != 0) return dwRet;
1035
1036     if (lpParms && (dwFlags & MCI_TO)) {
1037         end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1038     } else end = 0xFFFFFFFF;
1039     if (lpParms && (dwFlags & MCI_FROM)) {
1040         DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
1041         if (wmw->ckWaveData.cksize < position)  return MCIERR_OUTOFRANGE;
1042         /* Seek rounds down, so do we. */
1043         position /= wmw->lpWaveFormat->nBlockAlign;
1044         position *= wmw->lpWaveFormat->nBlockAlign;
1045         wmw->dwPosition = position;
1046     }
1047     if (end==wmw->dwPosition) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
1048
1049     TRACE("Recording from byte=%u to byte=%u\n", wmw->dwPosition, end);
1050
1051     oldcb = InterlockedExchangePointer(&wmw->hCallback,
1052         (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
1053     if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
1054     oldcb = NULL;
1055
1056 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1057 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1058
1059     wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1060
1061     /* Go back to the beginning of the chunk plus the requested position */
1062     /* FIXME: I'm not sure this is correct, notably because some data linked to
1063      * the decompression state machine will not be correctly initialized.
1064      * Try it this way (other way would be to decompress from 0 up to dwPosition
1065      * and to start sending to hWave when dwPosition is reached).
1066      */
1067     mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1068
1069     dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, wmw->wInput, wmw->lpWaveFormat,
1070                         (DWORD_PTR)WAVE_mciRecordCallback, (DWORD_PTR)wmw, CALLBACK_FUNCTION);
1071
1072     if (dwRet != MMSYSERR_NOERROR) {
1073         TRACE("Can't open low level audio device %d\n", dwRet);
1074         dwRet = MCIERR_DEVICE_OPEN;
1075         wmw->hWave = 0;
1076         goto cleanUp;
1077     }
1078
1079     /* make it so that 3 buffers per second are needed */
1080     bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1081
1082     waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1083     waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1084     waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1085     waveHdr[0].dwUser         = waveHdr[1].dwUser         = 0L;
1086     waveHdr[0].dwLoops        = waveHdr[1].dwLoops        = 0L;
1087     waveHdr[0].dwFlags        = waveHdr[1].dwFlags        = 0L;
1088     waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1089
1090     if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1091         waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1092         dwRet = MCIERR_INTERNAL;
1093         goto cleanUp;
1094     }
1095
1096     if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1097         waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1098         dwRet = MCIERR_INTERNAL;
1099         goto cleanUp;
1100     }
1101
1102     wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1103     wmw->dwEventCount = 1L; /* for first buffer */
1104
1105     TRACE("Recording (normalized) from byte=%u for %u bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1106
1107     dwRet = waveInStart(wmw->hWave);
1108
1109     if (hEvent) SetEvent(hEvent);
1110
1111     while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1112         WAVE_mciRecordWaitDone(wmw);
1113     }
1114     /* Grab callback before another thread kicks in after we change dwStatus. */
1115     if (dwFlags & MCI_NOTIFY) {
1116         oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
1117         dwFlags &= ~MCI_NOTIFY;
1118     }
1119     /* needed so that the callback above won't add again the buffers returned by the reset */
1120     wmw->dwStatus = MCI_MODE_STOP;
1121
1122     waveInReset(wmw->hWave);
1123
1124     waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1125     waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1126
1127     dwRet = 0;
1128
1129 cleanUp:
1130     if (dwFlags & MCI_NOTIFY)
1131         oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
1132
1133     HeapFree(GetProcessHeap(), 0, waveHdr);
1134
1135     if (wmw->hWave) {
1136         waveInClose(wmw->hWave);
1137         wmw->hWave = 0;
1138     }
1139     CloseHandle(wmw->hEvent);
1140
1141     wmw->dwStatus = MCI_MODE_STOP;
1142
1143     if (oldcb) mciDriverNotify(oldcb, wDevID,
1144         dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1145
1146     return dwRet;
1147
1148 }
1149
1150 /**************************************************************************
1151  *                              WAVE_mciPause                   [internal]
1152  */
1153 static DWORD WAVE_mciPause(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1154 {
1155     DWORD               dwRet;
1156     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1157
1158     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1159
1160     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1161
1162     switch (wmw->dwStatus) {
1163     case MCI_MODE_PLAY:
1164         dwRet = waveOutPause(wmw->hWave);
1165         if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1166         else { /* When playthread was not started yet, winmm not opened, error 5 MMSYSERR_INVALHANDLE */
1167             ERR("waveOutPause error %d\n",dwRet);
1168             dwRet = MCIERR_INTERNAL;
1169         }
1170         break;
1171     case MCI_MODE_RECORD:
1172         dwRet = waveInStop(wmw->hWave);
1173         if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1174         else {
1175             ERR("waveInStop error %d\n",dwRet);
1176             dwRet = MCIERR_INTERNAL;
1177         }
1178         break;
1179     case MCI_MODE_PAUSE:
1180         dwRet = MMSYSERR_NOERROR;
1181         break;
1182     default:
1183         dwRet = MCIERR_NONAPPLICABLE_FUNCTION;
1184     }
1185     if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1186         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1187     return dwRet;
1188 }
1189
1190 /**************************************************************************
1191  *                              WAVE_mciResume                  [internal]
1192  */
1193 static DWORD WAVE_mciResume(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1194 {
1195     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1196     DWORD               dwRet;
1197
1198     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1199
1200     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1201
1202     switch (wmw->dwStatus) {
1203     case MCI_MODE_PAUSE:
1204         /* Only update dwStatus if wave* succeeds and will exchange buffers buffers. */
1205         if (wmw->fInput) {
1206             dwRet = waveInStart(wmw->hWave);
1207             if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_RECORD;
1208             else {
1209                 ERR("waveInStart error %d\n",dwRet);
1210                 dwRet = MCIERR_INTERNAL;
1211             }
1212         } else {
1213             dwRet = waveOutRestart(wmw->hWave);
1214             if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PLAY;
1215             else {
1216                 ERR("waveOutRestart error %d\n",dwRet);
1217                 dwRet = MCIERR_INTERNAL;
1218             }
1219         }
1220         break;
1221     case MCI_MODE_PLAY:
1222     case MCI_MODE_RECORD:
1223         dwRet = MMSYSERR_NOERROR;
1224         break;
1225     default:
1226         dwRet = MCIERR_NONAPPLICABLE_FUNCTION;
1227     }
1228     if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1229         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1230     return dwRet;
1231 }
1232
1233 /**************************************************************************
1234  *                              WAVE_mciSeek                    [internal]
1235  */
1236 static DWORD WAVE_mciSeek(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1237 {
1238     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1239     DWORD               position, dwRet;
1240
1241     TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1242
1243     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1244     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1245
1246     position = dwFlags & (MCI_SEEK_TO_START|MCI_SEEK_TO_END|MCI_TO);
1247     if (!position)              return MCIERR_MISSING_PARAMETER;
1248     if (position&(position-1))  return MCIERR_FLAGS_NOT_COMPATIBLE;
1249
1250     /* Stop sends MCI_NOTIFY_ABORTED when needed */
1251     dwRet = WAVE_mciStop(wDevID, MCI_WAIT, 0);
1252     if (dwRet != MMSYSERR_NOERROR) return dwRet;
1253
1254     if (dwFlags & MCI_TO) {
1255         position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1256         if (position > wmw->ckWaveData.cksize)
1257             return MCIERR_OUTOFRANGE;
1258     } else if (dwFlags & MCI_SEEK_TO_START) {
1259         position = 0;
1260     } else {
1261         position = wmw->ckWaveData.cksize;
1262     }
1263     /* Seek rounds down, unless at end */
1264     if (position != wmw->ckWaveData.cksize) {
1265         position /= wmw->lpWaveFormat->nBlockAlign;
1266         position *= wmw->lpWaveFormat->nBlockAlign;
1267     }
1268     wmw->dwPosition = position;
1269     TRACE("Seeking to position=%u bytes\n", position);
1270
1271     if (dwFlags & MCI_NOTIFY)
1272         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1273
1274     return MMSYSERR_NOERROR;
1275 }
1276
1277 /**************************************************************************
1278  *                              WAVE_mciSet                     [internal]
1279  */
1280 static DWORD WAVE_mciSet(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_SET_PARMS lpParms)
1281 {
1282     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1283
1284     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1285
1286     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1287     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1288
1289     if (dwFlags & MCI_SET_TIME_FORMAT) {
1290         switch (lpParms->dwTimeFormat) {
1291         case MCI_FORMAT_MILLISECONDS:
1292             TRACE("MCI_FORMAT_MILLISECONDS !\n");
1293             wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1294             break;
1295         case MCI_FORMAT_BYTES:
1296             TRACE("MCI_FORMAT_BYTES !\n");
1297             wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1298             break;
1299         case MCI_FORMAT_SAMPLES:
1300             TRACE("MCI_FORMAT_SAMPLES !\n");
1301             wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1302             break;
1303         default:
1304             WARN("Bad time format %u!\n", lpParms->dwTimeFormat);
1305             return MCIERR_BAD_TIME_FORMAT;
1306         }
1307     }
1308     if (dwFlags & MCI_SET_VIDEO) {
1309         TRACE("No support for video !\n");
1310         return MCIERR_UNSUPPORTED_FUNCTION;
1311     }
1312     if (dwFlags & MCI_SET_DOOR_OPEN) {
1313         TRACE("No support for door open !\n");
1314         return MCIERR_UNSUPPORTED_FUNCTION;
1315     }
1316     if (dwFlags & MCI_SET_DOOR_CLOSED) {
1317         TRACE("No support for door close !\n");
1318         return MCIERR_UNSUPPORTED_FUNCTION;
1319     }
1320     if (dwFlags & MCI_SET_AUDIO) {
1321         if (dwFlags & MCI_SET_ON) {
1322             TRACE("MCI_SET_ON audio !\n");
1323         } else if (dwFlags & MCI_SET_OFF) {
1324             TRACE("MCI_SET_OFF audio !\n");
1325         } else {
1326             WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1327             return MCIERR_BAD_INTEGER;
1328         }
1329
1330         switch (lpParms->dwAudio)
1331         {
1332         case MCI_SET_AUDIO_ALL:         TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1333         case MCI_SET_AUDIO_LEFT:        TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1334         case MCI_SET_AUDIO_RIGHT:       TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1335         default:                        WARN("Unknown audio channel %u\n", lpParms->dwAudio); break;
1336         }
1337     }
1338     if (dwFlags & MCI_WAVE_INPUT) {
1339         TRACE("MCI_WAVE_INPUT = %d\n", lpParms->wInput);
1340         if (lpParms->wInput >= waveInGetNumDevs())
1341             return MCIERR_OUTOFRANGE;
1342         if (wmw->wInput != (WORD)lpParms->wInput)
1343             WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1344         wmw->wInput = lpParms->wInput;
1345     }
1346     if (dwFlags & MCI_WAVE_OUTPUT) {
1347         TRACE("MCI_WAVE_OUTPUT = %d\n", lpParms->wOutput);
1348         if (lpParms->wOutput >= waveOutGetNumDevs())
1349             return MCIERR_OUTOFRANGE;
1350         if (wmw->wOutput != (WORD)lpParms->wOutput)
1351             WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1352         wmw->wOutput = lpParms->wOutput;
1353     }
1354     if (dwFlags & MCI_WAVE_SET_ANYINPUT) {
1355         TRACE("MCI_WAVE_SET_ANYINPUT\n");
1356         if (wmw->wInput != (WORD)lpParms->wInput)
1357             WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1358         wmw->wInput = WAVE_MAPPER;
1359     }
1360     if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) {
1361         TRACE("MCI_WAVE_SET_ANYOUTPUT\n");
1362         if (wmw->wOutput != (WORD)lpParms->wOutput)
1363             WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1364         wmw->wOutput = WAVE_MAPPER;
1365     }
1366     /* Set wave format parameters is refused after Open or Record.*/
1367     if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1368         TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", lpParms->wFormatTag);
1369         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1370         if (lpParms->wFormatTag != WAVE_FORMAT_PCM)
1371             return MCIERR_OUTOFRANGE;
1372     }
1373     if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1374         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1375         wmw->wfxRef.nAvgBytesPerSec = lpParms->nAvgBytesPerSec;
1376         TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %d\n", wmw->wfxRef.nAvgBytesPerSec);
1377     }
1378     if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1379         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1380         wmw->wfxRef.wBitsPerSample = lpParms->wBitsPerSample;
1381         TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1382     }
1383     if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1384         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1385         wmw->wfxRef.nBlockAlign = lpParms->nBlockAlign;
1386         TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1387     }
1388     if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1389         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1390         wmw->wfxRef.nChannels = lpParms->nChannels;
1391         TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1392     }
1393     if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1394         if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1395         wmw->wfxRef.nSamplesPerSec = lpParms->nSamplesPerSec;
1396         TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %d\n", wmw->wfxRef.nSamplesPerSec);
1397     }
1398     if (dwFlags & MCI_NOTIFY)
1399         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1400     return 0;
1401 }
1402
1403 /**************************************************************************
1404  *                              WAVE_mciSave            [internal]
1405  */
1406 static DWORD WAVE_mciSave(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SAVE_PARMSW lpParms)
1407 {
1408     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1409     DWORD               ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1410
1411     TRACE("%d, %08X, %p);\n", wDevID, dwFlags, lpParms);
1412     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1413     if (wmw     == NULL)        return MCIERR_INVALID_DEVICE_ID;
1414
1415     if (dwFlags & MCI_WAIT)
1416     {
1417         FIXME("MCI_WAIT not implemented\n");
1418     }
1419     WAVE_mciStop(wDevID, 0, NULL);
1420
1421     ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1422     ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1423
1424     ret = mmioClose(wmw->hFile, 0);
1425     wmw->hFile = 0;
1426
1427     /*
1428       If the destination file already exists, it has to be overwritten.  (Behaviour
1429       verified in Windows (2000)).  If it doesn't overwrite, it is breaking one of
1430       my applications.  We are making use of mmioRename, which WILL NOT overwrite
1431       the destination file (which is what Windows does, also verified in Win2K)
1432       So, lets delete the destination file before calling mmioRename.  If the
1433       destination file DOESN'T exist, the delete will fail silently.  Let's also be
1434       careful not to lose our previous error code.
1435     */
1436     tmpRet = GetLastError();
1437     DeleteFileW (lpParms->lpfilename);
1438     SetLastError(tmpRet);
1439
1440     /* FIXME: Open file.wav; Save; must not rename the original file.
1441      * Nor must Save a.wav; Save b.wav rename a. */
1442     if (0 == mmioRenameW(wmw->lpFileName, lpParms->lpfilename, 0, 0 )) {
1443         ret = MMSYSERR_NOERROR;
1444     }
1445
1446     if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
1447         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1448
1449     if (ret == MMSYSERR_NOERROR)
1450         ret = WAVE_mciOpenFile(wmw, lpParms->lpfilename);
1451
1452     return ret;
1453 }
1454
1455 /**************************************************************************
1456  *                              WAVE_mciStatus          [internal]
1457  */
1458 static DWORD WAVE_mciStatus(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1459 {
1460     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1461     DWORD               ret = 0;
1462
1463     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1464     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1465     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1466
1467     if (dwFlags & MCI_STATUS_ITEM) {
1468         switch (lpParms->dwItem) {
1469         case MCI_STATUS_CURRENT_TRACK:
1470             lpParms->dwReturn = 1;
1471             TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1472             break;
1473         case MCI_STATUS_LENGTH:
1474             if (!wmw->hFile) {
1475                 lpParms->dwReturn = 0;
1476                 return MCIERR_UNSUPPORTED_FUNCTION;
1477             }
1478             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1479             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
1480             TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1481             break;
1482         case MCI_STATUS_MODE:
1483             TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1484             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1485             ret = MCI_RESOURCE_RETURNED;
1486             break;
1487         case MCI_STATUS_MEDIA_PRESENT:
1488             TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1489             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1490             ret = MCI_RESOURCE_RETURNED;
1491             break;
1492         case MCI_STATUS_NUMBER_OF_TRACKS:
1493             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1494             lpParms->dwReturn = 1;
1495             TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu\n", lpParms->dwReturn);
1496             break;
1497         case MCI_STATUS_POSITION:
1498             if (!wmw->hFile) {
1499                 lpParms->dwReturn = 0;
1500                 return MCIERR_UNSUPPORTED_FUNCTION;
1501             }
1502             /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1503             lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1504                                                              (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
1505                                                              &ret);
1506             TRACE("MCI_STATUS_POSITION %s => %lu\n",
1507                   (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1508             break;
1509         case MCI_STATUS_READY:
1510             lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1511                 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1512             TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1513             ret = MCI_RESOURCE_RETURNED;
1514             break;
1515         case MCI_STATUS_TIME_FORMAT:
1516             lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, MCI_FORMAT_RETURN_BASE + wmw->dwMciTimeFormat);
1517             TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1518             ret = MCI_RESOURCE_RETURNED;
1519             break;
1520         case MCI_WAVE_INPUT:
1521             if (wmw->wInput != (WORD)WAVE_MAPPER)
1522                 lpParms->dwReturn = wmw->wInput;
1523             else {
1524                 lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_MAPPER, WAVE_MAPPER_S);
1525                 ret = MCI_RESOURCE_RETURNED;
1526             }
1527             TRACE("MCI_WAVE_INPUT => %d\n", (signed)wmw->wInput);
1528             break;
1529         case MCI_WAVE_OUTPUT:
1530             if (wmw->wOutput != (WORD)WAVE_MAPPER)
1531                 lpParms->dwReturn = wmw->wOutput;
1532             else {
1533                 lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_MAPPER, WAVE_MAPPER_S);
1534                 ret = MCI_RESOURCE_RETURNED;
1535             }
1536             TRACE("MCI_WAVE_OUTPUT => %d\n", (signed)wmw->wOutput);
1537             break;
1538         /* It is always ok to query wave format parameters,
1539          * except on auto-open yield MCIERR_UNSUPPORTED_FUNCTION. */
1540         case MCI_WAVE_STATUS_FORMATTAG:
1541             if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
1542                 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1543             else {
1544                 lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_FORMAT_PCM, WAVE_FORMAT_PCM_S);
1545                 ret = MCI_RESOURCE_RETURNED;
1546             }
1547             TRACE("MCI_WAVE_FORMATTAG => %lu\n", lpParms->dwReturn);
1548             break;
1549         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1550             lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1551             TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu\n", lpParms->dwReturn);
1552             break;
1553         case MCI_WAVE_STATUS_BITSPERSAMPLE:
1554             lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1555             TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu\n", lpParms->dwReturn);
1556             break;
1557         case MCI_WAVE_STATUS_BLOCKALIGN:
1558             lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1559             TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu\n", lpParms->dwReturn);
1560             break;
1561         case MCI_WAVE_STATUS_CHANNELS:
1562             lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1563             TRACE("MCI_WAVE_STATUS_CHANNELS => %lu\n", lpParms->dwReturn);
1564             break;
1565         case MCI_WAVE_STATUS_SAMPLESPERSEC:
1566             lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1567             TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu\n", lpParms->dwReturn);
1568             break;
1569         case MCI_WAVE_STATUS_LEVEL:
1570             TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1571             lpParms->dwReturn = 0xAAAA5555;
1572             break;
1573         default:
1574             WARN("unknown command %08X !\n", lpParms->dwItem);
1575             return MCIERR_UNRECOGNIZED_COMMAND;
1576         }
1577     }
1578     if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1579         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1580     return ret;
1581 }
1582
1583 /**************************************************************************
1584  *                              WAVE_mciGetDevCaps              [internal]
1585  */
1586 static DWORD WAVE_mciGetDevCaps(MCIDEVICEID wDevID, DWORD dwFlags,
1587                                 LPMCI_GETDEVCAPS_PARMS lpParms)
1588 {
1589     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1590     DWORD               ret = 0;
1591
1592     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1593
1594     if (lpParms == NULL)        return MCIERR_NULL_PARAMETER_BLOCK;
1595     if (wmw == NULL)            return MCIERR_INVALID_DEVICE_ID;
1596
1597     if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1598         switch(lpParms->dwItem) {
1599         case MCI_GETDEVCAPS_DEVICE_TYPE:
1600             lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1601             ret = MCI_RESOURCE_RETURNED;
1602             break;
1603         case MCI_GETDEVCAPS_HAS_AUDIO:
1604             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1605             ret = MCI_RESOURCE_RETURNED;
1606             break;
1607         case MCI_GETDEVCAPS_HAS_VIDEO:
1608             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1609             ret = MCI_RESOURCE_RETURNED;
1610             break;
1611         case MCI_GETDEVCAPS_USES_FILES:
1612             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1613             ret = MCI_RESOURCE_RETURNED;
1614             break;
1615         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1616             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1617             ret = MCI_RESOURCE_RETURNED;
1618             break;
1619         case MCI_GETDEVCAPS_CAN_RECORD:
1620             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1621             ret = MCI_RESOURCE_RETURNED;
1622             break;
1623         case MCI_GETDEVCAPS_CAN_EJECT:
1624             lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1625             ret = MCI_RESOURCE_RETURNED;
1626             break;
1627         case MCI_GETDEVCAPS_CAN_PLAY:
1628             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1629             ret = MCI_RESOURCE_RETURNED;
1630             break;
1631         case MCI_GETDEVCAPS_CAN_SAVE:
1632             lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1633             ret = MCI_RESOURCE_RETURNED;
1634             break;
1635         case MCI_WAVE_GETDEVCAPS_INPUTS:
1636             lpParms->dwReturn = waveInGetNumDevs();
1637             break;
1638         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1639             lpParms->dwReturn = waveOutGetNumDevs();
1640             break;
1641         default:
1642             FIXME("Unknown capability (%08x) !\n", lpParms->dwItem);
1643             return MCIERR_UNRECOGNIZED_COMMAND;
1644         }
1645     } else {
1646         WARN("No GetDevCaps-Item !\n");
1647         return MCIERR_UNRECOGNIZED_COMMAND;
1648     }
1649     if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1650         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1651     return ret;
1652 }
1653
1654 /**************************************************************************
1655  *                              WAVE_mciInfo                    [internal]
1656  */
1657 static DWORD WAVE_mciInfo(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
1658 {
1659     DWORD               ret = 0;
1660     LPCWSTR             str = 0;
1661     WINE_MCIWAVE*       wmw = WAVE_mciGetOpenDev(wDevID);
1662
1663     TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1664
1665     if (!lpParms || !lpParms->lpstrReturn)
1666         return MCIERR_NULL_PARAMETER_BLOCK;
1667
1668     if (wmw == NULL) {
1669         ret = MCIERR_INVALID_DEVICE_ID;
1670     } else {
1671         static const WCHAR wszAudio  [] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','p','l','a','y','e','r',0};
1672         static const WCHAR wszWaveIn [] = {'W','i','n','e',' ','W','a','v','e',' ','I','n',0};
1673         static const WCHAR wszWaveOut[] = {'W','i','n','e',' ','W','a','v','e',' ','O','u','t',0};
1674
1675         TRACE("buf=%p, len=%u\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1676
1677         switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1678         case MCI_INFO_PRODUCT: str = wszAudio; break;
1679         case MCI_INFO_FILE:    str = wmw->lpFileName; break;
1680         case MCI_WAVE_INPUT:   str = wszWaveIn; break;
1681         case MCI_WAVE_OUTPUT:  str = wszWaveOut; break;
1682         default:
1683             WARN("Don't know this info command (%u)\n", dwFlags);
1684             ret = MCIERR_UNRECOGNIZED_COMMAND;
1685         }
1686     }
1687     if (str) {
1688         if (strlenW(str) + 1 > lpParms->dwRetSize) {
1689             ret = MCIERR_PARAM_OVERFLOW;
1690         } else {
1691             lstrcpynW(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1692         }
1693     } else {
1694         lpParms->lpstrReturn[0] = 0;
1695     }
1696     if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
1697         WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1698     return ret;
1699 }
1700
1701 /**************************************************************************
1702  *                              DriverProc (MCIWAVE.@)
1703  */
1704 LRESULT CALLBACK MCIWAVE_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1705                                     LPARAM dwParam1, LPARAM dwParam2)
1706 {
1707     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1708           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1709
1710     switch (wMsg) {
1711     case DRV_LOAD:              return 1;
1712     case DRV_FREE:              return 1;
1713     case DRV_OPEN:              return WAVE_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1714     case DRV_CLOSE:             return WAVE_drvClose(dwDevID);
1715     case DRV_ENABLE:            return 1;
1716     case DRV_DISABLE:           return 1;
1717     case DRV_QUERYCONFIGURE:    return 1;
1718     case DRV_CONFIGURE:         MessageBoxA(0, "MCI waveaudio Driver !", "Wine Driver", MB_OK); return 1;
1719     case DRV_INSTALL:           return DRVCNF_RESTART;
1720     case DRV_REMOVE:            return DRVCNF_RESTART;
1721     }
1722
1723     if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1724
1725     switch (wMsg) {
1726     case MCI_OPEN_DRIVER:       return WAVE_mciOpen      (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSW)  dwParam2);
1727     case MCI_CLOSE_DRIVER:      return WAVE_mciClose     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1728     case MCI_CUE:               return WAVE_mciCue       (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1729     case MCI_PLAY:              return WAVE_mciPlay      (dwDevID, dwParam1, dwParam2, NULL);
1730     case MCI_RECORD:            return WAVE_mciRecord    (dwDevID, dwParam1, dwParam2, NULL);
1731     case MCI_STOP:              return WAVE_mciStop      (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1732     case MCI_SET:               return WAVE_mciSet       (dwDevID, dwParam1, (LPMCI_WAVE_SET_PARMS)    dwParam2);
1733     case MCI_PAUSE:             return WAVE_mciPause     (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1734     case MCI_RESUME:            return WAVE_mciResume    (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)     dwParam2);
1735     case MCI_STATUS:            return WAVE_mciStatus    (dwDevID, dwParam1, (LPMCI_STATUS_PARMS)      dwParam2);
1736     case MCI_GETDEVCAPS:        return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)  dwParam2);
1737     case MCI_INFO:              return WAVE_mciInfo      (dwDevID, dwParam1, (LPMCI_INFO_PARMSW)       dwParam2);
1738     case MCI_SEEK:              return WAVE_mciSeek      (dwDevID, dwParam1, (LPMCI_SEEK_PARMS)        dwParam2);
1739     case MCI_SAVE:              return WAVE_mciSave      (dwDevID, dwParam1, (LPMCI_SAVE_PARMSW)       dwParam2);
1740         /* commands that should be supported */
1741     case MCI_LOAD:
1742     case MCI_FREEZE:
1743     case MCI_PUT:
1744     case MCI_REALIZE:
1745     case MCI_UNFREEZE:
1746     case MCI_UPDATE:
1747     case MCI_WHERE:
1748     case MCI_STEP:
1749     case MCI_SPIN:
1750     case MCI_ESCAPE:
1751     case MCI_COPY:
1752     case MCI_CUT:
1753     case MCI_DELETE:
1754     case MCI_PASTE:
1755         FIXME("Unsupported yet command [%u]\n", wMsg);
1756         break;
1757     case MCI_WINDOW:
1758         TRACE("Unsupported command [%u]\n", wMsg);
1759         break;
1760         /* option which can be silenced */
1761     case MCI_CONFIGURE:
1762         return 0;
1763     case MCI_OPEN:
1764     case MCI_CLOSE:
1765         ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1766         break;
1767     default:
1768         FIXME("is probably wrong msg [%u]\n", wMsg);
1769         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1770     }
1771     return MCIERR_UNRECOGNIZED_COMMAND;
1772 }