1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample Wine Driver for MCI wave forms
5 * Copyright 1994 Martin Ayotte
10 * - record/play should and must be done asynchronous
18 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(mciwave)
25 int nUseCount; /* Incremented for each shared open */
26 BOOL fShareable; /* TRUE if first open was shareable */
27 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
28 HMMIO hFile; /* mmio file handle open as Element */
29 MCI_WAVE_OPEN_PARMSA openParms;
30 LPWAVEFORMATEX lpWaveFormat;
31 BOOL fInput; /* FALSE = Output, TRUE = Input */
32 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
33 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
34 DWORD dwFileOffset; /* Offset of chunk in mmio file */
35 DWORD dwLength; /* number of bytes in chunk for playing */
36 DWORD dwPosition; /* position in bytes in chunk for playing */
37 HANDLE hEvent; /* for synchronization */
38 DWORD dwEventCount; /* for synchronization */
41 /* ===================================================================
42 * ===================================================================
43 * FIXME: should be using the new mmThreadXXXX functions from WINMM
45 * it would require to add a wine internal flag to mmThreadCreate
46 * in order to pass a 32 bit function instead of a 16 bit one
47 * ===================================================================
48 * =================================================================== */
58 /**************************************************************************
59 * MCI_SCAStarter [internal]
61 static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
63 struct SCA* sca = (struct SCA*)arg;
66 TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
67 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
68 ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
69 TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
70 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
71 if (sca->allocatedCopy)
72 HeapFree(GetProcessHeap(), 0, (LPVOID)sca->dwParam2);
73 HeapFree(GetProcessHeap(), 0, sca);
75 WARN("Should not happen ? what's wrong \n");
76 /* should not go after this point */
80 /**************************************************************************
81 * MCI_SendCommandAsync [internal]
83 static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
84 DWORD dwParam2, UINT size)
86 struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA));
89 return MCIERR_OUT_OF_MEMORY;
93 sca->dwParam1 = dwParam1;
96 sca->dwParam2 = (DWORD)HeapAlloc(GetProcessHeap(), 0, size);
97 if (sca->dwParam2 == 0) {
98 HeapFree(GetProcessHeap(), 0, sca);
99 return MCIERR_OUT_OF_MEMORY;
101 sca->allocatedCopy = TRUE;
102 /* copy structure passed by program in dwParam2 to be sure
103 * we can still use it whatever the program does
105 memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
107 sca->dwParam2 = dwParam2;
108 sca->allocatedCopy = FALSE;
111 if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
112 WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
113 return MCI_SCAStarter(&sca);
118 /*======================================================================*
119 * MCI WAVE implemantation *
120 *======================================================================*/
122 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
124 /**************************************************************************
125 * MCIWAVE_drvOpen [internal]
127 static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
129 WINE_MCIWAVE* wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
134 wmw->wDevID = modp->wDeviceID;
135 mciSetDriverData(wmw->wDevID, (DWORD)wmw);
136 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
137 modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
138 return modp->wDeviceID;
141 /**************************************************************************
142 * MCIWAVE_drvClose [internal]
144 static DWORD WAVE_drvClose(DWORD dwDevID)
146 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
149 HeapFree(GetProcessHeap(), 0, wmw);
150 mciSetDriverData(dwDevID, 0);
156 /**************************************************************************
157 * WAVE_mciGetOpenDev [internal]
159 static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
161 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
163 if (wmw == NULL || wmw->nUseCount == 0) {
164 WARN("Invalid wDevID=%u\n", wDevID);
170 /**************************************************************************
171 * WAVE_ConvertByteToTimeFormat [internal]
173 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
177 switch (wmw->dwMciTimeFormat) {
178 case MCI_FORMAT_MILLISECONDS:
179 ret = (val * 1000) / wmw->lpWaveFormat->nAvgBytesPerSec;
181 case MCI_FORMAT_BYTES:
184 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
185 ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
188 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
190 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
195 /**************************************************************************
196 * WAVE_ConvertTimeFormatToByte [internal]
198 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
202 switch (wmw->dwMciTimeFormat) {
203 case MCI_FORMAT_MILLISECONDS:
204 ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
206 case MCI_FORMAT_BYTES:
209 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
210 ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
213 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
215 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
219 /**************************************************************************
220 * WAVE_mciReadFmt [internal]
222 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
227 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
228 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
229 return MCIERR_INVALID_FILE;
230 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
231 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
233 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
234 r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
235 if (r < sizeof(WAVEFORMAT))
236 return MCIERR_INVALID_FILE;
238 TRACE("wFormatTag=%04X !\n", wmw->lpWaveFormat->wFormatTag);
239 TRACE("nChannels=%d \n", wmw->lpWaveFormat->nChannels);
240 TRACE("nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nSamplesPerSec);
241 TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
242 TRACE("nBlockAlign=%d \n", wmw->lpWaveFormat->nBlockAlign);
243 TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
244 if (r >= (long)sizeof(WAVEFORMATEX))
245 TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
247 mmioAscend(wmw->hFile, &mmckInfo, 0);
248 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
249 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
250 TRACE("can't find data chunk\n");
251 return MCIERR_INVALID_FILE;
253 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
254 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
255 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
256 wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
257 wmw->dwLength = mmckInfo.cksize;
258 wmw->dwFileOffset = mmckInfo.dwDataOffset;
262 /**************************************************************************
263 * WAVE_mciOpen [internal]
265 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
269 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
271 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
272 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
273 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
275 if (dwFlags & MCI_OPEN_SHAREABLE)
276 return MCIERR_HARDWARE;
278 if (wmw->nUseCount > 0) {
279 /* The driver is already opened on this channel
280 * Wave driver cannot be shared
282 return MCIERR_DEVICE_OPEN;
286 dwDeviceID = lpOpenParms->wDeviceID;
291 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
293 if (dwFlags & MCI_OPEN_ELEMENT) {
294 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
295 /* could it be that (DWORD)lpOpenParms->lpstrElementName
296 * contains the hFile value ?
298 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
300 LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
302 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
303 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
304 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
305 wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL,
306 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
307 if (wmw->hFile == 0) {
308 WARN("can't find file='%s' !\n", lpstrElementName);
309 dwRet = MCIERR_FILE_NOT_FOUND;
316 TRACE("hFile=%u\n", wmw->hFile);
318 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
319 wmw->wNotifyDeviceID = dwDeviceID;
320 wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
322 if (dwRet == 0 && wmw->hFile != 0) {
325 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
326 dwRet = MCIERR_INVALID_FILE;
328 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
329 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
330 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
331 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
332 dwRet = MCIERR_INVALID_FILE;
334 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
341 if (wmw->lpWaveFormat) {
342 switch (wmw->lpWaveFormat->wFormatTag) {
343 case WAVE_FORMAT_PCM:
344 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
345 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
346 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
347 wmw->lpWaveFormat->nAvgBytesPerSec,
348 wmw->lpWaveFormat->nSamplesPerSec *
349 wmw->lpWaveFormat->nBlockAlign);
350 wmw->lpWaveFormat->nAvgBytesPerSec =
351 wmw->lpWaveFormat->nSamplesPerSec *
352 wmw->lpWaveFormat->nBlockAlign;
359 wmw->dwStatus = MCI_MODE_STOP;
363 mmioClose(wmw->hFile, 0);
369 /**************************************************************************
370 * WAVE_mciCue [internal]
372 static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
377 This routine is far from complete. At the moment only a check is done on the
378 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
381 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
386 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
388 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
390 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
392 /* always close elements ? */
393 if (wmw->hFile != 0) {
394 mmioClose(wmw->hFile, 0);
398 dwRet = MMSYSERR_NOERROR; /* assume success */
400 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
401 dwRet = waveOutClose(wmw->hWave);
402 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
404 } else if (wmw->fInput) {
405 dwRet = waveInClose(wmw->hWave);
406 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
410 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
413 /**************************************************************************
414 * WAVE_mciStop [internal]
416 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
419 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
421 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
423 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
425 /* wait for playback thread (if any) to exit before processing further */
426 switch (wmw->dwStatus) {
429 case MCI_MODE_RECORD:
431 int oldStat = wmw->dwStatus;
432 wmw->dwStatus = MCI_MODE_NOT_READY;
433 if (oldStat == MCI_MODE_PAUSE)
434 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
436 while (wmw->dwStatus != MCI_MODE_STOP)
444 wmw->dwStatus = MCI_MODE_STOP;
446 if ((dwFlags & MCI_NOTIFY) && lpParms) {
447 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
448 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
454 /**************************************************************************
455 * WAVE_mciClose [internal]
457 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
460 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
462 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
464 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
466 if (wmw->dwStatus != MCI_MODE_STOP) {
467 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
472 if (wmw->nUseCount == 0) {
473 if (wmw->hFile != 0) {
474 mmioClose(wmw->hFile, 0);
479 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
480 wmw->lpWaveFormat = NULL;
482 if ((dwFlags & MCI_NOTIFY) && lpParms) {
483 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
484 wmw->wNotifyDeviceID,
485 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
491 /**************************************************************************
492 * WAVE_mciPlayCallback [internal]
494 static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
496 DWORD dwParam1, DWORD dwParam2)
498 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
505 InterlockedIncrement(&wmw->dwEventCount);
506 TRACE("Returning waveHdr=%lx\n", dwParam1);
507 SetEvent(wmw->hEvent);
510 ERR("Unknown uMsg=%d\n", uMsg);
514 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
517 ResetEvent(wmw->hEvent);
518 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
521 InterlockedIncrement(&wmw->dwEventCount);
523 WaitForSingleObject(wmw->hEvent, INFINITE);
527 /**************************************************************************
528 * WAVE_mciPlay [internal]
530 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
533 LONG bufsize, count, left;
535 LPWAVEHDR waveHdr = NULL;
536 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
539 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
541 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
542 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
545 WARN("cannot play on input device\n");
546 return MCIERR_NONAPPLICABLE_FUNCTION;
549 if (wmw->hFile == 0) {
550 WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
551 return MCIERR_FILE_NOT_FOUND;
554 if (wmw->dwStatus == MCI_MODE_PAUSE) {
555 /* FIXME: parameters (start/end) in lpParams may not be used */
556 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
559 /** This function will be called again by a thread when async is used.
560 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
561 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
563 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
564 return MCIERR_INTERNAL;
567 wmw->dwStatus = MCI_MODE_PLAY;
569 if (!(dwFlags & MCI_WAIT)) {
570 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
571 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
575 if (lpParms && (dwFlags & MCI_FROM)) {
576 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
578 if (lpParms && (dwFlags & MCI_TO)) {
579 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
582 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
584 if (end <= wmw->dwPosition)
587 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
588 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
590 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
591 wmw->dwLength = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwLength);
592 /* go back to begining of chunk plus the requested position */
593 /* FIXME: I'm not sure this is correct, notably because some data linked to
594 * the decompression state machine will not be correcly initialized.
595 * try it this way (other way would be to decompress from 0 up to dwPosition
596 * and to start sending to hWave when dwPosition is reached)
598 mmioSeek(wmw->hFile, wmw->dwFileOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
600 /* By default the device will be opened for output, the MCI_CUE function is there to
601 * change from output to input and back
603 /* FIXME: how to choose between several output channels ? here mapper is forced */
604 dwRet = waveOutOpen(&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
605 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
608 TRACE("Can't open low level audio device %ld\n", dwRet);
609 dwRet = MCIERR_DEVICE_OPEN;
614 /* make it so that 3 buffers per second are needed */
615 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
617 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
618 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
619 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
620 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
621 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
622 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
623 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
624 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
625 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
626 dwRet = MCIERR_INTERNAL;
631 left = min(wmw->dwLength, end - wmw->dwPosition);
632 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
633 wmw->dwEventCount = 1L; /* for first buffer */
635 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
637 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
638 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
639 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
640 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
643 /* count is always <= bufsize, so this is correct regarding the
644 * waveOutPrepareHeader function
646 waveHdr[whidx].dwBufferLength = count;
647 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
648 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
649 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
650 waveHdr[whidx].dwBytesRecorded);
651 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
653 wmw->dwPosition += count;
654 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
656 WAVE_mciPlayWaitDone(wmw);
660 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
662 /* just to get rid of some race conditions between play, stop and pause */
663 waveOutReset(wmw->hWave);
665 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
666 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
671 HeapFree(GetProcessHeap(), 0, waveHdr);
674 waveOutClose(wmw->hWave);
677 CloseHandle(wmw->hEvent);
679 if (lpParms && (dwFlags & MCI_NOTIFY)) {
680 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
681 wmw->wNotifyDeviceID,
682 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
685 wmw->dwStatus = MCI_MODE_STOP;
690 /**************************************************************************
691 * WAVE_mciRecord [internal]
693 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
699 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
701 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
703 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
704 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
707 WARN("cannot record on output device\n");
708 return MCIERR_NONAPPLICABLE_FUNCTION;
711 if (wmw->hFile == 0) {
712 WARN("can't find file='%s' !\n",
713 wmw->openParms.lpstrElementName);
714 return MCIERR_FILE_NOT_FOUND;
716 start = 1; end = 99999;
717 if (dwFlags & MCI_FROM) {
718 start = lpParms->dwFrom;
719 TRACE("MCI_FROM=%d \n", start);
721 if (dwFlags & MCI_TO) {
723 TRACE("MCI_TO=%d \n", end);
726 waveHdr.lpData = HeapAlloc(GetProcessHeap(), 0, bufsize);
727 waveHdr.dwBufferLength = bufsize;
729 waveHdr.dwFlags = 0L;
730 waveHdr.dwLoops = 0L;
731 dwRet = waveInPrepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
733 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
734 waveHdr.dwBytesRecorded = 0;
735 dwRet = waveInStart(wmw->hWave);
736 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
737 &waveHdr, waveHdr.dwBytesRecorded);
738 if (waveHdr.dwBytesRecorded == 0) break;
740 dwRet = waveInUnprepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
741 HeapFree(GetProcessHeap(), 0, waveHdr.lpData);
743 if (dwFlags & MCI_NOTIFY) {
744 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
745 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
750 /**************************************************************************
751 * WAVE_mciPause [internal]
753 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
756 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
758 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
760 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
761 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
763 if (wmw->dwStatus == MCI_MODE_PLAY) {
764 wmw->dwStatus = MCI_MODE_PAUSE;
767 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
768 else dwRet = waveOutPause(wmw->hWave);
770 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
773 /**************************************************************************
774 * WAVE_mciResume [internal]
776 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
778 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
781 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
783 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
785 if (wmw->dwStatus == MCI_MODE_PAUSE) {
786 wmw->dwStatus = MCI_MODE_PLAY;
789 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
790 else dwRet = waveOutRestart(wmw->hWave);
791 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
794 /**************************************************************************
795 * WAVE_mciSeek [internal]
797 static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
800 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
802 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
804 if (lpParms == NULL) {
805 ret = MCIERR_NULL_PARAMETER_BLOCK;
806 } else if (wmw == NULL) {
807 ret = MCIERR_INVALID_DEVICE_ID;
809 WAVE_mciStop(wDevID, MCI_WAIT, 0);
811 if (dwFlags & MCI_SEEK_TO_START) {
813 } else if (dwFlags & MCI_SEEK_TO_END) {
814 wmw->dwPosition = wmw->dwLength;
815 } else if (dwFlags & MCI_TO) {
816 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
818 WARN("dwFlag doesn't tell where to seek to...\n");
819 return MCIERR_MISSING_PARAMETER;
822 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
824 if (dwFlags & MCI_NOTIFY) {
825 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
826 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
832 /**************************************************************************
833 * WAVE_mciSet [internal]
835 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
837 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
839 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
841 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
842 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
844 if (dwFlags & MCI_SET_TIME_FORMAT) {
845 switch (lpParms->dwTimeFormat) {
846 case MCI_FORMAT_MILLISECONDS:
847 TRACE("MCI_FORMAT_MILLISECONDS !\n");
848 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
850 case MCI_FORMAT_BYTES:
851 TRACE("MCI_FORMAT_BYTES !\n");
852 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
854 case MCI_FORMAT_SAMPLES:
855 TRACE("MCI_FORMAT_SAMPLES !\n");
856 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
859 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
860 return MCIERR_BAD_TIME_FORMAT;
863 if (dwFlags & MCI_SET_VIDEO) {
864 TRACE("No support for video !\n");
865 return MCIERR_UNSUPPORTED_FUNCTION;
867 if (dwFlags & MCI_SET_DOOR_OPEN) {
868 TRACE("No support for door open !\n");
869 return MCIERR_UNSUPPORTED_FUNCTION;
871 if (dwFlags & MCI_SET_DOOR_CLOSED) {
872 TRACE("No support for door close !\n");
873 return MCIERR_UNSUPPORTED_FUNCTION;
875 if (dwFlags & MCI_SET_AUDIO) {
876 if (dwFlags & MCI_SET_ON) {
877 TRACE("MCI_SET_ON audio !\n");
878 } else if (dwFlags & MCI_SET_OFF) {
879 TRACE("MCI_SET_OFF audio !\n");
881 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
882 return MCIERR_BAD_INTEGER;
885 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
886 TRACE("MCI_SET_AUDIO_ALL !\n");
887 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
888 TRACE("MCI_SET_AUDIO_LEFT !\n");
889 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
890 TRACE("MCI_SET_AUDIO_RIGHT !\n");
892 if (dwFlags & MCI_WAVE_INPUT)
893 TRACE("MCI_WAVE_INPUT !\n");
894 if (dwFlags & MCI_WAVE_OUTPUT)
895 TRACE("MCI_WAVE_OUTPUT !\n");
896 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
897 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
898 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
899 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
900 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
901 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
902 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
903 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
904 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
905 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
906 if (dwFlags & MCI_WAVE_SET_CHANNELS)
907 TRACE("MCI_WAVE_SET_CHANNELS !\n");
908 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
909 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
910 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
911 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
915 /**************************************************************************
916 * WAVE_mciStatus [internal]
918 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
920 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
923 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
924 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
925 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
927 if (dwFlags & MCI_STATUS_ITEM) {
928 switch (lpParms->dwItem) {
929 case MCI_STATUS_CURRENT_TRACK:
930 lpParms->dwReturn = 1;
931 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
933 case MCI_STATUS_LENGTH:
935 lpParms->dwReturn = 0;
936 return MCIERR_UNSUPPORTED_FUNCTION;
938 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
939 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
940 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
942 case MCI_STATUS_MODE:
943 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
944 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
945 ret = MCI_RESOURCE_RETURNED;
947 case MCI_STATUS_MEDIA_PRESENT:
948 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
949 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
950 ret = MCI_RESOURCE_RETURNED;
952 case MCI_STATUS_NUMBER_OF_TRACKS:
953 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
954 lpParms->dwReturn = 1;
955 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
957 case MCI_STATUS_POSITION:
959 lpParms->dwReturn = 0;
960 return MCIERR_UNSUPPORTED_FUNCTION;
962 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
963 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
964 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
966 TRACE("MCI_STATUS_POSITION %s => %lu\n",
967 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
969 case MCI_STATUS_READY:
970 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
971 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
972 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
973 ret = MCI_RESOURCE_RETURNED;
975 case MCI_STATUS_TIME_FORMAT:
976 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
977 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
978 ret = MCI_RESOURCE_RETURNED;
981 TRACE("MCI_WAVE_INPUT !\n");
982 lpParms->dwReturn = 0;
983 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
985 case MCI_WAVE_OUTPUT:
986 TRACE("MCI_WAVE_OUTPUT !\n");
989 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
990 lpParms->dwReturn = id;
992 lpParms->dwReturn = 0;
993 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
997 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
999 lpParms->dwReturn = 0;
1000 return MCIERR_UNSUPPORTED_FUNCTION;
1002 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1003 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1005 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1007 lpParms->dwReturn = 0;
1008 return MCIERR_UNSUPPORTED_FUNCTION;
1010 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1011 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1013 case MCI_WAVE_STATUS_BLOCKALIGN:
1015 lpParms->dwReturn = 0;
1016 return MCIERR_UNSUPPORTED_FUNCTION;
1018 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1019 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1021 case MCI_WAVE_STATUS_CHANNELS:
1023 lpParms->dwReturn = 0;
1024 return MCIERR_UNSUPPORTED_FUNCTION;
1026 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1027 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1029 case MCI_WAVE_STATUS_FORMATTAG:
1031 lpParms->dwReturn = 0;
1032 return MCIERR_UNSUPPORTED_FUNCTION;
1034 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1035 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1037 case MCI_WAVE_STATUS_LEVEL:
1038 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1039 lpParms->dwReturn = 0xAAAA5555;
1041 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1043 lpParms->dwReturn = 0;
1044 return MCIERR_UNSUPPORTED_FUNCTION;
1046 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1047 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1050 WARN("unknown command %08lX !\n", lpParms->dwItem);
1051 return MCIERR_UNRECOGNIZED_COMMAND;
1054 if (dwFlags & MCI_NOTIFY) {
1055 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
1056 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
1061 /**************************************************************************
1062 * WAVE_mciGetDevCaps [internal]
1064 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1065 LPMCI_GETDEVCAPS_PARMS lpParms)
1067 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1070 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1072 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1073 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1075 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1076 switch(lpParms->dwItem) {
1077 case MCI_GETDEVCAPS_DEVICE_TYPE:
1078 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1079 ret = MCI_RESOURCE_RETURNED;
1081 case MCI_GETDEVCAPS_HAS_AUDIO:
1082 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1083 ret = MCI_RESOURCE_RETURNED;
1085 case MCI_GETDEVCAPS_HAS_VIDEO:
1086 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1087 ret = MCI_RESOURCE_RETURNED;
1089 case MCI_GETDEVCAPS_USES_FILES:
1090 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1091 ret = MCI_RESOURCE_RETURNED;
1093 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1094 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1095 ret = MCI_RESOURCE_RETURNED;
1097 case MCI_GETDEVCAPS_CAN_RECORD:
1098 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1099 ret = MCI_RESOURCE_RETURNED;
1101 case MCI_GETDEVCAPS_CAN_EJECT:
1102 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1103 ret = MCI_RESOURCE_RETURNED;
1105 case MCI_GETDEVCAPS_CAN_PLAY:
1106 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1107 ret = MCI_RESOURCE_RETURNED;
1109 case MCI_GETDEVCAPS_CAN_SAVE:
1110 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1111 ret = MCI_RESOURCE_RETURNED;
1113 case MCI_WAVE_GETDEVCAPS_INPUTS:
1114 lpParms->dwReturn = 1;
1116 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1117 lpParms->dwReturn = 1;
1120 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1121 return MCIERR_UNRECOGNIZED_COMMAND;
1124 WARN("No GetDevCaps-Item !\n");
1125 return MCIERR_UNRECOGNIZED_COMMAND;
1130 /**************************************************************************
1131 * WAVE_mciInfo [internal]
1133 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1137 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1139 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1141 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1142 ret = MCIERR_NULL_PARAMETER_BLOCK;
1143 } else if (wmw == NULL) {
1144 ret = MCIERR_INVALID_DEVICE_ID;
1146 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1148 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1149 case MCI_INFO_PRODUCT:
1150 str = "Wine's audio player";
1153 str = wmw->openParms.lpstrElementName;
1155 case MCI_WAVE_INPUT:
1156 str = "Wine Wave In";
1158 case MCI_WAVE_OUTPUT:
1159 str = "Wine Wave Out";
1162 WARN("Don't know this info command (%lu)\n", dwFlags);
1163 ret = MCIERR_UNRECOGNIZED_COMMAND;
1167 if (strlen(str) + 1 > lpParms->dwRetSize) {
1168 ret = MCIERR_PARAM_OVERFLOW;
1170 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1173 lpParms->lpstrReturn[0] = 0;
1179 /**************************************************************************
1180 * MCIWAVE_DriverProc [sample driver]
1182 LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1183 DWORD dwParam1, DWORD dwParam2)
1185 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1186 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1189 case DRV_LOAD: return 1;
1190 case DRV_FREE: return 1;
1191 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1192 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1193 case DRV_ENABLE: return 1;
1194 case DRV_DISABLE: return 1;
1195 case DRV_QUERYCONFIGURE: return 1;
1196 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1197 case DRV_INSTALL: return DRVCNF_RESTART;
1198 case DRV_REMOVE: return DRVCNF_RESTART;
1199 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
1200 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1201 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1202 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1203 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1204 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1205 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1206 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1207 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1208 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1209 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1210 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
1211 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1212 /* commands that should be supported */
1228 FIXME("Unsupported yet command [%lu]\n", wMsg);
1231 TRACE("Unsupported command [%lu]\n", wMsg);
1235 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1238 FIXME("is probably wrong msg [%lu]\n", wMsg);
1239 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1241 return MCIERR_UNRECOGNIZED_COMMAND;