~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/mciwave/mciwave.c

Version: ~ [ wine-1.5.30 ] ~ [ wine-1.5.29 ] ~ [ wine-1.5.28 ] ~ [ wine-1.5.27 ] ~ [ wine-1.5.26 ] ~ [ wine-1.5.25 ] ~ [ wine-1.5.24 ] ~ [ wine-1.5.23 ] ~ [ wine-1.5.22 ] ~ [ wine-1.5.21 ] ~ [ wine-1.5.20 ] ~ [ wine-1.5.19 ] ~ [ wine-1.5.18 ] ~ [ wine-1.5.17 ] ~ [ wine-1.5.16 ] ~ [ wine-1.5.15 ] ~ [ wine-1.5.14 ] ~ [ wine-1.5.13 ] ~ [ wine-1.5.12 ] ~ [ wine-1.5.11 ] ~ [ wine-1.5.10 ] ~ [ wine-1.5.9 ] ~ [ wine-1.5.8 ] ~ [ wine-1.5.7 ] ~ [ wine-1.4.1 ] ~ [ wine-1.5.6 ] ~ [ wine-1.5.5 ] ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.