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
11 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
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 HANDLE hCallback
; /* Callback handle for pending notification */
29 HMMIO hFile
; /* mmio file handle open as Element */
30 MCI_WAVE_OPEN_PARMSA openParms
;
31 WAVEOPENDESC waveDesc
;
32 PCMWAVEFORMAT WaveFormat
;
34 BOOL fInput
; /* FALSE = Output, TRUE = Input */
35 WORD dwStatus
; /* one from MCI_MODE_xxxx */
36 DWORD dwMciTimeFormat
;/* One of the supported MCI_FORMAT_xxxx */
37 DWORD dwFileOffset
; /* Offset of chunk in mmio file */
38 DWORD dwLength
; /* number of bytes in chunk for playing */
39 DWORD dwPosition
; /* position in bytes in chunk for playing */
42 /*======================================================================*
43 * MCI WAVE implemantation *
44 *======================================================================*/
46 static DWORD
WAVE_mciResume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
);
48 /**************************************************************************
49 * MCIWAVE_drvOpen [internal]
51 static DWORD
WAVE_drvOpen(LPSTR str
, LPMCI_OPEN_DRIVER_PARMSA modp
)
53 WINE_MCIWAVE
* wmw
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MCIWAVE
));
58 wmw
->wDevID
= modp
->wDeviceID
;
59 mciSetDriverData(wmw
->wDevID
, (DWORD
)wmw
);
60 modp
->wCustomCommandTable
= MCI_NO_COMMAND_TABLE
;
61 modp
->wType
= MCI_DEVTYPE_WAVEFORM_AUDIO
;
62 return modp
->wDeviceID
;
65 /**************************************************************************
66 * MCIWAVE_drvClose [internal]
68 static DWORD
WAVE_drvClose(DWORD dwDevID
)
70 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(dwDevID
);
73 HeapFree(GetProcessHeap(), 0, wmw
);
74 mciSetDriverData(dwDevID
, 0);
80 /**************************************************************************
81 * WAVE_mciGetOpenDev [internal]
83 static WINE_MCIWAVE
* WAVE_mciGetOpenDev(UINT wDevID
)
85 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(wDevID
);
87 if (wmw
== NULL
|| wmw
->nUseCount
== 0) {
88 WARN("Invalid wDevID=%u\n", wDevID
);
94 /**************************************************************************
95 * WAVE_ConvertByteToTimeFormat [internal]
97 static DWORD
WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE
* wmw
, DWORD val
, LPDWORD lpRet
)
101 switch (wmw
->dwMciTimeFormat
) {
102 case MCI_FORMAT_MILLISECONDS
:
103 ret
= (val
* 1000) / wmw
->WaveFormat
.wf
.nAvgBytesPerSec
;
105 case MCI_FORMAT_BYTES
:
108 case MCI_FORMAT_SAMPLES
: /* FIXME: is this correct ? */
109 ret
= (val
* 8) / wmw
->WaveFormat
.wBitsPerSample
;
112 WARN("Bad time format %lu!\n", wmw
->dwMciTimeFormat
);
114 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val
, val
, wmw
->dwMciTimeFormat
, ret
);
119 /**************************************************************************
120 * WAVE_ConvertTimeFormatToByte [internal]
122 static DWORD
WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE
* wmw
, DWORD val
)
126 switch (wmw
->dwMciTimeFormat
) {
127 case MCI_FORMAT_MILLISECONDS
:
128 ret
= (val
* wmw
->WaveFormat
.wf
.nAvgBytesPerSec
) / 1000;
130 case MCI_FORMAT_BYTES
:
133 case MCI_FORMAT_SAMPLES
: /* FIXME: is this correct ? */
134 ret
= (val
* wmw
->WaveFormat
.wBitsPerSample
) / 8;
137 WARN("Bad time format %lu!\n", wmw
->dwMciTimeFormat
);
139 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val
, val
, wmw
->dwMciTimeFormat
, ret
);
143 /**************************************************************************
144 * WAVE_mciReadFmt [internal]
146 static DWORD
WAVE_mciReadFmt(WINE_MCIWAVE
* wmw
, MMCKINFO
* pckMainRIFF
)
150 mmckInfo
.ckid
= mmioFOURCC('f', 'm', 't', ' ');
151 if (mmioDescend(wmw
->hFile
, &mmckInfo
, pckMainRIFF
, MMIO_FINDCHUNK
) != 0)
152 return MCIERR_INVALID_FILE
;
153 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
154 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
, mmckInfo
.cksize
);
155 if (mmioRead(wmw
->hFile
, (HPSTR
)&wmw
->WaveFormat
,
156 (long)sizeof(PCMWAVEFORMAT
)) != (long)sizeof(PCMWAVEFORMAT
))
157 return MCIERR_INVALID_FILE
;
159 TRACE("wFormatTag=%04X !\n", wmw
->WaveFormat
.wf
.wFormatTag
);
160 TRACE("nChannels=%d \n", wmw
->WaveFormat
.wf
.nChannels
);
161 TRACE("nSamplesPerSec=%ld\n", wmw
->WaveFormat
.wf
.nSamplesPerSec
);
162 TRACE("nAvgBytesPerSec=%ld\n", wmw
->WaveFormat
.wf
.nAvgBytesPerSec
);
163 TRACE("nBlockAlign=%d \n", wmw
->WaveFormat
.wf
.nBlockAlign
);
164 TRACE("wBitsPerSample=%u !\n", wmw
->WaveFormat
.wBitsPerSample
);
166 mmckInfo
.ckid
= mmioFOURCC('d', 'a', 't', 'a');
167 mmioSeek(wmw
->hFile
, mmckInfo
.dwDataOffset
+ ((mmckInfo
.cksize
+ 1) & ~1), SEEK_SET
);
168 if (mmioDescend(wmw
->hFile
, &mmckInfo
, pckMainRIFF
, MMIO_FINDCHUNK
) != 0) {
169 TRACE("can't find data chunk\n");
170 return MCIERR_INVALID_FILE
;
172 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
173 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
, mmckInfo
.cksize
);
174 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
175 wmw
->WaveFormat
.wf
.nChannels
, wmw
->WaveFormat
.wf
.nSamplesPerSec
);
176 wmw
->dwLength
= mmckInfo
.cksize
;
177 wmw
->dwFileOffset
= mmioSeek(wmw
->hFile
, 0, SEEK_CUR
); /* >= 0 */
181 /**************************************************************************
182 * WAVE_mciOpen [internal]
184 static DWORD
WAVE_mciOpen(UINT wDevID
, DWORD dwFlags
, LPMCI_WAVE_OPEN_PARMSA lpOpenParms
)
188 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(wDevID
);
190 TRACE("(%04X, %08lX, %p)\n", wDevID
, dwFlags
, lpOpenParms
);
191 if (lpOpenParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
192 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
194 if (dwFlags
& MCI_OPEN_SHAREABLE
)
195 return MCIERR_HARDWARE
;
197 if (wmw
->nUseCount
> 0) {
198 /* The driver is already opened on this channel
199 * Wave driver cannot be shared
201 return MCIERR_DEVICE_OPEN
;
205 dwDeviceID
= lpOpenParms
->wDeviceID
;
210 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID
, dwDeviceID
);
212 if (dwFlags
& MCI_OPEN_ELEMENT
) {
213 if (dwFlags
& MCI_OPEN_ELEMENT_ID
) {
214 /* could it be that (DWORD)lpOpenParms->lpstrElementName
215 * contains the hFile value ?
217 dwRet
= MCIERR_UNRECOGNIZED_COMMAND
;
219 LPCSTR lpstrElementName
= lpOpenParms
->lpstrElementName
;
221 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
222 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName
);
223 if (lpstrElementName
&& (strlen(lpstrElementName
) > 0)) {
224 wmw
->hFile
= mmioOpenA((LPSTR
)lpstrElementName
, NULL
,
225 MMIO_ALLOCBUF
| MMIO_READ
| MMIO_DENYWRITE
);
226 if (wmw
->hFile
== 0) {
227 WARN("can't find file='%s' !\n", lpstrElementName
);
228 dwRet
= MCIERR_FILE_NOT_FOUND
;
235 TRACE("hFile=%u\n", wmw
->hFile
);
237 memcpy(&wmw
->openParms
, lpOpenParms
, sizeof(MCI_WAVE_OPEN_PARMSA
));
238 wmw
->wNotifyDeviceID
= dwDeviceID
;
239 wmw
->dwStatus
= MCI_MODE_NOT_READY
; /* while loading file contents */
241 wmw
->waveDesc
.hWave
= 0;
243 if (dwRet
== 0 && wmw
->hFile
!= 0) {
246 if (mmioDescend(wmw
->hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
247 dwRet
= MCIERR_INVALID_FILE
;
249 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
250 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
, ckMainRIFF
.cksize
);
251 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
252 (ckMainRIFF
.fccType
!= mmioFOURCC('W', 'A', 'V', 'E'))) {
253 dwRet
= MCIERR_INVALID_FILE
;
255 dwRet
= WAVE_mciReadFmt(wmw
, &ckMainRIFF
);
262 wmw
->WaveFormat
.wf
.nAvgBytesPerSec
=
263 wmw
->WaveFormat
.wf
.nSamplesPerSec
* wmw
->WaveFormat
.wf
.nBlockAlign
;
264 wmw
->waveDesc
.lpFormat
= (LPWAVEFORMAT
)&wmw
->WaveFormat
;
267 wmw
->dwStatus
= MCI_MODE_STOP
;
271 mmioClose(wmw
->hFile
, 0);
277 /**************************************************************************
278 * WAVE_mciCue [internal]
280 static DWORD
WAVE_mciCue(UINT wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
285 This routine is far from complete. At the moment only a check is done on the
286 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
289 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
294 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
296 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID
, dwParam
, lpParms
);
298 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
300 /* always close elements ? */
301 if (wmw
->hFile
!= 0) {
302 mmioClose(wmw
->hFile
, 0);
306 dwRet
= MMSYSERR_NOERROR
; /* assume success */
308 if ((dwParam
& MCI_WAVE_INPUT
) && !wmw
->fInput
) {
309 dwRet
= waveOutClose(wmw
->hWave
);
310 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
312 } else if (wmw
->fInput
) {
313 dwRet
= waveInClose(wmw
->hWave
);
314 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
318 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
321 /**************************************************************************
322 * WAVE_mciStop [internal]
324 static DWORD
WAVE_mciStop(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
327 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
329 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
331 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
332 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
334 wmw
->dwStatus
= MCI_MODE_STOP
;
336 TRACE("wmw->dwStatus=%d\n", wmw
->dwStatus
);
339 dwRet
= waveInReset(wmw
->hWave
);
341 dwRet
= waveOutReset(wmw
->hWave
);
343 if (dwFlags
& MCI_NOTIFY
) {
344 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
345 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
346 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
349 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
352 /**************************************************************************
353 * WAVE_mciClose [internal]
355 static DWORD
WAVE_mciClose(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
358 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
360 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
362 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
364 if (wmw
->dwStatus
!= MCI_MODE_STOP
) {
365 dwRet
= WAVE_mciStop(wDevID
, MCI_WAIT
, lpParms
);
370 if (wmw
->nUseCount
== 0) {
372 if (wmw
->hFile
!= 0) {
373 mmioClose(wmw
->hFile
, 0);
376 mmRet
= (wmw
->fInput
) ? waveInClose(wmw
->hWave
) : waveOutClose(wmw
->hWave
);
378 if (mmRet
!= MMSYSERR_NOERROR
) dwRet
= MCIERR_INTERNAL
;
381 if ((dwFlags
& MCI_NOTIFY
) && lpParms
) {
382 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
383 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
384 wmw
->wNotifyDeviceID
,
385 (dwRet
== 0) ? MCI_NOTIFY_SUCCESSFUL
: MCI_NOTIFY_FAILURE
);
390 /**************************************************************************
391 * WAVE_mciPlay [internal]
393 static DWORD
WAVE_mciPlay(UINT wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
399 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
401 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
403 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
404 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
407 WARN("cannot play on input device\n");
408 return MCIERR_NONAPPLICABLE_FUNCTION
;
411 if (wmw
->hFile
== 0) {
412 WARN("Can't play: no file='%s' !\n", wmw
->openParms
.lpstrElementName
);
413 return MCIERR_FILE_NOT_FOUND
;
416 if (!(dwFlags
& MCI_WAIT
)) {
417 return MCI_SendCommandAsync(wmw
->wNotifyDeviceID
, MCI_PLAY
, dwFlags
,
418 (DWORD
)lpParms
, sizeof(MCI_PLAY_PARMS
));
421 if (wmw
->dwStatus
!= MCI_MODE_STOP
) {
422 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
423 /* FIXME: parameters (start/end) in lpParams may not be used */
424 return WAVE_mciResume(wDevID
, dwFlags
, (LPMCI_GENERIC_PARMS
)lpParms
);
426 return MCIERR_INTERNAL
;
430 if (lpParms
&& (dwFlags
& MCI_FROM
)) {
431 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwFrom
);
433 if (lpParms
&& (dwFlags
& MCI_TO
)) {
434 end
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
437 TRACE("Playing from byte=%lu to byte=%lu\n", wmw
->dwPosition
, end
);
439 /* go back to begining of chunk */
440 mmioSeek(wmw
->hFile
, wmw
->dwFileOffset
, SEEK_SET
); /* >= 0 */
442 /* By default the device will be opened for output, the MCI_CUE function is there to
443 * change from output to input and back
445 /* FIXME: how to choose between several output channels ? here 0 is forced */
446 /* I shall rather use WAVE_MAPPER */
447 dwRet
= waveOutOpen(&wmw
->hWave
, 0, (LPWAVEFORMATEX
)&wmw
->WaveFormat
, 0L, 0L, CALLBACK_NULL
);
449 TRACE("Can't open low level audio device %ld\n", dwRet
);
450 return MCIERR_DEVICE_OPEN
;
453 /* at 22050 bytes per sec => 30 ms by block */
455 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
456 wmw
->WaveHdr
.lpData
= (LPSTR
)GlobalLock16(hData
);
458 wmw
->dwStatus
= MCI_MODE_PLAY
;
460 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
461 /* FIXME: use several WaveHdr for smoother playback */
462 /* FIXME: use only regular MMSYS functions, not calling directly the driver */
463 while (wmw
->dwStatus
!= MCI_MODE_STOP
) {
464 wmw
->WaveHdr
.dwUser
= 0L;
465 wmw
->WaveHdr
.dwFlags
= 0L;
466 wmw
->WaveHdr
.dwLoops
= 0L;
467 count
= mmioRead(wmw
->hFile
, wmw
->WaveHdr
.lpData
, bufsize
);
468 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize
, count
);
471 dwRet
= waveOutPrepareHeader(wmw
->hWave
, &wmw
->WaveHdr
, sizeof(WAVEHDR
));
472 wmw
->WaveHdr
.dwBufferLength
= count
;
473 wmw
->WaveHdr
.dwBytesRecorded
= 0;
474 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
475 &wmw
->WaveHdr
, wmw
->WaveHdr
.dwBufferLength
, wmw
->WaveHdr
.dwBytesRecorded
);
476 dwRet
= waveOutWrite(wmw
->hWave
, &wmw
->WaveHdr
, sizeof(WAVEHDR
));
477 /* FIXME: should use callback mechanisms from audio driver */
479 while (!(wmw
->WaveHdr
.dwFlags
& WHDR_DONE
))
482 wmw
->dwPosition
+= count
;
483 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw
->dwPosition
);
484 dwRet
= waveOutUnprepareHeader(wmw
->hWave
, &wmw
->WaveHdr
, sizeof(WAVEHDR
));
487 if (wmw
->WaveHdr
.lpData
!= NULL
) {
488 GlobalUnlock16(hData
);
490 wmw
->WaveHdr
.lpData
= NULL
;
493 waveOutReset(wmw
->hWave
);
494 waveOutClose(wmw
->hWave
);
496 wmw
->dwStatus
= MCI_MODE_STOP
;
497 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
498 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
499 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
500 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
505 /**************************************************************************
506 * WAVE_mciRecord [internal]
508 static DWORD
WAVE_mciRecord(UINT wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
515 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
517 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
519 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
520 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
523 WARN("cannot record on output device\n");
524 return MCIERR_NONAPPLICABLE_FUNCTION
;
527 if (wmw
->hFile
== 0) {
528 WARN("can't find file='%s' !\n",
529 wmw
->openParms
.lpstrElementName
);
530 return MCIERR_FILE_NOT_FOUND
;
532 start
= 1; end
= 99999;
533 if (dwFlags
& MCI_FROM
) {
534 start
= lpParms
->dwFrom
;
535 TRACE("MCI_FROM=%d \n", start
);
537 if (dwFlags
& MCI_TO
) {
539 TRACE("MCI_TO=%d \n", end
);
542 lpWaveHdr
= &wmw
->WaveHdr
;
543 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
544 lpWaveHdr
->lpData
= (LPSTR
)GlobalLock16(hData
);
545 lpWaveHdr
->dwBufferLength
= bufsize
;
546 lpWaveHdr
->dwUser
= 0L;
547 lpWaveHdr
->dwFlags
= 0L;
548 lpWaveHdr
->dwLoops
= 0L;
549 dwRet
= waveInPrepareHeader(wmw
->hWave
, lpWaveHdr
, sizeof(WAVEHDR
));
550 while (TRUE
) { /* FIXME: I don't see any waveInAddBuffer ? */
551 lpWaveHdr
->dwBytesRecorded
= 0;
552 dwRet
= waveInStart(wmw
->hWave
);
553 TRACE("after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
554 lpWaveHdr
, lpWaveHdr
->dwBytesRecorded
);
555 if (lpWaveHdr
->dwBytesRecorded
== 0) break;
557 dwRet
= waveInUnprepareHeader(wmw
->hWave
, lpWaveHdr
, sizeof(WAVEHDR
));
558 if (lpWaveHdr
->lpData
!= NULL
) {
559 GlobalUnlock16(hData
);
561 lpWaveHdr
->lpData
= NULL
;
563 if (dwFlags
& MCI_NOTIFY
) {
564 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
565 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
566 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
571 /**************************************************************************
572 * WAVE_mciPause [internal]
574 static DWORD
WAVE_mciPause(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
577 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
579 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
581 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
582 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
584 if (wmw
->dwStatus
== MCI_MODE_PLAY
) {
585 wmw
->dwStatus
= MCI_MODE_PAUSE
;
588 if (wmw
->fInput
) dwRet
= waveInStop(wmw
->hWave
);
589 else dwRet
= waveOutPause(wmw
->hWave
);
591 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
594 /**************************************************************************
595 * WAVE_mciResume [internal]
597 static DWORD
WAVE_mciResume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
599 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
602 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
604 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
605 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
607 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
608 wmw
->dwStatus
= MCI_MODE_PLAY
;
611 /* FIXME: I doubt WIDM_START is correct */
612 if (wmw
->fInput
) dwRet
= waveInStart(wmw
->hWave
);
613 else dwRet
= waveOutRestart(wmw
->hWave
);
614 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
617 /**************************************************************************
618 * WAVE_mciSeek [internal]
620 static DWORD
WAVE_mciSeek(UINT wDevID
, DWORD dwFlags
, LPMCI_SEEK_PARMS lpParms
)
623 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
625 TRACE("(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
627 if (lpParms
== NULL
) {
628 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
629 } else if (wmw
== NULL
) {
630 ret
= MCIERR_INVALID_DEVICE_ID
;
632 WAVE_mciStop(wDevID
, MCI_WAIT
, 0);
634 if (dwFlags
& MCI_SEEK_TO_START
) {
636 } else if (dwFlags
& MCI_SEEK_TO_END
) {
637 wmw
->dwPosition
= 0xFFFFFFFF; /* fixme */
638 } else if (dwFlags
& MCI_TO
) {
639 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
641 WARN("dwFlag doesn't tell where to seek to...\n");
642 return MCIERR_MISSING_PARAMETER
;
645 TRACE("Seeking to position=%lu bytes\n", wmw
->dwPosition
);
647 if (dwFlags
& MCI_NOTIFY
) {
648 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
649 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
650 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
656 /**************************************************************************
657 * WAVE_mciSet [internal]
659 static DWORD
WAVE_mciSet(UINT wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
661 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
663 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
665 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
666 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
668 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
669 switch (lpParms
->dwTimeFormat
) {
670 case MCI_FORMAT_MILLISECONDS
:
671 TRACE("MCI_FORMAT_MILLISECONDS !\n");
672 wmw
->dwMciTimeFormat
= MCI_FORMAT_MILLISECONDS
;
674 case MCI_FORMAT_BYTES
:
675 TRACE("MCI_FORMAT_BYTES !\n");
676 wmw
->dwMciTimeFormat
= MCI_FORMAT_BYTES
;
678 case MCI_FORMAT_SAMPLES
:
679 TRACE("MCI_FORMAT_SAMPLES !\n");
680 wmw
->dwMciTimeFormat
= MCI_FORMAT_SAMPLES
;
683 WARN("Bad time format %lu!\n", lpParms
->dwTimeFormat
);
684 return MCIERR_BAD_TIME_FORMAT
;
687 if (dwFlags
& MCI_SET_VIDEO
) {
688 TRACE("No support for video !\n");
689 return MCIERR_UNSUPPORTED_FUNCTION
;
691 if (dwFlags
& MCI_SET_DOOR_OPEN
) {
692 TRACE("No support for door open !\n");
693 return MCIERR_UNSUPPORTED_FUNCTION
;
695 if (dwFlags
& MCI_SET_DOOR_CLOSED
) {
696 TRACE("No support for door close !\n");
697 return MCIERR_UNSUPPORTED_FUNCTION
;
699 if (dwFlags
& MCI_SET_AUDIO
) {
700 if (dwFlags
& MCI_SET_ON
) {
701 TRACE("MCI_SET_ON audio !\n");
702 } else if (dwFlags
& MCI_SET_OFF
) {
703 TRACE("MCI_SET_OFF audio !\n");
705 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
706 return MCIERR_BAD_INTEGER
;
709 if (lpParms
->dwAudio
& MCI_SET_AUDIO_ALL
)
710 TRACE("MCI_SET_AUDIO_ALL !\n");
711 if (lpParms
->dwAudio
& MCI_SET_AUDIO_LEFT
)
712 TRACE("MCI_SET_AUDIO_LEFT !\n");
713 if (lpParms
->dwAudio
& MCI_SET_AUDIO_RIGHT
)
714 TRACE("MCI_SET_AUDIO_RIGHT !\n");
716 if (dwFlags
& MCI_WAVE_INPUT
)
717 TRACE("MCI_WAVE_INPUT !\n");
718 if (dwFlags
& MCI_WAVE_OUTPUT
)
719 TRACE("MCI_WAVE_OUTPUT !\n");
720 if (dwFlags
& MCI_WAVE_SET_ANYINPUT
)
721 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
722 if (dwFlags
& MCI_WAVE_SET_ANYOUTPUT
)
723 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
724 if (dwFlags
& MCI_WAVE_SET_AVGBYTESPERSEC
)
725 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
726 if (dwFlags
& MCI_WAVE_SET_BITSPERSAMPLE
)
727 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
728 if (dwFlags
& MCI_WAVE_SET_BLOCKALIGN
)
729 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
730 if (dwFlags
& MCI_WAVE_SET_CHANNELS
)
731 TRACE("MCI_WAVE_SET_CHANNELS !\n");
732 if (dwFlags
& MCI_WAVE_SET_FORMATTAG
)
733 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
734 if (dwFlags
& MCI_WAVE_SET_SAMPLESPERSEC
)
735 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
739 /**************************************************************************
740 * WAVE_mciStatus [internal]
742 static DWORD
WAVE_mciStatus(UINT wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
744 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
747 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
748 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
749 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
751 if (dwFlags
& MCI_STATUS_ITEM
) {
752 switch (lpParms
->dwItem
) {
753 case MCI_STATUS_CURRENT_TRACK
:
754 lpParms
->dwReturn
= 1;
755 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms
->dwReturn
);
757 case MCI_STATUS_LENGTH
:
758 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
759 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
, wmw
->dwLength
, &ret
);
760 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms
->dwReturn
);
762 case MCI_STATUS_MODE
:
763 TRACE("MCI_STATUS_MODE => %u\n", wmw
->dwStatus
);
764 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwStatus
, wmw
->dwStatus
);
765 ret
= MCI_RESOURCE_RETURNED
;
767 case MCI_STATUS_MEDIA_PRESENT
:
768 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
769 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
770 ret
= MCI_RESOURCE_RETURNED
;
772 case MCI_STATUS_NUMBER_OF_TRACKS
:
773 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
774 lpParms
->dwReturn
= 1;
775 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms
->dwReturn
);
777 case MCI_STATUS_POSITION
:
778 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
779 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
,
780 (dwFlags
& MCI_STATUS_START
) ? 0 : wmw
->dwPosition
,
782 TRACE("MCI_STATUS_POSITION %s => %lu\n",
783 (dwFlags
& MCI_STATUS_START
) ? "start" : "current", lpParms
->dwReturn
);
785 case MCI_STATUS_READY
:
786 lpParms
->dwReturn
= (wmw
->dwStatus
== MCI_MODE_NOT_READY
) ?
787 MAKEMCIRESOURCE(FALSE
, MCI_FALSE
) : MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
788 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms
->dwReturn
));
789 ret
= MCI_RESOURCE_RETURNED
;
791 case MCI_STATUS_TIME_FORMAT
:
792 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwMciTimeFormat
, wmw
->dwMciTimeFormat
);
793 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms
->dwReturn
);
794 ret
= MCI_RESOURCE_RETURNED
;
797 TRACE("MCI_WAVE_INPUT !\n");
798 lpParms
->dwReturn
= 0;
800 case MCI_WAVE_OUTPUT
:
801 TRACE("MCI_WAVE_OUTPUT !\n");
802 lpParms
->dwReturn
= 0;
804 case MCI_WAVE_STATUS_AVGBYTESPERSEC
:
805 lpParms
->dwReturn
= wmw
->WaveFormat
.wf
.nAvgBytesPerSec
;
806 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms
->dwReturn
);
808 case MCI_WAVE_STATUS_BITSPERSAMPLE
:
809 lpParms
->dwReturn
= wmw
->WaveFormat
.wBitsPerSample
;
810 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms
->dwReturn
);
812 case MCI_WAVE_STATUS_BLOCKALIGN
:
813 lpParms
->dwReturn
= wmw
->WaveFormat
.wf
.nBlockAlign
;
814 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms
->dwReturn
);
816 case MCI_WAVE_STATUS_CHANNELS
:
817 lpParms
->dwReturn
= wmw
->WaveFormat
.wf
.nChannels
;
818 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms
->dwReturn
);
820 case MCI_WAVE_STATUS_FORMATTAG
:
821 lpParms
->dwReturn
= wmw
->WaveFormat
.wf
.wFormatTag
;
822 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms
->dwReturn
);
824 case MCI_WAVE_STATUS_LEVEL
:
825 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
826 lpParms
->dwReturn
= 0xAAAA5555;
828 case MCI_WAVE_STATUS_SAMPLESPERSEC
:
829 lpParms
->dwReturn
= wmw
->WaveFormat
.wf
.nSamplesPerSec
;
830 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms
->dwReturn
);
833 WARN("unknown command %08lX !\n", lpParms
->dwItem
);
834 return MCIERR_UNRECOGNIZED_COMMAND
;
837 if (dwFlags
& MCI_NOTIFY
) {
838 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
839 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
840 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
845 /**************************************************************************
846 * WAVE_mciGetDevCaps [internal]
848 static DWORD
WAVE_mciGetDevCaps(UINT wDevID
, DWORD dwFlags
,
849 LPMCI_GETDEVCAPS_PARMS lpParms
)
851 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
854 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
856 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
857 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
859 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
860 switch(lpParms
->dwItem
) {
861 case MCI_GETDEVCAPS_DEVICE_TYPE
:
862 lpParms
->dwReturn
= MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO
, MCI_DEVTYPE_WAVEFORM_AUDIO
);
863 ret
= MCI_RESOURCE_RETURNED
;
865 case MCI_GETDEVCAPS_HAS_AUDIO
:
866 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
867 ret
= MCI_RESOURCE_RETURNED
;
869 case MCI_GETDEVCAPS_HAS_VIDEO
:
870 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
871 ret
= MCI_RESOURCE_RETURNED
;
873 case MCI_GETDEVCAPS_USES_FILES
:
874 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
875 ret
= MCI_RESOURCE_RETURNED
;
877 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
878 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
879 ret
= MCI_RESOURCE_RETURNED
;
881 case MCI_GETDEVCAPS_CAN_RECORD
:
882 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
883 ret
= MCI_RESOURCE_RETURNED
;
885 case MCI_GETDEVCAPS_CAN_EJECT
:
886 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
887 ret
= MCI_RESOURCE_RETURNED
;
889 case MCI_GETDEVCAPS_CAN_PLAY
:
890 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
891 ret
= MCI_RESOURCE_RETURNED
;
893 case MCI_GETDEVCAPS_CAN_SAVE
:
894 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
895 ret
= MCI_RESOURCE_RETURNED
;
897 case MCI_WAVE_GETDEVCAPS_INPUTS
:
898 lpParms
->dwReturn
= 1;
900 case MCI_WAVE_GETDEVCAPS_OUTPUTS
:
901 lpParms
->dwReturn
= 1;
904 FIXME("Unknown capability (%08lx) !\n", lpParms
->dwItem
);
905 return MCIERR_UNRECOGNIZED_COMMAND
;
908 WARN("No GetDevCaps-Item !\n");
909 return MCIERR_UNRECOGNIZED_COMMAND
;
914 /**************************************************************************
915 * WAVE_mciInfo [internal]
917 static DWORD
WAVE_mciInfo(UINT wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMSA lpParms
)
921 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
923 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
925 if (lpParms
== NULL
|| lpParms
->lpstrReturn
== NULL
) {
926 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
927 } else if (wmw
== NULL
) {
928 ret
= MCIERR_INVALID_DEVICE_ID
;
930 TRACE("buf=%p, len=%lu\n", lpParms
->lpstrReturn
, lpParms
->dwRetSize
);
933 case MCI_INFO_PRODUCT
:
934 str
= "Wine's audio player";
937 str
= wmw
->openParms
.lpstrElementName
;
940 str
= "Wine Wave In";
942 case MCI_WAVE_OUTPUT
:
943 str
= "Wine Wave Out";
946 WARN("Don't know this info command (%lu)\n", dwFlags
);
947 ret
= MCIERR_UNRECOGNIZED_COMMAND
;
951 if (strlen(str
) + 1 > lpParms
->dwRetSize
) {
952 ret
= MCIERR_PARAM_OVERFLOW
;
954 lstrcpynA(lpParms
->lpstrReturn
, str
, lpParms
->dwRetSize
);
957 lpParms
->lpstrReturn
[0] = 0;
963 /**************************************************************************
964 * MCIWAVE_DriverProc [sample driver]
966 LONG CALLBACK
MCIWAVE_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
967 DWORD dwParam1
, DWORD dwParam2
)
969 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
970 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
973 case DRV_LOAD
: return 1;
974 case DRV_FREE
: return 1;
975 case DRV_OPEN
: return WAVE_drvOpen((LPSTR
)dwParam1
, (LPMCI_OPEN_DRIVER_PARMSA
)dwParam2
);
976 case DRV_CLOSE
: return WAVE_drvClose(dwDevID
);
977 case DRV_ENABLE
: return 1;
978 case DRV_DISABLE
: return 1;
979 case DRV_QUERYCONFIGURE
: return 1;
980 case DRV_CONFIGURE
: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK
); return 1;
981 case DRV_INSTALL
: return DRVCNF_RESTART
;
982 case DRV_REMOVE
: return DRVCNF_RESTART
;
983 case MCI_OPEN_DRIVER
: return WAVE_mciOpen (dwDevID
, dwParam1
, (LPMCI_WAVE_OPEN_PARMSA
) dwParam2
);
984 case MCI_CLOSE_DRIVER
: return WAVE_mciClose (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
985 case MCI_CUE
: return WAVE_mciCue (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
986 case MCI_PLAY
: return WAVE_mciPlay (dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
) dwParam2
);
987 case MCI_RECORD
: return WAVE_mciRecord (dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
) dwParam2
);
988 case MCI_STOP
: return WAVE_mciStop (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
989 case MCI_SET
: return WAVE_mciSet (dwDevID
, dwParam1
, (LPMCI_SET_PARMS
) dwParam2
);
990 case MCI_PAUSE
: return WAVE_mciPause (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
991 case MCI_RESUME
: return WAVE_mciResume (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
992 case MCI_STATUS
: return WAVE_mciStatus (dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
) dwParam2
);
993 case MCI_GETDEVCAPS
: return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
) dwParam2
);
994 case MCI_INFO
: return WAVE_mciInfo (dwDevID
, dwParam1
, (LPMCI_INFO_PARMSA
) dwParam2
);
995 case MCI_SEEK
: return WAVE_mciSeek (dwDevID
, dwParam1
, (LPMCI_SEEK_PARMS
) dwParam2
);
996 /* commands that should be supported */
1012 FIXME("Unsupported yet command=%s\n", MCI_MessageToString(wMsg
));
1015 TRACE("Unsupported command=%s\n", MCI_MessageToString(wMsg
));
1019 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1022 FIXME("is probably wrong msg=%s\n", MCI_MessageToString(wMsg
));
1023 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1025 return MCIERR_UNRECOGNIZED_COMMAND
;