wined3d: Take predication tokens into account.
[wine/dcerpc.git] / dlls / mciwave / mciwave.c
blob12167189a8d53a292ffb107d1796d6c52a2907d3
1 /*
2 * Sample Wine Driver for MCI wave forms
4 * Copyright 1994 Martin Ayotte
5 * 1999,2000,2005 Eric Pouech
6 * 2000 Francois Jacques
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <stdarg.h>
25 #include "winerror.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "mmddk.h"
31 #include "wownt32.h"
32 #include "digitalv.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(mciwave);
38 typedef struct {
39 UINT wDevID;
40 HANDLE hWave;
41 int nUseCount; /* Incremented for each shared open */
42 BOOL fShareable; /* TRUE if first open was shareable */
43 HMMIO hFile; /* mmio file handle open as Element */
44 MCI_WAVE_OPEN_PARMSW openParms;
45 WAVEFORMATEX wfxRef;
46 LPWAVEFORMATEX lpWaveFormat;
47 BOOL fInput; /* FALSE = Output, TRUE = Input */
48 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
49 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
50 DWORD dwPosition; /* position in bytes in chunk */
51 HANDLE hEvent; /* for synchronization */
52 LONG dwEventCount; /* for synchronization */
53 MMCKINFO ckMainRIFF; /* main RIFF chunk */
54 MMCKINFO ckWaveData; /* data chunk */
55 } WINE_MCIWAVE;
57 /* ===================================================================
58 * ===================================================================
59 * FIXME: should be using the new mmThreadXXXX functions from WINMM
60 * instead of those
61 * it would require to add a wine internal flag to mmThreadCreate
62 * in order to pass a 32 bit function instead of a 16 bit one
63 * ===================================================================
64 * =================================================================== */
66 struct SCA {
67 UINT wDevID;
68 UINT wMsg;
69 DWORD dwParam1;
70 DWORD dwParam2;
73 /**************************************************************************
74 * MCI_SCAStarter [internal]
76 static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
78 struct SCA* sca = (struct SCA*)arg;
79 DWORD ret;
81 TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
82 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
83 ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
84 TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
85 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
86 HeapFree(GetProcessHeap(), 0, sca);
87 ExitThread(ret);
88 WARN("Should not happen ? what's wrong\n");
89 /* should not go after this point */
90 return ret;
93 /**************************************************************************
94 * MCI_SendCommandAsync [internal]
96 static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
97 DWORD dwParam2, UINT size)
99 HANDLE handle;
100 struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
102 if (sca == 0)
103 return MCIERR_OUT_OF_MEMORY;
105 sca->wDevID = wDevID;
106 sca->wMsg = wMsg;
107 sca->dwParam1 = dwParam1;
109 if (size && dwParam2) {
110 sca->dwParam2 = (DWORD)sca + sizeof(struct SCA);
111 /* copy structure passed by program in dwParam2 to be sure
112 * we can still use it whatever the program does
114 memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
115 } else {
116 sca->dwParam2 = dwParam2;
119 if ((handle = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
120 WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
121 return MCI_SCAStarter(&sca);
123 SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL);
124 CloseHandle(handle);
125 return 0;
128 /*======================================================================*
129 * MCI WAVE implemantation *
130 *======================================================================*/
132 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
134 /**************************************************************************
135 * MCIWAVE_drvOpen [internal]
137 static LRESULT WAVE_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
139 WINE_MCIWAVE* wmw;
141 if (modp == NULL) return 0xFFFFFFFF;
143 wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
145 if (!wmw)
146 return 0;
148 wmw->wDevID = modp->wDeviceID;
149 mciSetDriverData(wmw->wDevID, (DWORD)wmw);
150 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
151 modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
153 wmw->wfxRef.wFormatTag = WAVE_FORMAT_PCM;
154 wmw->wfxRef.nChannels = 1; /* MONO */
155 wmw->wfxRef.nSamplesPerSec = 11025;
156 wmw->wfxRef.nAvgBytesPerSec = 11025;
157 wmw->wfxRef.nBlockAlign = 1;
158 wmw->wfxRef.wBitsPerSample = 8;
159 wmw->wfxRef.cbSize = 0; /* don't care */
161 return modp->wDeviceID;
164 /**************************************************************************
165 * MCIWAVE_drvClose [internal]
167 static LRESULT WAVE_drvClose(MCIDEVICEID dwDevID)
169 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
171 if (wmw) {
172 HeapFree(GetProcessHeap(), 0, wmw);
173 mciSetDriverData(dwDevID, 0);
174 return 1;
176 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
179 /**************************************************************************
180 * WAVE_mciGetOpenDev [internal]
182 static WINE_MCIWAVE *WAVE_mciGetOpenDev(MCIDEVICEID wDevID)
184 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
186 if (wmw == NULL || wmw->nUseCount == 0) {
187 WARN("Invalid wDevID=%u\n", wDevID);
188 return 0;
190 return wmw;
193 /**************************************************************************
194 * WAVE_ConvertByteToTimeFormat [internal]
196 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
198 DWORD ret = 0;
200 switch (wmw->dwMciTimeFormat) {
201 case MCI_FORMAT_MILLISECONDS:
202 ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec);
203 break;
204 case MCI_FORMAT_BYTES:
205 ret = val;
206 break;
207 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
208 ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
209 break;
210 default:
211 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
213 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
214 *lpRet = 0;
215 return ret;
218 /**************************************************************************
219 * WAVE_ConvertTimeFormatToByte [internal]
221 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
223 DWORD ret = 0;
225 switch (wmw->dwMciTimeFormat) {
226 case MCI_FORMAT_MILLISECONDS:
227 ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
228 break;
229 case MCI_FORMAT_BYTES:
230 ret = val;
231 break;
232 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
233 ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
234 break;
235 default:
236 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
238 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
239 return ret;
242 /**************************************************************************
243 * WAVE_mciReadFmt [internal]
245 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
247 MMCKINFO mmckInfo;
248 long r;
250 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
251 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
252 return MCIERR_INVALID_FILE;
253 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
254 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
256 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
257 if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
258 r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
259 if (r < sizeof(WAVEFORMAT))
260 return MCIERR_INVALID_FILE;
262 TRACE("wFormatTag=%04X !\n", wmw->lpWaveFormat->wFormatTag);
263 TRACE("nChannels=%d\n", wmw->lpWaveFormat->nChannels);
264 TRACE("nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nSamplesPerSec);
265 TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
266 TRACE("nBlockAlign=%d\n", wmw->lpWaveFormat->nBlockAlign);
267 TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
268 if (r >= (long)sizeof(WAVEFORMATEX))
269 TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
271 mmioAscend(wmw->hFile, &mmckInfo, 0);
272 wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
273 if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
274 TRACE("can't find data chunk\n");
275 return MCIERR_INVALID_FILE;
277 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
278 (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
279 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
280 wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
282 return 0;
285 /**************************************************************************
286 * WAVE_mciDefaultFmt [internal]
288 static DWORD WAVE_mciDefaultFmt(WINE_MCIWAVE* wmw)
290 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, sizeof(*wmw->lpWaveFormat));
291 if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
293 wmw->lpWaveFormat->wFormatTag = WAVE_FORMAT_PCM;
294 wmw->lpWaveFormat->nChannels = 1;
295 wmw->lpWaveFormat->nSamplesPerSec = 44000;
296 wmw->lpWaveFormat->nAvgBytesPerSec = 44000;
297 wmw->lpWaveFormat->nBlockAlign = 1;
298 wmw->lpWaveFormat->wBitsPerSample = 8;
300 return 0;
303 /**************************************************************************
304 * WAVE_mciCreateRIFFSkeleton [internal]
306 static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
308 MMCKINFO ckWaveFormat;
309 LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF);
310 LPMMCKINFO lpckWaveData = &(wmw->ckWaveData);
312 lpckRIFF->ckid = FOURCC_RIFF;
313 lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
314 lpckRIFF->cksize = 0;
316 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF))
317 goto err;
319 ckWaveFormat.fccType = 0;
320 ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' ');
321 ckWaveFormat.cksize = sizeof(PCMWAVEFORMAT);
323 if (!wmw->lpWaveFormat)
325 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmw->lpWaveFormat));
326 if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
327 memcpy(wmw->lpWaveFormat, &wmw->wfxRef, sizeof(wmw->wfxRef));
330 /* we can only record PCM files... there is no way in the MCI API to specify
331 * the necessary data to initialize the extra bytes of the WAVEFORMATEX
332 * structure
334 if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
335 goto err;
337 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
338 goto err;
340 if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, sizeof(PCMWAVEFORMAT)))
341 goto err;
343 if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
344 goto err;
346 lpckWaveData->cksize = 0;
347 lpckWaveData->fccType = 0;
348 lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a');
350 /* create data chunk */
351 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
352 goto err;
354 return 0;
356 err:
357 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
358 wmw->lpWaveFormat = NULL;
359 return MCIERR_INVALID_FILE;
362 static DWORD create_tmp_file(HMMIO* hFile, LPWSTR* pszTmpFileName)
364 WCHAR szTmpPath[MAX_PATH];
365 WCHAR szPrefix[4];
366 DWORD dwRet = MMSYSERR_NOERROR;
368 szPrefix[0] = 'M';
369 szPrefix[1] = 'C';
370 szPrefix[2] = 'I';
371 szPrefix[3] = '\0';
373 if (!GetTempPathW(sizeof(szTmpPath), szTmpPath)) {
374 WARN("can't retrieve temp path!\n");
375 return MCIERR_FILE_NOT_FOUND;
378 *pszTmpFileName = HeapAlloc(GetProcessHeap(),
379 HEAP_ZERO_MEMORY,
380 MAX_PATH * sizeof(WCHAR));
381 if (!GetTempFileNameW(szTmpPath, szPrefix, 0, *pszTmpFileName)) {
382 WARN("can't retrieve temp file name!\n");
383 HeapFree(GetProcessHeap(), 0, *pszTmpFileName);
384 return MCIERR_FILE_NOT_FOUND;
387 TRACE("%s!\n", debugstr_w(*pszTmpFileName));
389 if (*pszTmpFileName && (strlenW(*pszTmpFileName) > 0)) {
391 *hFile = mmioOpenW(*pszTmpFileName, NULL,
392 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
394 if (*hFile == 0) {
395 WARN("can't create file=%s!\n", debugstr_w(*pszTmpFileName));
396 /* temporary file could not be created. clean filename. */
397 HeapFree(GetProcessHeap(), 0, *pszTmpFileName);
398 dwRet = MCIERR_FILE_NOT_FOUND;
401 return dwRet;
404 static LRESULT WAVE_mciOpenFile(WINE_MCIWAVE* wmw, const WCHAR* filename)
406 LRESULT dwRet = MMSYSERR_NOERROR;
407 WCHAR* fn;
409 fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
410 if (!fn) return MCIERR_OUT_OF_MEMORY;
411 strcpyW(fn, filename);
412 HeapFree(GetProcessHeap(), 0, (void*)wmw->openParms.lpstrElementName);
413 wmw->openParms.lpstrElementName = fn;
415 if (strlenW(filename) > 0) {
416 /* FIXME : what should be done if wmw->hFile is already != 0, or the driver is playin' */
417 TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(filename));
419 wmw->hFile = mmioOpenW((LPWSTR)filename, NULL,
420 MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
422 if (wmw->hFile == 0) {
423 WARN("can't find file=%s!\n", debugstr_w(filename));
424 dwRet = MCIERR_FILE_NOT_FOUND;
426 else
428 LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF;
430 /* make sure we're are the beginning of the file */
431 mmioSeek(wmw->hFile, 0, SEEK_SET);
433 /* first reading of this file. read the waveformat chunk */
434 if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
435 dwRet = MCIERR_INVALID_FILE;
436 } else {
437 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX\n",
438 (LPSTR)&(lpckMainRIFF->ckid),
439 (LPSTR) &(lpckMainRIFF->fccType),
440 (lpckMainRIFF->cksize));
442 if ((lpckMainRIFF->ckid != FOURCC_RIFF) ||
443 lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
444 dwRet = MCIERR_INVALID_FILE;
445 } else {
446 dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
451 return dwRet;
454 /**************************************************************************
455 * WAVE_mciOpen [internal]
457 static LRESULT WAVE_mciOpen(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSW lpOpenParms)
459 DWORD dwRet = 0;
460 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
462 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
463 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
464 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
466 if (dwFlags & MCI_OPEN_SHAREABLE)
467 return MCIERR_HARDWARE;
469 if (wmw->nUseCount > 0) {
470 /* The driver is already opened on this channel
471 * Wave driver cannot be shared
473 return MCIERR_DEVICE_OPEN;
476 wmw->nUseCount++;
478 wmw->fInput = FALSE;
479 wmw->hWave = 0;
480 wmw->dwStatus = MCI_MODE_NOT_READY;
481 wmw->hFile = 0;
482 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
484 TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
486 if (dwFlags & MCI_OPEN_ELEMENT) {
487 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
488 /* could it be that (DWORD)lpOpenParms->lpstrElementName
489 * contains the hFile value ?
491 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
492 } else {
493 dwRet = WAVE_mciOpenFile(wmw, lpOpenParms->lpstrElementName);
497 TRACE("hFile=%p\n", wmw->hFile);
499 if (dwRet == 0 && !wmw->lpWaveFormat)
500 dwRet = WAVE_mciDefaultFmt(wmw);
502 if (dwRet == 0) {
503 if (wmw->lpWaveFormat) {
504 switch (wmw->lpWaveFormat->wFormatTag) {
505 case WAVE_FORMAT_PCM:
506 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
507 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
508 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
509 wmw->lpWaveFormat->nAvgBytesPerSec,
510 wmw->lpWaveFormat->nSamplesPerSec *
511 wmw->lpWaveFormat->nBlockAlign);
512 wmw->lpWaveFormat->nAvgBytesPerSec =
513 wmw->lpWaveFormat->nSamplesPerSec *
514 wmw->lpWaveFormat->nBlockAlign;
516 break;
519 wmw->dwPosition = 0;
521 wmw->dwStatus = MCI_MODE_STOP;
522 } else {
523 wmw->nUseCount--;
524 if (wmw->hFile != 0)
525 mmioClose(wmw->hFile, 0);
526 wmw->hFile = 0;
528 return dwRet;
531 /**************************************************************************
532 * WAVE_mciCue [internal]
534 static DWORD WAVE_mciCue(MCIDEVICEID wDevID, LPARAM dwParam, LPMCI_GENERIC_PARMS lpParms)
537 FIXME
539 This routine is far from complete. At the moment only a check is done on the
540 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
541 is the default.
543 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
544 are ignored
547 DWORD dwRet;
548 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
550 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
552 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
554 /* FIXME */
555 /* always close elements ? */
556 if (wmw->hFile != 0) {
557 mmioClose(wmw->hFile, 0);
558 wmw->hFile = 0;
561 dwRet = MMSYSERR_NOERROR; /* assume success */
563 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
564 dwRet = waveOutClose(wmw->hWave);
565 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
566 wmw->fInput = TRUE;
567 } else if (wmw->fInput) {
568 dwRet = waveInClose(wmw->hWave);
569 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
570 wmw->fInput = FALSE;
572 wmw->hWave = 0;
573 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
576 /**************************************************************************
577 * WAVE_mciStop [internal]
579 static DWORD WAVE_mciStop(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
581 DWORD dwRet = 0;
582 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
584 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
586 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
588 /* wait for playback thread (if any) to exit before processing further */
589 switch (wmw->dwStatus) {
590 case MCI_MODE_PAUSE:
591 case MCI_MODE_PLAY:
592 case MCI_MODE_RECORD:
594 int oldStat = wmw->dwStatus;
595 wmw->dwStatus = MCI_MODE_NOT_READY;
596 if (oldStat == MCI_MODE_PAUSE)
597 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
599 while (wmw->dwStatus != MCI_MODE_STOP)
600 Sleep(10);
601 break;
604 wmw->dwPosition = 0;
606 /* sanity resets */
607 wmw->dwStatus = MCI_MODE_STOP;
609 if ((dwFlags & MCI_NOTIFY) && lpParms) {
610 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
611 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
614 return dwRet;
617 /**************************************************************************
618 * WAVE_mciClose [internal]
620 static DWORD WAVE_mciClose(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
622 DWORD dwRet = 0;
623 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
625 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
627 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
629 if (wmw->dwStatus != MCI_MODE_STOP) {
630 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
633 wmw->nUseCount--;
635 if (wmw->nUseCount == 0) {
636 if (wmw->hFile != 0) {
637 mmioClose(wmw->hFile, 0);
638 wmw->hFile = 0;
642 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
643 wmw->lpWaveFormat = NULL;
644 HeapFree(GetProcessHeap(), 0, (void*)wmw->openParms.lpstrElementName);
645 wmw->openParms.lpstrElementName = NULL;
647 if ((dwFlags & MCI_NOTIFY) && lpParms) {
648 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
649 wmw->openParms.wDeviceID,
650 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
653 return 0;
656 /**************************************************************************
657 * WAVE_mciPlayCallback [internal]
659 static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
660 DWORD_PTR dwInstance,
661 LPARAM dwParam1, LPARAM dwParam2)
663 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
665 switch (uMsg) {
666 case WOM_OPEN:
667 case WOM_CLOSE:
668 break;
669 case WOM_DONE:
670 InterlockedIncrement(&wmw->dwEventCount);
671 TRACE("Returning waveHdr=%lx\n", dwParam1);
672 SetEvent(wmw->hEvent);
673 break;
674 default:
675 ERR("Unknown uMsg=%d\n", uMsg);
679 /******************************************************************
680 * WAVE_mciPlayWaitDone
684 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
686 for (;;) {
687 ResetEvent(wmw->hEvent);
688 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
689 break;
691 InterlockedIncrement(&wmw->dwEventCount);
693 WaitForSingleObject(wmw->hEvent, INFINITE);
697 /**************************************************************************
698 * WAVE_mciPlay [internal]
700 static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
702 DWORD end;
703 LONG bufsize, count, left;
704 DWORD dwRet = 0;
705 LPWAVEHDR waveHdr = NULL;
706 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
707 int whidx;
709 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
711 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
712 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
714 wmw->fInput = FALSE;
716 if (wmw->hFile == 0) {
717 WARN("Can't play: no file=%s!\n", debugstr_w(wmw->openParms.lpstrElementName));
718 return MCIERR_FILE_NOT_FOUND;
721 if (wmw->dwStatus == MCI_MODE_PAUSE) {
722 /* FIXME: parameters (start/end) in lpParams may not be used */
723 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
726 /** This function will be called again by a thread when async is used.
727 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
728 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
730 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
731 return MCIERR_INTERNAL;
734 wmw->dwStatus = MCI_MODE_PLAY;
736 if (!(dwFlags & MCI_WAIT)) {
737 return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_PLAY, dwFlags,
738 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
741 end = 0xFFFFFFFF;
742 if (lpParms && (dwFlags & MCI_FROM)) {
743 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
745 if (lpParms && (dwFlags & MCI_TO)) {
746 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
749 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
751 if (end <= wmw->dwPosition)
752 return TRUE;
755 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
756 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
758 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
759 wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
761 if (dwRet == 0) {
762 if (wmw->lpWaveFormat) {
763 switch (wmw->lpWaveFormat->wFormatTag) {
764 case WAVE_FORMAT_PCM:
765 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
766 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
767 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
768 wmw->lpWaveFormat->nAvgBytesPerSec,
769 wmw->lpWaveFormat->nSamplesPerSec *
770 wmw->lpWaveFormat->nBlockAlign);
771 wmw->lpWaveFormat->nAvgBytesPerSec =
772 wmw->lpWaveFormat->nSamplesPerSec *
773 wmw->lpWaveFormat->nBlockAlign;
775 break;
778 } else {
779 TRACE("can't retrieve wave format %ld\n", dwRet);
780 goto cleanUp;
784 /* go back to beginning of chunk plus the requested position */
785 /* FIXME: I'm not sure this is correct, notably because some data linked to
786 * the decompression state machine will not be correcly initialized.
787 * try it this way (other way would be to decompress from 0 up to dwPosition
788 * and to start sending to hWave when dwPosition is reached)
790 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
792 /* By default the device will be opened for output, the MCI_CUE function is there to
793 * change from output to input and back
795 /* FIXME: how to choose between several output channels ? here mapper is forced */
796 dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
797 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
799 if (dwRet != 0) {
800 TRACE("Can't open low level audio device %ld\n", dwRet);
801 dwRet = MCIERR_DEVICE_OPEN;
802 wmw->hWave = 0;
803 goto cleanUp;
806 /* make it so that 3 buffers per second are needed */
807 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
809 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
810 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
811 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
812 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
813 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
814 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
815 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
816 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
817 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
818 dwRet = MCIERR_INTERNAL;
819 goto cleanUp;
822 whidx = 0;
823 left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition);
824 wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
825 wmw->dwEventCount = 1L; /* for first buffer */
827 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
829 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
830 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
831 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
832 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
833 if (count < 1)
834 break;
835 /* count is always <= bufsize, so this is correct regarding the
836 * waveOutPrepareHeader function
838 waveHdr[whidx].dwBufferLength = count;
839 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
840 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
841 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
842 waveHdr[whidx].dwBytesRecorded);
843 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
844 left -= count;
845 wmw->dwPosition += count;
846 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
848 WAVE_mciPlayWaitDone(wmw);
849 whidx ^= 1;
852 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
854 /* just to get rid of some race conditions between play, stop and pause */
855 waveOutReset(wmw->hWave);
857 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
858 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
860 dwRet = 0;
862 cleanUp:
863 HeapFree(GetProcessHeap(), 0, waveHdr);
865 if (wmw->hWave) {
866 waveOutClose(wmw->hWave);
867 wmw->hWave = 0;
869 CloseHandle(wmw->hEvent);
871 if (lpParms && (dwFlags & MCI_NOTIFY)) {
872 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
873 wmw->openParms.wDeviceID,
874 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
877 wmw->dwStatus = MCI_MODE_STOP;
879 return dwRet;
882 /**************************************************************************
883 * WAVE_mciPlayCallback [internal]
885 static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
886 DWORD_PTR dwInstance,
887 LPARAM dwParam1, LPARAM dwParam2)
889 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
890 LPWAVEHDR lpWaveHdr;
891 LONG count = 0;
893 switch (uMsg) {
894 case WIM_OPEN:
895 case WIM_CLOSE:
896 break;
897 case WIM_DATA:
898 lpWaveHdr = (LPWAVEHDR) dwParam1;
900 InterlockedIncrement(&wmw->dwEventCount);
902 count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
904 lpWaveHdr->dwFlags &= ~WHDR_DONE;
905 if (count > 0)
906 wmw->dwPosition += count;
907 /* else error reporting ?? */
908 if (wmw->dwStatus == MCI_MODE_RECORD)
910 /* Only queue up another buffer if we are recording. We could receive this
911 message also when waveInReset() is called, since it notifies on all wave
912 buffers that are outstanding. Queueing up more sometimes causes waveInClose
913 to fail. */
914 waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
915 TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
918 SetEvent(wmw->hEvent);
919 break;
920 default:
921 ERR("Unknown uMsg=%d\n", uMsg);
925 /******************************************************************
926 * bWAVE_mciRecordWaitDone
929 static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
931 for (;;) {
932 ResetEvent(wmw->hEvent);
933 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
934 break;
936 InterlockedIncrement(&wmw->dwEventCount);
938 WaitForSingleObject(wmw->hEvent, INFINITE);
942 /**************************************************************************
943 * WAVE_mciRecord [internal]
945 static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
947 DWORD end;
948 DWORD dwRet = MMSYSERR_NOERROR;
949 LONG bufsize;
950 LPWAVEHDR waveHdr = NULL;
951 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
953 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
955 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
956 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
958 /* FIXME : since there is no way to determine in which mode the device is
959 * open (recording/playback) automatically switch from a mode to another
961 wmw->fInput = TRUE;
963 if (wmw->dwStatus == MCI_MODE_PAUSE) {
964 /* FIXME: parameters (start/end) in lpParams may not be used */
965 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
968 /** This function will be called again by a thread when async is used.
969 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
970 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
972 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
973 return MCIERR_INTERNAL;
976 wmw->dwStatus = MCI_MODE_RECORD;
978 if (!(dwFlags & MCI_WAIT)) {
979 return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_RECORD, dwFlags,
980 (DWORD)lpParms, sizeof(MCI_RECORD_PARMS));
983 /* FIXME: we only re-create the RIFF structure from an existing file (if any)
984 * we don't modify the wave part of an existing file (ie. we always erase an
985 * existing content, we don't overwrite)
987 HeapFree(GetProcessHeap(), 0, (void*)wmw->openParms.lpstrElementName);
988 dwRet = create_tmp_file(&wmw->hFile, (WCHAR**)&wmw->openParms.lpstrElementName);
989 if (dwRet != 0) return dwRet;
991 /* new RIFF file */
992 dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
993 if (dwRet != 0) return dwRet; /* FIXME: we leak resources */
995 end = 0xFFFFFFFF;
996 if (lpParms && (dwFlags & MCI_FROM)) {
997 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
1000 if (lpParms && (dwFlags & MCI_TO)) {
1001 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1004 TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
1006 if (end <= wmw->dwPosition)
1008 return TRUE;
1011 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1012 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1014 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
1015 wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1017 /* go back to beginning of chunk plus the requested position */
1018 /* FIXME: I'm not sure this is correct, notably because some data linked to
1019 * the decompression state machine will not be correcly initialized.
1020 * try it this way (other way would be to decompress from 0 up to dwPosition
1021 * and to start sending to hWave when dwPosition is reached)
1023 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1025 /* By default the device will be opened for output, the MCI_CUE function is there to
1026 * change from output to input and back
1028 /* FIXME: how to choose between several output channels ? here mapper is forced */
1029 dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
1030 (DWORD)WAVE_mciRecordCallback, (DWORD)wmw, CALLBACK_FUNCTION);
1032 if (dwRet != MMSYSERR_NOERROR) {
1033 TRACE("Can't open low level audio device %ld\n", dwRet);
1034 dwRet = MCIERR_DEVICE_OPEN;
1035 wmw->hWave = 0;
1036 goto cleanUp;
1039 /* make it so that 3 buffers per second are needed */
1040 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1042 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1043 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1044 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1045 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
1046 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
1047 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
1048 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1050 if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1051 waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1052 dwRet = MCIERR_INTERNAL;
1053 goto cleanUp;
1056 if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1057 waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1058 dwRet = MCIERR_INTERNAL;
1059 goto cleanUp;
1062 wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1063 wmw->dwEventCount = 1L; /* for first buffer */
1065 TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1067 dwRet = waveInStart(wmw->hWave);
1069 while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1070 WAVE_mciRecordWaitDone(wmw);
1073 /* needed so that the callback above won't add again the buffers returned by the reset */
1074 wmw->dwStatus = MCI_MODE_STOP;
1076 waveInReset(wmw->hWave);
1078 waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1079 waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1081 dwRet = 0;
1083 cleanUp:
1084 HeapFree(GetProcessHeap(), 0, waveHdr);
1086 if (wmw->hWave) {
1087 waveInClose(wmw->hWave);
1088 wmw->hWave = 0;
1090 CloseHandle(wmw->hEvent);
1092 if (lpParms && (dwFlags & MCI_NOTIFY)) {
1093 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1094 wmw->openParms.wDeviceID,
1095 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1098 wmw->dwStatus = MCI_MODE_STOP;
1100 return dwRet;
1104 /**************************************************************************
1105 * WAVE_mciPause [internal]
1107 static DWORD WAVE_mciPause(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1109 DWORD dwRet;
1110 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1112 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1114 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1115 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1117 if (wmw->dwStatus == MCI_MODE_PLAY) {
1118 wmw->dwStatus = MCI_MODE_PAUSE;
1121 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
1122 else dwRet = waveOutPause(wmw->hWave);
1124 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1127 /**************************************************************************
1128 * WAVE_mciResume [internal]
1130 static DWORD WAVE_mciResume(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1132 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1133 DWORD dwRet = 0;
1135 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1137 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1139 if (wmw->dwStatus == MCI_MODE_PAUSE) {
1140 wmw->dwStatus = MCI_MODE_PLAY;
1143 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
1144 else dwRet = waveOutRestart(wmw->hWave);
1145 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1148 /**************************************************************************
1149 * WAVE_mciSeek [internal]
1151 static DWORD WAVE_mciSeek(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1153 DWORD ret = 0;
1154 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1156 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1158 if (lpParms == NULL) {
1159 ret = MCIERR_NULL_PARAMETER_BLOCK;
1160 } else if (wmw == NULL) {
1161 ret = MCIERR_INVALID_DEVICE_ID;
1162 } else {
1163 WAVE_mciStop(wDevID, MCI_WAIT, 0);
1165 if (dwFlags & MCI_SEEK_TO_START) {
1166 wmw->dwPosition = 0;
1167 } else if (dwFlags & MCI_SEEK_TO_END) {
1168 wmw->dwPosition = wmw->ckWaveData.cksize;
1169 } else if (dwFlags & MCI_TO) {
1170 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1171 } else {
1172 WARN("dwFlag doesn't tell where to seek to...\n");
1173 return MCIERR_MISSING_PARAMETER;
1176 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
1178 if (dwFlags & MCI_NOTIFY) {
1179 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1180 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1183 return ret;
1186 /**************************************************************************
1187 * WAVE_mciSet [internal]
1189 static DWORD WAVE_mciSet(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1191 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1193 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1195 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1196 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1198 if (dwFlags & MCI_SET_TIME_FORMAT) {
1199 switch (lpParms->dwTimeFormat) {
1200 case MCI_FORMAT_MILLISECONDS:
1201 TRACE("MCI_FORMAT_MILLISECONDS !\n");
1202 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1203 break;
1204 case MCI_FORMAT_BYTES:
1205 TRACE("MCI_FORMAT_BYTES !\n");
1206 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1207 break;
1208 case MCI_FORMAT_SAMPLES:
1209 TRACE("MCI_FORMAT_SAMPLES !\n");
1210 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1211 break;
1212 default:
1213 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
1214 return MCIERR_BAD_TIME_FORMAT;
1217 if (dwFlags & MCI_SET_VIDEO) {
1218 TRACE("No support for video !\n");
1219 return MCIERR_UNSUPPORTED_FUNCTION;
1221 if (dwFlags & MCI_SET_DOOR_OPEN) {
1222 TRACE("No support for door open !\n");
1223 return MCIERR_UNSUPPORTED_FUNCTION;
1225 if (dwFlags & MCI_SET_DOOR_CLOSED) {
1226 TRACE("No support for door close !\n");
1227 return MCIERR_UNSUPPORTED_FUNCTION;
1229 if (dwFlags & MCI_SET_AUDIO) {
1230 if (dwFlags & MCI_SET_ON) {
1231 TRACE("MCI_SET_ON audio !\n");
1232 } else if (dwFlags & MCI_SET_OFF) {
1233 TRACE("MCI_SET_OFF audio !\n");
1234 } else {
1235 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1236 return MCIERR_BAD_INTEGER;
1239 switch (lpParms->dwAudio)
1241 case MCI_SET_AUDIO_ALL: TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1242 case MCI_SET_AUDIO_LEFT: TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1243 case MCI_SET_AUDIO_RIGHT: TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1244 default: WARN("Unknown audio channel %lu\n", lpParms->dwAudio); break;
1247 if (dwFlags & MCI_WAVE_INPUT)
1248 TRACE("MCI_WAVE_INPUT !\n");
1249 if (dwFlags & MCI_WAVE_OUTPUT)
1250 TRACE("MCI_WAVE_OUTPUT !\n");
1251 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
1252 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
1253 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
1254 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
1255 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1256 wmw->wfxRef.nAvgBytesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nAvgBytesPerSec;
1257 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %ld\n", wmw->wfxRef.nAvgBytesPerSec);
1259 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1260 wmw->wfxRef.wBitsPerSample = ((LPMCI_WAVE_SET_PARMS)lpParms)->wBitsPerSample;
1261 TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1263 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1264 wmw->wfxRef.nBlockAlign = ((LPMCI_WAVE_SET_PARMS)lpParms)->nBlockAlign;
1265 TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1267 if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1268 wmw->wfxRef.nChannels = ((LPMCI_WAVE_SET_PARMS)lpParms)->nChannels;
1269 TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1271 if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1272 wmw->wfxRef.wFormatTag = ((LPMCI_WAVE_SET_PARMS)lpParms)->wFormatTag;
1273 TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", wmw->wfxRef.wFormatTag);
1275 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1276 wmw->wfxRef.nSamplesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nSamplesPerSec;
1277 TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %ld\n", wmw->wfxRef.nSamplesPerSec);
1279 return 0;
1282 /**************************************************************************
1283 * WAVE_mciSave [internal]
1285 static DWORD WAVE_mciSave(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SAVE_PARMSW lpParms)
1287 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1288 DWORD ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1289 WPARAM wparam = MCI_NOTIFY_FAILURE;
1291 TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1292 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1293 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1295 if (dwFlags & MCI_WAIT)
1297 FIXME("MCI_WAIT not implemented\n");
1299 WAVE_mciStop(wDevID, 0, NULL);
1301 ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1302 ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1304 ret = mmioClose(wmw->hFile, 0);
1305 wmw->hFile = 0;
1308 If the destination file already exists, it has to be overwritten. (Behaviour
1309 verified in Windows (2000)). If it doesn't overwrite, it is breaking one of
1310 my applications. We are making use of mmioRename, which WILL NOT overwrite
1311 the destination file (which is what Windows does, also verified in Win2K)
1312 So, lets delete the destination file before calling mmioRename. If the
1313 destination file DOESN'T exist, the delete will fail silently. Let's also be
1314 careful not to lose our previous error code.
1316 tmpRet = GetLastError();
1317 DeleteFileW (lpParms->lpfilename);
1318 SetLastError(tmpRet);
1320 if (0 == mmioRenameW(wmw->openParms.lpstrElementName, lpParms->lpfilename, 0, 0 )) {
1321 ret = MMSYSERR_NOERROR;
1324 if (dwFlags & MCI_NOTIFY) {
1325 if (ret == MMSYSERR_NOERROR) wparam = MCI_NOTIFY_SUCCESSFUL;
1327 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1328 wmw->openParms.wDeviceID, wparam);
1331 if (ret == MMSYSERR_NOERROR)
1332 ret = WAVE_mciOpenFile(wmw, lpParms->lpfilename);
1334 return ret;
1337 /**************************************************************************
1338 * WAVE_mciStatus [internal]
1340 static DWORD WAVE_mciStatus(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1342 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1343 DWORD ret = 0;
1345 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1346 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1347 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1349 if (dwFlags & MCI_STATUS_ITEM) {
1350 switch (lpParms->dwItem) {
1351 case MCI_STATUS_CURRENT_TRACK:
1352 lpParms->dwReturn = 1;
1353 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1354 break;
1355 case MCI_STATUS_LENGTH:
1356 if (!wmw->hFile) {
1357 lpParms->dwReturn = 0;
1358 return MCIERR_UNSUPPORTED_FUNCTION;
1360 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1361 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
1362 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1363 break;
1364 case MCI_STATUS_MODE:
1365 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1366 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1367 ret = MCI_RESOURCE_RETURNED;
1368 break;
1369 case MCI_STATUS_MEDIA_PRESENT:
1370 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1371 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1372 ret = MCI_RESOURCE_RETURNED;
1373 break;
1374 case MCI_STATUS_NUMBER_OF_TRACKS:
1375 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1376 lpParms->dwReturn = 1;
1377 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
1378 break;
1379 case MCI_STATUS_POSITION:
1380 if (!wmw->hFile) {
1381 lpParms->dwReturn = 0;
1382 return MCIERR_UNSUPPORTED_FUNCTION;
1384 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1385 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1386 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
1387 &ret);
1388 TRACE("MCI_STATUS_POSITION %s => %lu\n",
1389 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1390 break;
1391 case MCI_STATUS_READY:
1392 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1393 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1394 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1395 ret = MCI_RESOURCE_RETURNED;
1396 break;
1397 case MCI_STATUS_TIME_FORMAT:
1398 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, MCI_FORMAT_RETURN_BASE + wmw->dwMciTimeFormat);
1399 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1400 ret = MCI_RESOURCE_RETURNED;
1401 break;
1402 case MCI_WAVE_INPUT:
1403 TRACE("MCI_WAVE_INPUT !\n");
1404 lpParms->dwReturn = 0;
1405 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1406 break;
1407 case MCI_WAVE_OUTPUT:
1408 TRACE("MCI_WAVE_OUTPUT !\n");
1410 UINT id;
1411 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
1412 lpParms->dwReturn = id;
1413 } else {
1414 lpParms->dwReturn = 0;
1415 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1418 break;
1419 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1420 if (!wmw->hFile) {
1421 lpParms->dwReturn = 0;
1422 return MCIERR_UNSUPPORTED_FUNCTION;
1424 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1425 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1426 break;
1427 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1428 if (!wmw->hFile) {
1429 lpParms->dwReturn = 0;
1430 return MCIERR_UNSUPPORTED_FUNCTION;
1432 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1433 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1434 break;
1435 case MCI_WAVE_STATUS_BLOCKALIGN:
1436 if (!wmw->hFile) {
1437 lpParms->dwReturn = 0;
1438 return MCIERR_UNSUPPORTED_FUNCTION;
1440 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1441 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1442 break;
1443 case MCI_WAVE_STATUS_CHANNELS:
1444 if (!wmw->hFile) {
1445 lpParms->dwReturn = 0;
1446 return MCIERR_UNSUPPORTED_FUNCTION;
1448 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1449 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1450 break;
1451 case MCI_WAVE_STATUS_FORMATTAG:
1452 if (!wmw->hFile) {
1453 lpParms->dwReturn = 0;
1454 return MCIERR_UNSUPPORTED_FUNCTION;
1456 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1457 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1458 break;
1459 case MCI_WAVE_STATUS_LEVEL:
1460 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1461 lpParms->dwReturn = 0xAAAA5555;
1462 break;
1463 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1464 if (!wmw->hFile) {
1465 lpParms->dwReturn = 0;
1466 return MCIERR_UNSUPPORTED_FUNCTION;
1468 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1469 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1470 break;
1471 default:
1472 WARN("unknown command %08lX !\n", lpParms->dwItem);
1473 return MCIERR_UNRECOGNIZED_COMMAND;
1476 if (dwFlags & MCI_NOTIFY) {
1477 mciDriverNotify(HWND_32(LOWORD(lpParms->dwCallback)),
1478 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1480 return ret;
1483 /**************************************************************************
1484 * WAVE_mciGetDevCaps [internal]
1486 static DWORD WAVE_mciGetDevCaps(MCIDEVICEID wDevID, DWORD dwFlags,
1487 LPMCI_GETDEVCAPS_PARMS lpParms)
1489 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1490 DWORD ret = 0;
1492 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1494 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1495 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1497 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1498 switch(lpParms->dwItem) {
1499 case MCI_GETDEVCAPS_DEVICE_TYPE:
1500 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1501 ret = MCI_RESOURCE_RETURNED;
1502 break;
1503 case MCI_GETDEVCAPS_HAS_AUDIO:
1504 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1505 ret = MCI_RESOURCE_RETURNED;
1506 break;
1507 case MCI_GETDEVCAPS_HAS_VIDEO:
1508 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1509 ret = MCI_RESOURCE_RETURNED;
1510 break;
1511 case MCI_GETDEVCAPS_USES_FILES:
1512 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1513 ret = MCI_RESOURCE_RETURNED;
1514 break;
1515 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1516 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1517 ret = MCI_RESOURCE_RETURNED;
1518 break;
1519 case MCI_GETDEVCAPS_CAN_RECORD:
1520 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1521 ret = MCI_RESOURCE_RETURNED;
1522 break;
1523 case MCI_GETDEVCAPS_CAN_EJECT:
1524 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1525 ret = MCI_RESOURCE_RETURNED;
1526 break;
1527 case MCI_GETDEVCAPS_CAN_PLAY:
1528 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1529 ret = MCI_RESOURCE_RETURNED;
1530 break;
1531 case MCI_GETDEVCAPS_CAN_SAVE:
1532 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1533 ret = MCI_RESOURCE_RETURNED;
1534 break;
1535 case MCI_WAVE_GETDEVCAPS_INPUTS:
1536 lpParms->dwReturn = 1;
1537 break;
1538 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1539 lpParms->dwReturn = 1;
1540 break;
1541 default:
1542 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1543 return MCIERR_UNRECOGNIZED_COMMAND;
1545 } else {
1546 WARN("No GetDevCaps-Item !\n");
1547 return MCIERR_UNRECOGNIZED_COMMAND;
1549 return ret;
1552 /**************************************************************************
1553 * WAVE_mciInfo [internal]
1555 static DWORD WAVE_mciInfo(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
1557 DWORD ret = 0;
1558 LPCWSTR str = 0;
1559 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1561 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1563 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1564 ret = MCIERR_NULL_PARAMETER_BLOCK;
1565 } else if (wmw == NULL) {
1566 ret = MCIERR_INVALID_DEVICE_ID;
1567 } else {
1568 static const WCHAR wszAudio [] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','p','l','a','y','e','r',0};
1569 static const WCHAR wszWaveIn [] = {'W','i','n','e',' ','W','a','v','e',' ','I','n',0};
1570 static const WCHAR wszWaveOut[] = {'W','i','n','e',' ','W','a','v','e',' ','O','u','t',0};
1572 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1574 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1575 case MCI_INFO_PRODUCT: str = wszAudio; break;
1576 case MCI_INFO_FILE: str = wmw->openParms.lpstrElementName; break;
1577 case MCI_WAVE_INPUT: str = wszWaveIn; break;
1578 case MCI_WAVE_OUTPUT: str = wszWaveOut; break;
1579 default:
1580 WARN("Don't know this info command (%lu)\n", dwFlags);
1581 ret = MCIERR_UNRECOGNIZED_COMMAND;
1584 if (str) {
1585 if (strlenW(str) + 1 > lpParms->dwRetSize) {
1586 ret = MCIERR_PARAM_OVERFLOW;
1587 } else {
1588 lstrcpynW(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1590 } else {
1591 lpParms->lpstrReturn[0] = 0;
1594 return ret;
1597 /**************************************************************************
1598 * DriverProc (MCIWAVE.@)
1600 LRESULT CALLBACK MCIWAVE_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1601 LPARAM dwParam1, LPARAM dwParam2)
1603 TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1604 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1606 switch (wMsg) {
1607 case DRV_LOAD: return 1;
1608 case DRV_FREE: return 1;
1609 case DRV_OPEN: return WAVE_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1610 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1611 case DRV_ENABLE: return 1;
1612 case DRV_DISABLE: return 1;
1613 case DRV_QUERYCONFIGURE: return 1;
1614 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1615 case DRV_INSTALL: return DRVCNF_RESTART;
1616 case DRV_REMOVE: return DRVCNF_RESTART;
1619 if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1621 switch (wMsg) {
1622 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSW) dwParam2);
1623 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1624 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1625 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1626 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1627 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1628 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1629 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1630 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1631 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1632 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1633 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSW) dwParam2);
1634 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1635 case MCI_SAVE: return WAVE_mciSave (dwDevID, dwParam1, (LPMCI_SAVE_PARMSW) dwParam2);
1636 /* commands that should be supported */
1637 case MCI_LOAD:
1638 case MCI_FREEZE:
1639 case MCI_PUT:
1640 case MCI_REALIZE:
1641 case MCI_UNFREEZE:
1642 case MCI_UPDATE:
1643 case MCI_WHERE:
1644 case MCI_STEP:
1645 case MCI_SPIN:
1646 case MCI_ESCAPE:
1647 case MCI_COPY:
1648 case MCI_CUT:
1649 case MCI_DELETE:
1650 case MCI_PASTE:
1651 FIXME("Unsupported yet command [%u]\n", wMsg);
1652 break;
1653 case MCI_WINDOW:
1654 TRACE("Unsupported command [%u]\n", wMsg);
1655 break;
1656 /* option which can be silenced */
1657 case MCI_CONFIGURE:
1658 return 0;
1659 case MCI_OPEN:
1660 case MCI_CLOSE:
1661 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1662 break;
1663 default:
1664 FIXME("is probably wrong msg [%u]\n", wMsg);
1665 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1667 return MCIERR_UNRECOGNIZED_COMMAND;