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 LPWAVEFORMATEX lpWaveFormat
;
32 BOOL fInput
; /* FALSE = Output, TRUE = Input */
33 WORD dwStatus
; /* one from MCI_MODE_xxxx */
34 DWORD dwMciTimeFormat
;/* One of the supported MCI_FORMAT_xxxx */
35 DWORD dwFileOffset
; /* Offset of chunk in mmio file */
36 DWORD dwLength
; /* number of bytes in chunk for playing */
37 DWORD dwPosition
; /* position in bytes in chunk for playing */
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 (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
423 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
425 wmw
->dwStatus
= MCI_MODE_STOP
;
427 TRACE("wmw->dwStatus=%d\n", wmw
->dwStatus
);
430 dwRet
= waveInReset(wmw
->hWave
);
432 dwRet
= waveOutReset(wmw
->hWave
);
434 if (dwFlags
& MCI_NOTIFY
) {
435 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
436 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
437 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
440 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
443 /**************************************************************************
444 * WAVE_mciClose [internal]
446 static DWORD
WAVE_mciClose(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
449 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
451 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
453 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
455 if (wmw
->dwStatus
!= MCI_MODE_STOP
) {
456 dwRet
= WAVE_mciStop(wDevID
, MCI_WAIT
, lpParms
);
461 if (wmw
->nUseCount
== 0) {
463 if (wmw
->hFile
!= 0) {
464 mmioClose(wmw
->hFile
, 0);
467 mmRet
= (wmw
->fInput
) ? waveInClose(wmw
->hWave
) : waveOutClose(wmw
->hWave
);
469 if (mmRet
!= MMSYSERR_NOERROR
) dwRet
= MCIERR_INTERNAL
;
472 HeapFree(GetProcessHeap(), 0, wmw
->lpWaveFormat
);
473 wmw
->lpWaveFormat
= NULL
;
475 if ((dwFlags
& MCI_NOTIFY
) && lpParms
) {
476 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
477 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
478 wmw
->wNotifyDeviceID
,
479 (dwRet
== 0) ? MCI_NOTIFY_SUCCESSFUL
: MCI_NOTIFY_FAILURE
);
484 /**************************************************************************
485 * WAVE_mciPlay [internal]
487 static DWORD
WAVE_mciPlay(UINT wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
490 LONG bufsize
, count
, left
;
493 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
496 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
498 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
499 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
502 WARN("cannot play on input device\n");
503 return MCIERR_NONAPPLICABLE_FUNCTION
;
506 if (wmw
->hFile
== 0) {
507 WARN("Can't play: no file='%s' !\n", wmw
->openParms
.lpstrElementName
);
508 return MCIERR_FILE_NOT_FOUND
;
511 if (!(dwFlags
& MCI_WAIT
)) {
512 return MCI_SendCommandAsync(wmw
->wNotifyDeviceID
, MCI_PLAY
, dwFlags
,
513 (DWORD
)lpParms
, sizeof(MCI_PLAY_PARMS
));
516 if (wmw
->dwStatus
!= MCI_MODE_STOP
) {
517 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
518 /* FIXME: parameters (start/end) in lpParams may not be used */
519 return WAVE_mciResume(wDevID
, dwFlags
, (LPMCI_GENERIC_PARMS
)lpParms
);
521 return MCIERR_INTERNAL
;
525 if (lpParms
&& (dwFlags
& MCI_FROM
)) {
526 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwFrom
);
528 if (lpParms
&& (dwFlags
& MCI_TO
)) {
529 end
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
532 TRACE("Playing from byte=%lu to byte=%lu\n", wmw
->dwPosition
, end
);
534 if (end
<= wmw
->dwPosition
)
537 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
538 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
540 wmw
->dwPosition
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->dwPosition
);
541 wmw
->dwLength
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->dwLength
);
542 /* go back to begining of chunk plus the requested position */
543 /* FIXME: I'm not sure this is correct, notably because some data linked to
544 * the decompression state machine will not be correcly initialized.
545 * try it this way (other way would be to decompress from 0 up to dwPosition
546 * and to start sending to hWave when dwPosition is reached)
548 mmioSeek(wmw
->hFile
, wmw
->dwFileOffset
+ wmw
->dwPosition
, SEEK_SET
); /* >= 0 */
550 /* By default the device will be opened for output, the MCI_CUE function is there to
551 * change from output to input and back
553 /* FIXME: how to choose between several output channels ? here mapper is forced */
554 dwRet
= waveOutOpen(&wmw
->hWave
, WAVE_MAPPER
, wmw
->lpWaveFormat
, 0L, 0L, CALLBACK_NULL
);
556 TRACE("Can't open low level audio device %ld\n", dwRet
);
557 return MCIERR_DEVICE_OPEN
;
560 /* make it so that 3 buffers per second are needed */
561 bufsize
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->lpWaveFormat
->nAvgBytesPerSec
/ 3);
563 waveHdr
= HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR
) + 2 * bufsize
);
564 waveHdr
[0].lpData
= (char*)waveHdr
+ 2 * sizeof(WAVEHDR
);
565 waveHdr
[1].lpData
= (char*)waveHdr
+ 2 * sizeof(WAVEHDR
) + bufsize
;
566 waveHdr
[0].dwUser
= waveHdr
[1].dwUser
= 0L;
567 waveHdr
[0].dwLoops
= waveHdr
[1].dwLoops
= 0L;
569 wmw
->dwStatus
= MCI_MODE_PLAY
;
572 left
= MIN(wmw
->dwLength
, end
- wmw
->dwPosition
);
574 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw
->dwPosition
, left
);
576 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
577 while (left
> 0 && wmw
->dwStatus
!= MCI_MODE_STOP
) {
578 waveHdr
[whidx
].dwFlags
= 0L;
579 count
= mmioRead(wmw
->hFile
, waveHdr
[whidx
].lpData
, MIN(bufsize
, left
));
580 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize
, count
);
584 waveHdr
[whidx
].dwBufferLength
= count
;
585 dwRet
= waveOutPrepareHeader(wmw
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
586 /* EPP waveHdr[whidx].dwBytesRecorded = 0; */
587 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
588 &waveHdr
[whidx
], waveHdr
[whidx
].dwBufferLength
,
589 waveHdr
[whidx
].dwBytesRecorded
);
590 dwRet
= waveOutWrite(wmw
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
591 wmw
->dwPosition
+= count
;
592 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw
->dwPosition
);
595 if (waveHdr
[whidx
].dwFlags
& WHDR_PREPARED
) {
596 /* FIXME: should use callback mechanisms from audio driver */
597 while (!(waveHdr
[whidx
].dwFlags
& WHDR_DONE
))
599 dwRet
= waveOutUnprepareHeader(wmw
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
603 if (waveHdr
[whidx
].dwFlags
& WHDR_PREPARED
) {
604 /* test if waveHdr[whidx] has been prepared, if so it has been queued for playing */
605 while (!(waveHdr
[whidx
].dwFlags
& WHDR_DONE
))
607 waveOutUnprepareHeader(wmw
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
610 HeapFree(GetProcessHeap(), 0, waveHdr
);
612 waveOutReset(wmw
->hWave
);
613 waveOutClose(wmw
->hWave
);
615 wmw
->dwStatus
= MCI_MODE_STOP
;
616 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
617 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
618 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
619 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
624 /**************************************************************************
625 * WAVE_mciRecord [internal]
627 static DWORD
WAVE_mciRecord(UINT wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
633 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
635 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
637 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
638 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
641 WARN("cannot record on output device\n");
642 return MCIERR_NONAPPLICABLE_FUNCTION
;
645 if (wmw
->hFile
== 0) {
646 WARN("can't find file='%s' !\n",
647 wmw
->openParms
.lpstrElementName
);
648 return MCIERR_FILE_NOT_FOUND
;
650 start
= 1; end
= 99999;
651 if (dwFlags
& MCI_FROM
) {
652 start
= lpParms
->dwFrom
;
653 TRACE("MCI_FROM=%d \n", start
);
655 if (dwFlags
& MCI_TO
) {
657 TRACE("MCI_TO=%d \n", end
);
660 waveHdr
.lpData
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
661 waveHdr
.dwBufferLength
= bufsize
;
663 waveHdr
.dwFlags
= 0L;
664 waveHdr
.dwLoops
= 0L;
665 dwRet
= waveInPrepareHeader(wmw
->hWave
, &waveHdr
, sizeof(WAVEHDR
));
667 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
668 waveHdr
.dwBytesRecorded
= 0;
669 dwRet
= waveInStart(wmw
->hWave
);
670 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
671 &waveHdr
, waveHdr
.dwBytesRecorded
);
672 if (waveHdr
.dwBytesRecorded
== 0) break;
674 dwRet
= waveInUnprepareHeader(wmw
->hWave
, &waveHdr
, sizeof(WAVEHDR
));
675 HeapFree(GetProcessHeap(), 0, waveHdr
.lpData
);
677 if (dwFlags
& MCI_NOTIFY
) {
678 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
679 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
680 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
685 /**************************************************************************
686 * WAVE_mciPause [internal]
688 static DWORD
WAVE_mciPause(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
691 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
693 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
695 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
696 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
698 if (wmw
->dwStatus
== MCI_MODE_PLAY
) {
699 wmw
->dwStatus
= MCI_MODE_PAUSE
;
702 if (wmw
->fInput
) dwRet
= waveInStop(wmw
->hWave
);
703 else dwRet
= waveOutPause(wmw
->hWave
);
705 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
708 /**************************************************************************
709 * WAVE_mciResume [internal]
711 static DWORD
WAVE_mciResume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
713 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
716 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
718 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
719 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
721 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
722 wmw
->dwStatus
= MCI_MODE_PLAY
;
725 /* FIXME: I doubt WIDM_START is correct */
726 if (wmw
->fInput
) dwRet
= waveInStart(wmw
->hWave
);
727 else dwRet
= waveOutRestart(wmw
->hWave
);
728 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
731 /**************************************************************************
732 * WAVE_mciSeek [internal]
734 static DWORD
WAVE_mciSeek(UINT wDevID
, DWORD dwFlags
, LPMCI_SEEK_PARMS lpParms
)
737 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
739 TRACE("(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
741 if (lpParms
== NULL
) {
742 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
743 } else if (wmw
== NULL
) {
744 ret
= MCIERR_INVALID_DEVICE_ID
;
746 WAVE_mciStop(wDevID
, MCI_WAIT
, 0);
748 if (dwFlags
& MCI_SEEK_TO_START
) {
750 } else if (dwFlags
& MCI_SEEK_TO_END
) {
751 wmw
->dwPosition
= wmw
->dwLength
;
752 } else if (dwFlags
& MCI_TO
) {
753 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
755 WARN("dwFlag doesn't tell where to seek to...\n");
756 return MCIERR_MISSING_PARAMETER
;
759 TRACE("Seeking to position=%lu bytes\n", wmw
->dwPosition
);
761 if (dwFlags
& MCI_NOTIFY
) {
762 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
763 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
764 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
770 /**************************************************************************
771 * WAVE_mciSet [internal]
773 static DWORD
WAVE_mciSet(UINT wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
775 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
777 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
779 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
780 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
782 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
783 switch (lpParms
->dwTimeFormat
) {
784 case MCI_FORMAT_MILLISECONDS
:
785 TRACE("MCI_FORMAT_MILLISECONDS !\n");
786 wmw
->dwMciTimeFormat
= MCI_FORMAT_MILLISECONDS
;
788 case MCI_FORMAT_BYTES
:
789 TRACE("MCI_FORMAT_BYTES !\n");
790 wmw
->dwMciTimeFormat
= MCI_FORMAT_BYTES
;
792 case MCI_FORMAT_SAMPLES
:
793 TRACE("MCI_FORMAT_SAMPLES !\n");
794 wmw
->dwMciTimeFormat
= MCI_FORMAT_SAMPLES
;
797 WARN("Bad time format %lu!\n", lpParms
->dwTimeFormat
);
798 return MCIERR_BAD_TIME_FORMAT
;
801 if (dwFlags
& MCI_SET_VIDEO
) {
802 TRACE("No support for video !\n");
803 return MCIERR_UNSUPPORTED_FUNCTION
;
805 if (dwFlags
& MCI_SET_DOOR_OPEN
) {
806 TRACE("No support for door open !\n");
807 return MCIERR_UNSUPPORTED_FUNCTION
;
809 if (dwFlags
& MCI_SET_DOOR_CLOSED
) {
810 TRACE("No support for door close !\n");
811 return MCIERR_UNSUPPORTED_FUNCTION
;
813 if (dwFlags
& MCI_SET_AUDIO
) {
814 if (dwFlags
& MCI_SET_ON
) {
815 TRACE("MCI_SET_ON audio !\n");
816 } else if (dwFlags
& MCI_SET_OFF
) {
817 TRACE("MCI_SET_OFF audio !\n");
819 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
820 return MCIERR_BAD_INTEGER
;
823 if (lpParms
->dwAudio
& MCI_SET_AUDIO_ALL
)
824 TRACE("MCI_SET_AUDIO_ALL !\n");
825 if (lpParms
->dwAudio
& MCI_SET_AUDIO_LEFT
)
826 TRACE("MCI_SET_AUDIO_LEFT !\n");
827 if (lpParms
->dwAudio
& MCI_SET_AUDIO_RIGHT
)
828 TRACE("MCI_SET_AUDIO_RIGHT !\n");
830 if (dwFlags
& MCI_WAVE_INPUT
)
831 TRACE("MCI_WAVE_INPUT !\n");
832 if (dwFlags
& MCI_WAVE_OUTPUT
)
833 TRACE("MCI_WAVE_OUTPUT !\n");
834 if (dwFlags
& MCI_WAVE_SET_ANYINPUT
)
835 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
836 if (dwFlags
& MCI_WAVE_SET_ANYOUTPUT
)
837 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
838 if (dwFlags
& MCI_WAVE_SET_AVGBYTESPERSEC
)
839 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
840 if (dwFlags
& MCI_WAVE_SET_BITSPERSAMPLE
)
841 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
842 if (dwFlags
& MCI_WAVE_SET_BLOCKALIGN
)
843 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
844 if (dwFlags
& MCI_WAVE_SET_CHANNELS
)
845 TRACE("MCI_WAVE_SET_CHANNELS !\n");
846 if (dwFlags
& MCI_WAVE_SET_FORMATTAG
)
847 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
848 if (dwFlags
& MCI_WAVE_SET_SAMPLESPERSEC
)
849 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
853 /**************************************************************************
854 * WAVE_mciStatus [internal]
856 static DWORD
WAVE_mciStatus(UINT wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
858 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
861 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
862 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
863 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
865 if (dwFlags
& MCI_STATUS_ITEM
) {
866 switch (lpParms
->dwItem
) {
867 case MCI_STATUS_CURRENT_TRACK
:
868 lpParms
->dwReturn
= 1;
869 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms
->dwReturn
);
871 case MCI_STATUS_LENGTH
:
873 lpParms
->dwReturn
= 0;
874 return MCIERR_UNSUPPORTED_FUNCTION
;
876 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
877 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
, wmw
->dwLength
, &ret
);
878 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms
->dwReturn
);
880 case MCI_STATUS_MODE
:
881 TRACE("MCI_STATUS_MODE => %u\n", wmw
->dwStatus
);
882 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwStatus
, wmw
->dwStatus
);
883 ret
= MCI_RESOURCE_RETURNED
;
885 case MCI_STATUS_MEDIA_PRESENT
:
886 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
887 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
888 ret
= MCI_RESOURCE_RETURNED
;
890 case MCI_STATUS_NUMBER_OF_TRACKS
:
891 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
892 lpParms
->dwReturn
= 1;
893 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms
->dwReturn
);
895 case MCI_STATUS_POSITION
:
897 lpParms
->dwReturn
= 0;
898 return MCIERR_UNSUPPORTED_FUNCTION
;
900 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
901 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
,
902 (dwFlags
& MCI_STATUS_START
) ? 0 : wmw
->dwPosition
,
904 TRACE("MCI_STATUS_POSITION %s => %lu\n",
905 (dwFlags
& MCI_STATUS_START
) ? "start" : "current", lpParms
->dwReturn
);
907 case MCI_STATUS_READY
:
908 lpParms
->dwReturn
= (wmw
->dwStatus
== MCI_MODE_NOT_READY
) ?
909 MAKEMCIRESOURCE(FALSE
, MCI_FALSE
) : MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
910 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms
->dwReturn
));
911 ret
= MCI_RESOURCE_RETURNED
;
913 case MCI_STATUS_TIME_FORMAT
:
914 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwMciTimeFormat
, wmw
->dwMciTimeFormat
);
915 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms
->dwReturn
);
916 ret
= MCI_RESOURCE_RETURNED
;
919 TRACE("MCI_WAVE_INPUT !\n");
920 lpParms
->dwReturn
= 0;
921 ret
= MCIERR_WAVE_INPUTUNSPECIFIED
;
923 case MCI_WAVE_OUTPUT
:
924 TRACE("MCI_WAVE_OUTPUT !\n");
927 if (waveOutGetID(wmw
->hWave
, &id
) == MMSYSERR_NOERROR
) {
928 lpParms
->dwReturn
= id
;
930 lpParms
->dwReturn
= 0;
931 ret
= MCIERR_WAVE_INPUTUNSPECIFIED
;
935 case MCI_WAVE_STATUS_AVGBYTESPERSEC
:
937 lpParms
->dwReturn
= 0;
938 return MCIERR_UNSUPPORTED_FUNCTION
;
940 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nAvgBytesPerSec
;
941 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms
->dwReturn
);
943 case MCI_WAVE_STATUS_BITSPERSAMPLE
:
945 lpParms
->dwReturn
= 0;
946 return MCIERR_UNSUPPORTED_FUNCTION
;
948 lpParms
->dwReturn
= wmw
->lpWaveFormat
->wBitsPerSample
;
949 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms
->dwReturn
);
951 case MCI_WAVE_STATUS_BLOCKALIGN
:
953 lpParms
->dwReturn
= 0;
954 return MCIERR_UNSUPPORTED_FUNCTION
;
956 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nBlockAlign
;
957 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms
->dwReturn
);
959 case MCI_WAVE_STATUS_CHANNELS
:
961 lpParms
->dwReturn
= 0;
962 return MCIERR_UNSUPPORTED_FUNCTION
;
964 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nChannels
;
965 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms
->dwReturn
);
967 case MCI_WAVE_STATUS_FORMATTAG
:
969 lpParms
->dwReturn
= 0;
970 return MCIERR_UNSUPPORTED_FUNCTION
;
972 lpParms
->dwReturn
= wmw
->lpWaveFormat
->wFormatTag
;
973 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms
->dwReturn
);
975 case MCI_WAVE_STATUS_LEVEL
:
976 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
977 lpParms
->dwReturn
= 0xAAAA5555;
979 case MCI_WAVE_STATUS_SAMPLESPERSEC
:
981 lpParms
->dwReturn
= 0;
982 return MCIERR_UNSUPPORTED_FUNCTION
;
984 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nSamplesPerSec
;
985 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms
->dwReturn
);
988 WARN("unknown command %08lX !\n", lpParms
->dwItem
);
989 return MCIERR_UNRECOGNIZED_COMMAND
;
992 if (dwFlags
& MCI_NOTIFY
) {
993 TRACE("MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
994 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
995 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
1000 /**************************************************************************
1001 * WAVE_mciGetDevCaps [internal]
1003 static DWORD
WAVE_mciGetDevCaps(UINT wDevID
, DWORD dwFlags
,
1004 LPMCI_GETDEVCAPS_PARMS lpParms
)
1006 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
1009 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1011 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
1012 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
1014 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
1015 switch(lpParms
->dwItem
) {
1016 case MCI_GETDEVCAPS_DEVICE_TYPE
:
1017 lpParms
->dwReturn
= MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO
, MCI_DEVTYPE_WAVEFORM_AUDIO
);
1018 ret
= MCI_RESOURCE_RETURNED
;
1020 case MCI_GETDEVCAPS_HAS_AUDIO
:
1021 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1022 ret
= MCI_RESOURCE_RETURNED
;
1024 case MCI_GETDEVCAPS_HAS_VIDEO
:
1025 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
1026 ret
= MCI_RESOURCE_RETURNED
;
1028 case MCI_GETDEVCAPS_USES_FILES
:
1029 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1030 ret
= MCI_RESOURCE_RETURNED
;
1032 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
1033 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1034 ret
= MCI_RESOURCE_RETURNED
;
1036 case MCI_GETDEVCAPS_CAN_RECORD
:
1037 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1038 ret
= MCI_RESOURCE_RETURNED
;
1040 case MCI_GETDEVCAPS_CAN_EJECT
:
1041 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
1042 ret
= MCI_RESOURCE_RETURNED
;
1044 case MCI_GETDEVCAPS_CAN_PLAY
:
1045 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1046 ret
= MCI_RESOURCE_RETURNED
;
1048 case MCI_GETDEVCAPS_CAN_SAVE
:
1049 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1050 ret
= MCI_RESOURCE_RETURNED
;
1052 case MCI_WAVE_GETDEVCAPS_INPUTS
:
1053 lpParms
->dwReturn
= 1;
1055 case MCI_WAVE_GETDEVCAPS_OUTPUTS
:
1056 lpParms
->dwReturn
= 1;
1059 FIXME("Unknown capability (%08lx) !\n", lpParms
->dwItem
);
1060 return MCIERR_UNRECOGNIZED_COMMAND
;
1063 WARN("No GetDevCaps-Item !\n");
1064 return MCIERR_UNRECOGNIZED_COMMAND
;
1069 /**************************************************************************
1070 * WAVE_mciInfo [internal]
1072 static DWORD
WAVE_mciInfo(UINT wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMSA lpParms
)
1076 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
1078 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1080 if (lpParms
== NULL
|| lpParms
->lpstrReturn
== NULL
) {
1081 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
1082 } else if (wmw
== NULL
) {
1083 ret
= MCIERR_INVALID_DEVICE_ID
;
1085 TRACE("buf=%p, len=%lu\n", lpParms
->lpstrReturn
, lpParms
->dwRetSize
);
1088 case MCI_INFO_PRODUCT
:
1089 str
= "Wine's audio player";
1092 str
= wmw
->openParms
.lpstrElementName
;
1094 case MCI_WAVE_INPUT
:
1095 str
= "Wine Wave In";
1097 case MCI_WAVE_OUTPUT
:
1098 str
= "Wine Wave Out";
1101 WARN("Don't know this info command (%lu)\n", dwFlags
);
1102 ret
= MCIERR_UNRECOGNIZED_COMMAND
;
1106 if (strlen(str
) + 1 > lpParms
->dwRetSize
) {
1107 ret
= MCIERR_PARAM_OVERFLOW
;
1109 lstrcpynA(lpParms
->lpstrReturn
, str
, lpParms
->dwRetSize
);
1112 lpParms
->lpstrReturn
[0] = 0;
1118 /**************************************************************************
1119 * MCIWAVE_DriverProc [sample driver]
1121 LONG CALLBACK
MCIWAVE_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
1122 DWORD dwParam1
, DWORD dwParam2
)
1124 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1125 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1128 case DRV_LOAD
: return 1;
1129 case DRV_FREE
: return 1;
1130 case DRV_OPEN
: return WAVE_drvOpen((LPSTR
)dwParam1
, (LPMCI_OPEN_DRIVER_PARMSA
)dwParam2
);
1131 case DRV_CLOSE
: return WAVE_drvClose(dwDevID
);
1132 case DRV_ENABLE
: return 1;
1133 case DRV_DISABLE
: return 1;
1134 case DRV_QUERYCONFIGURE
: return 1;
1135 case DRV_CONFIGURE
: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK
); return 1;
1136 case DRV_INSTALL
: return DRVCNF_RESTART
;
1137 case DRV_REMOVE
: return DRVCNF_RESTART
;
1138 case MCI_OPEN_DRIVER
: return WAVE_mciOpen (dwDevID
, dwParam1
, (LPMCI_WAVE_OPEN_PARMSA
) dwParam2
);
1139 case MCI_CLOSE_DRIVER
: return WAVE_mciClose (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1140 case MCI_CUE
: return WAVE_mciCue (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1141 case MCI_PLAY
: return WAVE_mciPlay (dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
) dwParam2
);
1142 case MCI_RECORD
: return WAVE_mciRecord (dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
) dwParam2
);
1143 case MCI_STOP
: return WAVE_mciStop (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1144 case MCI_SET
: return WAVE_mciSet (dwDevID
, dwParam1
, (LPMCI_SET_PARMS
) dwParam2
);
1145 case MCI_PAUSE
: return WAVE_mciPause (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1146 case MCI_RESUME
: return WAVE_mciResume (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1147 case MCI_STATUS
: return WAVE_mciStatus (dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
) dwParam2
);
1148 case MCI_GETDEVCAPS
: return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
) dwParam2
);
1149 case MCI_INFO
: return WAVE_mciInfo (dwDevID
, dwParam1
, (LPMCI_INFO_PARMSA
) dwParam2
);
1150 case MCI_SEEK
: return WAVE_mciSeek (dwDevID
, dwParam1
, (LPMCI_SEEK_PARMS
) dwParam2
);
1151 /* commands that should be supported */
1167 FIXME("Unsupported yet command [%lu]\n", wMsg
);
1170 TRACE("Unsupported command [%lu]\n", wMsg
);
1174 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1177 FIXME("is probably wrong msg [%lu]\n", wMsg
);
1178 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1180 return MCIERR_UNRECOGNIZED_COMMAND
;