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