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
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(mciwave)
24 int nUseCount; /* Incremented for each shared open */
25 BOOL fShareable; /* TRUE if first open was shareable */
26 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
27 HMMIO hFile; /* mmio file handle open as Element */
28 MCI_WAVE_OPEN_PARMSA openParms;
29 LPWAVEFORMATEX lpWaveFormat;
30 BOOL fInput; /* FALSE = Output, TRUE = Input */
31 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
32 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
33 DWORD dwFileOffset; /* Offset of chunk in mmio file */
34 DWORD dwLength; /* number of bytes in chunk for playing */
35 DWORD dwPosition; /* position in bytes in chunk for playing */
36 HANDLE hEvent; /* for synchronization */
37 DWORD dwEventCount; /* for synchronization */
40 /* ===================================================================
41 * ===================================================================
42 * FIXME: should be using the new mmThreadXXXX functions from WINMM
44 * it would require to add a wine internal flag to mmThreadCreate
45 * in order to pass a 32 bit function instead of a 16 bit one
46 * ===================================================================
47 * =================================================================== */
57 /**************************************************************************
58 * MCI_SCAStarter [internal]
60 static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
62 struct SCA* sca = (struct SCA*)arg;
65 TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
66 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
67 ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
68 TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
69 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
70 if (sca->allocatedCopy)
71 HeapFree(GetProcessHeap(), 0, (LPVOID)sca->dwParam2);
72 HeapFree(GetProcessHeap(), 0, sca);
74 WARN("Should not happen ? what's wrong \n");
75 /* should not go after this point */
79 /**************************************************************************
80 * MCI_SendCommandAsync [internal]
82 static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
83 DWORD dwParam2, UINT size)
85 struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA));
88 return MCIERR_OUT_OF_MEMORY;
92 sca->dwParam1 = dwParam1;
95 sca->dwParam2 = (DWORD)HeapAlloc(GetProcessHeap(), 0, size);
96 if (sca->dwParam2 == 0) {
97 HeapFree(GetProcessHeap(), 0, sca);
98 return MCIERR_OUT_OF_MEMORY;
100 sca->allocatedCopy = TRUE;
101 /* copy structure passed by program in dwParam2 to be sure
102 * we can still use it whatever the program does
104 memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
106 sca->dwParam2 = dwParam2;
107 sca->allocatedCopy = FALSE;
110 if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
111 WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
112 return MCI_SCAStarter(&sca);
117 /*======================================================================*
118 * MCI WAVE implemantation *
119 *======================================================================*/
121 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
123 /**************************************************************************
124 * MCIWAVE_drvOpen [internal]
126 static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
128 WINE_MCIWAVE* wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
133 wmw->wDevID = modp->wDeviceID;
134 mciSetDriverData(wmw->wDevID, (DWORD)wmw);
135 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
136 modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
137 return modp->wDeviceID;
140 /**************************************************************************
141 * MCIWAVE_drvClose [internal]
143 static DWORD WAVE_drvClose(DWORD dwDevID)
145 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
148 HeapFree(GetProcessHeap(), 0, wmw);
149 mciSetDriverData(dwDevID, 0);
155 /**************************************************************************
156 * WAVE_mciGetOpenDev [internal]
158 static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
160 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
162 if (wmw == NULL || wmw->nUseCount == 0) {
163 WARN("Invalid wDevID=%u\n", wDevID);
169 /**************************************************************************
170 * WAVE_ConvertByteToTimeFormat [internal]
172 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
176 switch (wmw->dwMciTimeFormat) {
177 case MCI_FORMAT_MILLISECONDS:
178 ret = (val * 1000) / wmw->lpWaveFormat->nAvgBytesPerSec;
180 case MCI_FORMAT_BYTES:
183 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
184 ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
187 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
189 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
194 /**************************************************************************
195 * WAVE_ConvertTimeFormatToByte [internal]
197 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
201 switch (wmw->dwMciTimeFormat) {
202 case MCI_FORMAT_MILLISECONDS:
203 ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
205 case MCI_FORMAT_BYTES:
208 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
209 ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
212 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
214 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
218 /**************************************************************************
219 * WAVE_mciReadFmt [internal]
221 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
226 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
227 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
228 return MCIERR_INVALID_FILE;
229 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
230 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
232 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
233 r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
234 if (r < sizeof(WAVEFORMAT))
235 return MCIERR_INVALID_FILE;
237 TRACE("wFormatTag=%04X !\n", wmw->lpWaveFormat->wFormatTag);
238 TRACE("nChannels=%d \n", wmw->lpWaveFormat->nChannels);
239 TRACE("nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nSamplesPerSec);
240 TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
241 TRACE("nBlockAlign=%d \n", wmw->lpWaveFormat->nBlockAlign);
242 TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
243 if (r >= (long)sizeof(WAVEFORMATEX))
244 TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
246 mmioAscend(wmw->hFile, &mmckInfo, 0);
247 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
248 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
249 TRACE("can't find data chunk\n");
250 return MCIERR_INVALID_FILE;
252 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
253 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
254 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
255 wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
256 wmw->dwLength = mmckInfo.cksize;
257 wmw->dwFileOffset = mmckInfo.dwDataOffset;
261 /**************************************************************************
262 * WAVE_mciOpen [internal]
264 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
268 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
270 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
271 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
272 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
274 if (dwFlags & MCI_OPEN_SHAREABLE)
275 return MCIERR_HARDWARE;
277 if (wmw->nUseCount > 0) {
278 /* The driver is already opened on this channel
279 * Wave driver cannot be shared
281 return MCIERR_DEVICE_OPEN;
285 dwDeviceID = lpOpenParms->wDeviceID;
290 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
292 if (dwFlags & MCI_OPEN_ELEMENT) {
293 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
294 /* could it be that (DWORD)lpOpenParms->lpstrElementName
295 * contains the hFile value ?
297 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
299 LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
301 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
302 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
303 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
304 wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL,
305 MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
306 if (wmw->hFile == 0) {
307 WARN("can't find file='%s' !\n", lpstrElementName);
308 dwRet = MCIERR_FILE_NOT_FOUND;
315 TRACE("hFile=%u\n", wmw->hFile);
317 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
318 wmw->wNotifyDeviceID = dwDeviceID;
319 wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
321 if (dwRet == 0 && wmw->hFile != 0) {
324 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
325 dwRet = MCIERR_INVALID_FILE;
327 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
328 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
329 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
330 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
331 dwRet = MCIERR_INVALID_FILE;
333 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
340 if (wmw->lpWaveFormat) {
341 switch (wmw->lpWaveFormat->wFormatTag) {
342 case WAVE_FORMAT_PCM:
343 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
344 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
345 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
346 wmw->lpWaveFormat->nAvgBytesPerSec,
347 wmw->lpWaveFormat->nSamplesPerSec *
348 wmw->lpWaveFormat->nBlockAlign);
349 wmw->lpWaveFormat->nAvgBytesPerSec =
350 wmw->lpWaveFormat->nSamplesPerSec *
351 wmw->lpWaveFormat->nBlockAlign;
358 wmw->dwStatus = MCI_MODE_STOP;
362 mmioClose(wmw->hFile, 0);
368 /**************************************************************************
369 * WAVE_mciCue [internal]
371 static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
376 This routine is far from complete. At the moment only a check is done on the
377 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
380 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
385 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
387 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
389 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
391 /* always close elements ? */
392 if (wmw->hFile != 0) {
393 mmioClose(wmw->hFile, 0);
397 dwRet = MMSYSERR_NOERROR; /* assume success */
399 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
400 dwRet = waveOutClose(wmw->hWave);
401 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
403 } else if (wmw->fInput) {
404 dwRet = waveInClose(wmw->hWave);
405 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
409 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
412 /**************************************************************************
413 * WAVE_mciStop [internal]
415 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
418 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
420 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
422 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
424 /* wait for playback thread (if any) to exit before processing further */
425 switch (wmw->dwStatus) {
428 case MCI_MODE_RECORD:
430 int oldStat = wmw->dwStatus;
431 wmw->dwStatus = MCI_MODE_NOT_READY;
432 if (oldStat == MCI_MODE_PAUSE)
433 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
435 while (wmw->dwStatus != MCI_MODE_STOP)
443 wmw->dwStatus = MCI_MODE_STOP;
445 if ((dwFlags & MCI_NOTIFY) && lpParms) {
446 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
447 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
453 /**************************************************************************
454 * WAVE_mciClose [internal]
456 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
459 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
461 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
463 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
465 if (wmw->dwStatus != MCI_MODE_STOP) {
466 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
471 if (wmw->nUseCount == 0) {
472 if (wmw->hFile != 0) {
473 mmioClose(wmw->hFile, 0);
478 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
479 wmw->lpWaveFormat = NULL;
481 if ((dwFlags & MCI_NOTIFY) && lpParms) {
482 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
483 wmw->wNotifyDeviceID,
484 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
490 /**************************************************************************
491 * WAVE_mciPlayCallback [internal]
493 static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
495 DWORD dwParam1, DWORD dwParam2)
497 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
504 InterlockedIncrement(&wmw->dwEventCount);
505 TRACE("Returning waveHdr=%lx\n", dwParam1);
506 SetEvent(wmw->hEvent);
509 ERR("Unknown uMsg=%d\n", uMsg);
513 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
516 ResetEvent(wmw->hEvent);
517 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
520 InterlockedIncrement(&wmw->dwEventCount);
522 WaitForSingleObject(wmw->hEvent, INFINITE);
526 /**************************************************************************
527 * WAVE_mciPlay [internal]
529 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
532 LONG bufsize, count, left;
534 LPWAVEHDR waveHdr = NULL;
535 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
538 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
540 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
541 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
544 WARN("cannot play on input device\n");
545 return MCIERR_NONAPPLICABLE_FUNCTION;
548 if (wmw->hFile == 0) {
549 WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
550 return MCIERR_FILE_NOT_FOUND;
553 if (wmw->dwStatus == MCI_MODE_PAUSE) {
554 /* FIXME: parameters (start/end) in lpParams may not be used */
555 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
558 /** This function will be called again by a thread when async is used.
559 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
560 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
562 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
563 return MCIERR_INTERNAL;
566 wmw->dwStatus = MCI_MODE_PLAY;
568 if (!(dwFlags & MCI_WAIT)) {
569 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
570 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
574 if (lpParms && (dwFlags & MCI_FROM)) {
575 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
577 if (lpParms && (dwFlags & MCI_TO)) {
578 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
581 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
583 if (end <= wmw->dwPosition)
586 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
587 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
589 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
590 wmw->dwLength = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwLength);
591 /* go back to begining of chunk plus the requested position */
592 /* FIXME: I'm not sure this is correct, notably because some data linked to
593 * the decompression state machine will not be correcly initialized.
594 * try it this way (other way would be to decompress from 0 up to dwPosition
595 * and to start sending to hWave when dwPosition is reached)
597 mmioSeek(wmw->hFile, wmw->dwFileOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
599 /* By default the device will be opened for output, the MCI_CUE function is there to
600 * change from output to input and back
602 /* FIXME: how to choose between several output channels ? here mapper is forced */
603 dwRet = waveOutOpen(&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
604 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
607 TRACE("Can't open low level audio device %ld\n", dwRet);
608 dwRet = MCIERR_DEVICE_OPEN;
613 /* make it so that 3 buffers per second are needed */
614 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
616 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
617 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
618 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
619 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
620 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
621 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
622 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
623 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
624 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
625 dwRet = MCIERR_INTERNAL;
630 left = MIN(wmw->dwLength, end - wmw->dwPosition);
631 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
632 wmw->dwEventCount = 1L; /* for first buffer */
634 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
636 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
637 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
638 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, MIN(bufsize, left));
639 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
642 /* count is always <= bufsize, so this is correct regarding the
643 * waveOutPrepareHeader function
645 waveHdr[whidx].dwBufferLength = count;
646 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
647 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
648 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
649 waveHdr[whidx].dwBytesRecorded);
650 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
652 wmw->dwPosition += count;
653 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
655 WAVE_mciPlayWaitDone(wmw);
659 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
661 /* just to get rid of some race conditions between play, stop and pause */
662 waveOutReset(wmw->hWave);
664 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
665 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
670 HeapFree(GetProcessHeap(), 0, waveHdr);
673 waveOutClose(wmw->hWave);
676 CloseHandle(wmw->hEvent);
678 if (lpParms && (dwFlags & MCI_NOTIFY)) {
679 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
680 wmw->wNotifyDeviceID,
681 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
684 wmw->dwStatus = MCI_MODE_STOP;
689 /**************************************************************************
690 * WAVE_mciRecord [internal]
692 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
698 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
700 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
702 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
703 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
706 WARN("cannot record on output device\n");
707 return MCIERR_NONAPPLICABLE_FUNCTION;
710 if (wmw->hFile == 0) {
711 WARN("can't find file='%s' !\n",
712 wmw->openParms.lpstrElementName);
713 return MCIERR_FILE_NOT_FOUND;
715 start = 1; end = 99999;
716 if (dwFlags & MCI_FROM) {
717 start = lpParms->dwFrom;
718 TRACE("MCI_FROM=%d \n", start);
720 if (dwFlags & MCI_TO) {
722 TRACE("MCI_TO=%d \n", end);
725 waveHdr.lpData = HeapAlloc(GetProcessHeap(), 0, bufsize);
726 waveHdr.dwBufferLength = bufsize;
728 waveHdr.dwFlags = 0L;
729 waveHdr.dwLoops = 0L;
730 dwRet = waveInPrepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
732 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
733 waveHdr.dwBytesRecorded = 0;
734 dwRet = waveInStart(wmw->hWave);
735 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
736 &waveHdr, waveHdr.dwBytesRecorded);
737 if (waveHdr.dwBytesRecorded == 0) break;
739 dwRet = waveInUnprepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
740 HeapFree(GetProcessHeap(), 0, waveHdr.lpData);
742 if (dwFlags & MCI_NOTIFY) {
743 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
744 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
749 /**************************************************************************
750 * WAVE_mciPause [internal]
752 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
755 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
757 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
759 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
760 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
762 if (wmw->dwStatus == MCI_MODE_PLAY) {
763 wmw->dwStatus = MCI_MODE_PAUSE;
766 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
767 else dwRet = waveOutPause(wmw->hWave);
769 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
772 /**************************************************************************
773 * WAVE_mciResume [internal]
775 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
777 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
780 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
782 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
784 if (wmw->dwStatus == MCI_MODE_PAUSE) {
785 wmw->dwStatus = MCI_MODE_PLAY;
788 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
789 else dwRet = waveOutRestart(wmw->hWave);
790 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
793 /**************************************************************************
794 * WAVE_mciSeek [internal]
796 static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
799 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
801 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
803 if (lpParms == NULL) {
804 ret = MCIERR_NULL_PARAMETER_BLOCK;
805 } else if (wmw == NULL) {
806 ret = MCIERR_INVALID_DEVICE_ID;
808 WAVE_mciStop(wDevID, MCI_WAIT, 0);
810 if (dwFlags & MCI_SEEK_TO_START) {
812 } else if (dwFlags & MCI_SEEK_TO_END) {
813 wmw->dwPosition = wmw->dwLength;
814 } else if (dwFlags & MCI_TO) {
815 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
817 WARN("dwFlag doesn't tell where to seek to...\n");
818 return MCIERR_MISSING_PARAMETER;
821 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
823 if (dwFlags & MCI_NOTIFY) {
824 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
825 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
831 /**************************************************************************
832 * WAVE_mciSet [internal]
834 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
836 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
838 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
840 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
841 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
843 if (dwFlags & MCI_SET_TIME_FORMAT) {
844 switch (lpParms->dwTimeFormat) {
845 case MCI_FORMAT_MILLISECONDS:
846 TRACE("MCI_FORMAT_MILLISECONDS !\n");
847 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
849 case MCI_FORMAT_BYTES:
850 TRACE("MCI_FORMAT_BYTES !\n");
851 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
853 case MCI_FORMAT_SAMPLES:
854 TRACE("MCI_FORMAT_SAMPLES !\n");
855 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
858 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
859 return MCIERR_BAD_TIME_FORMAT;
862 if (dwFlags & MCI_SET_VIDEO) {
863 TRACE("No support for video !\n");
864 return MCIERR_UNSUPPORTED_FUNCTION;
866 if (dwFlags & MCI_SET_DOOR_OPEN) {
867 TRACE("No support for door open !\n");
868 return MCIERR_UNSUPPORTED_FUNCTION;
870 if (dwFlags & MCI_SET_DOOR_CLOSED) {
871 TRACE("No support for door close !\n");
872 return MCIERR_UNSUPPORTED_FUNCTION;
874 if (dwFlags & MCI_SET_AUDIO) {
875 if (dwFlags & MCI_SET_ON) {
876 TRACE("MCI_SET_ON audio !\n");
877 } else if (dwFlags & MCI_SET_OFF) {
878 TRACE("MCI_SET_OFF audio !\n");
880 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
881 return MCIERR_BAD_INTEGER;
884 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
885 TRACE("MCI_SET_AUDIO_ALL !\n");
886 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
887 TRACE("MCI_SET_AUDIO_LEFT !\n");
888 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
889 TRACE("MCI_SET_AUDIO_RIGHT !\n");
891 if (dwFlags & MCI_WAVE_INPUT)
892 TRACE("MCI_WAVE_INPUT !\n");
893 if (dwFlags & MCI_WAVE_OUTPUT)
894 TRACE("MCI_WAVE_OUTPUT !\n");
895 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
896 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
897 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
898 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
899 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
900 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
901 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
902 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
903 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
904 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
905 if (dwFlags & MCI_WAVE_SET_CHANNELS)
906 TRACE("MCI_WAVE_SET_CHANNELS !\n");
907 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
908 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
909 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
910 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
914 /**************************************************************************
915 * WAVE_mciStatus [internal]
917 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
919 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
922 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
923 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
924 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
926 if (dwFlags & MCI_STATUS_ITEM) {
927 switch (lpParms->dwItem) {
928 case MCI_STATUS_CURRENT_TRACK:
929 lpParms->dwReturn = 1;
930 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
932 case MCI_STATUS_LENGTH:
934 lpParms->dwReturn = 0;
935 return MCIERR_UNSUPPORTED_FUNCTION;
937 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
938 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
939 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
941 case MCI_STATUS_MODE:
942 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
943 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
944 ret = MCI_RESOURCE_RETURNED;
946 case MCI_STATUS_MEDIA_PRESENT:
947 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
948 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
949 ret = MCI_RESOURCE_RETURNED;
951 case MCI_STATUS_NUMBER_OF_TRACKS:
952 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
953 lpParms->dwReturn = 1;
954 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
956 case MCI_STATUS_POSITION:
958 lpParms->dwReturn = 0;
959 return MCIERR_UNSUPPORTED_FUNCTION;
961 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
962 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
963 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
965 TRACE("MCI_STATUS_POSITION %s => %lu\n",
966 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
968 case MCI_STATUS_READY:
969 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
970 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
971 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
972 ret = MCI_RESOURCE_RETURNED;
974 case MCI_STATUS_TIME_FORMAT:
975 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
976 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
977 ret = MCI_RESOURCE_RETURNED;
980 TRACE("MCI_WAVE_INPUT !\n");
981 lpParms->dwReturn = 0;
982 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
984 case MCI_WAVE_OUTPUT:
985 TRACE("MCI_WAVE_OUTPUT !\n");
988 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
989 lpParms->dwReturn = id;
991 lpParms->dwReturn = 0;
992 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
996 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
998 lpParms->dwReturn = 0;
999 return MCIERR_UNSUPPORTED_FUNCTION;
1001 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1002 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1004 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1006 lpParms->dwReturn = 0;
1007 return MCIERR_UNSUPPORTED_FUNCTION;
1009 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1010 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1012 case MCI_WAVE_STATUS_BLOCKALIGN:
1014 lpParms->dwReturn = 0;
1015 return MCIERR_UNSUPPORTED_FUNCTION;
1017 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1018 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1020 case MCI_WAVE_STATUS_CHANNELS:
1022 lpParms->dwReturn = 0;
1023 return MCIERR_UNSUPPORTED_FUNCTION;
1025 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1026 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1028 case MCI_WAVE_STATUS_FORMATTAG:
1030 lpParms->dwReturn = 0;
1031 return MCIERR_UNSUPPORTED_FUNCTION;
1033 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1034 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1036 case MCI_WAVE_STATUS_LEVEL:
1037 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1038 lpParms->dwReturn = 0xAAAA5555;
1040 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1042 lpParms->dwReturn = 0;
1043 return MCIERR_UNSUPPORTED_FUNCTION;
1045 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1046 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1049 WARN("unknown command %08lX !\n", lpParms->dwItem);
1050 return MCIERR_UNRECOGNIZED_COMMAND;
1053 if (dwFlags & MCI_NOTIFY) {
1054 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
1055 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
1060 /**************************************************************************
1061 * WAVE_mciGetDevCaps [internal]
1063 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1064 LPMCI_GETDEVCAPS_PARMS lpParms)
1066 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1069 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1071 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1072 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1074 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1075 switch(lpParms->dwItem) {
1076 case MCI_GETDEVCAPS_DEVICE_TYPE:
1077 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1078 ret = MCI_RESOURCE_RETURNED;
1080 case MCI_GETDEVCAPS_HAS_AUDIO:
1081 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1082 ret = MCI_RESOURCE_RETURNED;
1084 case MCI_GETDEVCAPS_HAS_VIDEO:
1085 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1086 ret = MCI_RESOURCE_RETURNED;
1088 case MCI_GETDEVCAPS_USES_FILES:
1089 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1090 ret = MCI_RESOURCE_RETURNED;
1092 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1093 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1094 ret = MCI_RESOURCE_RETURNED;
1096 case MCI_GETDEVCAPS_CAN_RECORD:
1097 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1098 ret = MCI_RESOURCE_RETURNED;
1100 case MCI_GETDEVCAPS_CAN_EJECT:
1101 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1102 ret = MCI_RESOURCE_RETURNED;
1104 case MCI_GETDEVCAPS_CAN_PLAY:
1105 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1106 ret = MCI_RESOURCE_RETURNED;
1108 case MCI_GETDEVCAPS_CAN_SAVE:
1109 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1110 ret = MCI_RESOURCE_RETURNED;
1112 case MCI_WAVE_GETDEVCAPS_INPUTS:
1113 lpParms->dwReturn = 1;
1115 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1116 lpParms->dwReturn = 1;
1119 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1120 return MCIERR_UNRECOGNIZED_COMMAND;
1123 WARN("No GetDevCaps-Item !\n");
1124 return MCIERR_UNRECOGNIZED_COMMAND;
1129 /**************************************************************************
1130 * WAVE_mciInfo [internal]
1132 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1136 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1138 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1140 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1141 ret = MCIERR_NULL_PARAMETER_BLOCK;
1142 } else if (wmw == NULL) {
1143 ret = MCIERR_INVALID_DEVICE_ID;
1145 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1147 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1148 case MCI_INFO_PRODUCT:
1149 str = "Wine's audio player";
1152 str = wmw->openParms.lpstrElementName;
1154 case MCI_WAVE_INPUT:
1155 str = "Wine Wave In";
1157 case MCI_WAVE_OUTPUT:
1158 str = "Wine Wave Out";
1161 WARN("Don't know this info command (%lu)\n", dwFlags);
1162 ret = MCIERR_UNRECOGNIZED_COMMAND;
1166 if (strlen(str) + 1 > lpParms->dwRetSize) {
1167 ret = MCIERR_PARAM_OVERFLOW;
1169 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1172 lpParms->lpstrReturn[0] = 0;
1178 /**************************************************************************
1179 * MCIWAVE_DriverProc [sample driver]
1181 LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1182 DWORD dwParam1, DWORD dwParam2)
1184 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1185 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1188 case DRV_LOAD: return 1;
1189 case DRV_FREE: return 1;
1190 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1191 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1192 case DRV_ENABLE: return 1;
1193 case DRV_DISABLE: return 1;
1194 case DRV_QUERYCONFIGURE: return 1;
1195 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1196 case DRV_INSTALL: return DRVCNF_RESTART;
1197 case DRV_REMOVE: return DRVCNF_RESTART;
1198 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
1199 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1200 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1201 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1202 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1203 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1204 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1205 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1206 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1207 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1208 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1209 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
1210 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1211 /* commands that should be supported */
1227 FIXME("Unsupported yet command [%lu]\n", wMsg);
1230 TRACE("Unsupported command [%lu]\n", wMsg);
1234 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1237 FIXME("is probably wrong msg [%lu]\n", wMsg);
1238 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1240 return MCIERR_UNRECOGNIZED_COMMAND;