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
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(mciwave
)
26 int nUseCount
; /* Incremented for each shared open */
27 BOOL fShareable
; /* TRUE if first open was shareable */
28 WORD wNotifyDeviceID
;/* MCI device ID with a 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 volatile 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 */
38 HANDLE hEvent
; /* for synchronization */
39 DWORD dwEventCount
; /* for synchronization */
42 /* ===================================================================
43 * ===================================================================
44 * FIXME: should be using the new mmThreadXXXX functions from WINMM
46 * it would require to add a wine internal flag to mmThreadCreate
47 * in order to pass a 32 bit function instead of a 16 bit one
48 * ===================================================================
49 * =================================================================== */
59 /**************************************************************************
60 * MCI_SCAStarter [internal]
62 static DWORD CALLBACK
MCI_SCAStarter(LPVOID arg
)
64 struct SCA
* sca
= (struct SCA
*)arg
;
67 TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
68 sca
->wDevID
, sca
->wMsg
, sca
->dwParam1
, sca
->dwParam2
);
69 ret
= mciSendCommandA(sca
->wDevID
, sca
->wMsg
, sca
->dwParam1
| MCI_WAIT
, sca
->dwParam2
);
70 TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
71 sca
->wDevID
, sca
->wMsg
, sca
->dwParam1
, sca
->dwParam2
);
72 if (sca
->allocatedCopy
)
73 HeapFree(GetProcessHeap(), 0, (LPVOID
)sca
->dwParam2
);
74 HeapFree(GetProcessHeap(), 0, sca
);
76 WARN("Should not happen ? what's wrong \n");
77 /* should not go after this point */
81 /**************************************************************************
82 * MCI_SendCommandAsync [internal]
84 static DWORD
MCI_SendCommandAsync(UINT wDevID
, UINT wMsg
, DWORD dwParam1
,
85 DWORD dwParam2
, UINT size
)
87 struct SCA
* sca
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA
));
90 return MCIERR_OUT_OF_MEMORY
;
94 sca
->dwParam1
= dwParam1
;
97 sca
->dwParam2
= (DWORD
)HeapAlloc(GetProcessHeap(), 0, size
);
98 if (sca
->dwParam2
== 0) {
99 HeapFree(GetProcessHeap(), 0, sca
);
100 return MCIERR_OUT_OF_MEMORY
;
102 sca
->allocatedCopy
= TRUE
;
103 /* copy structure passed by program in dwParam2 to be sure
104 * we can still use it whatever the program does
106 memcpy((LPVOID
)sca
->dwParam2
, (LPVOID
)dwParam2
, size
);
108 sca
->dwParam2
= dwParam2
;
109 sca
->allocatedCopy
= FALSE
;
112 if (CreateThread(NULL
, 0, MCI_SCAStarter
, sca
, 0, NULL
) == 0) {
113 WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
114 return MCI_SCAStarter(&sca
);
119 /*======================================================================*
120 * MCI WAVE implemantation *
121 *======================================================================*/
123 static DWORD
WAVE_mciResume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
);
125 /**************************************************************************
126 * MCIWAVE_drvOpen [internal]
128 static DWORD
WAVE_drvOpen(LPSTR str
, LPMCI_OPEN_DRIVER_PARMSA modp
)
130 WINE_MCIWAVE
* wmw
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WINE_MCIWAVE
));
135 wmw
->wDevID
= modp
->wDeviceID
;
136 mciSetDriverData(wmw
->wDevID
, (DWORD
)wmw
);
137 modp
->wCustomCommandTable
= MCI_NO_COMMAND_TABLE
;
138 modp
->wType
= MCI_DEVTYPE_WAVEFORM_AUDIO
;
139 return modp
->wDeviceID
;
142 /**************************************************************************
143 * MCIWAVE_drvClose [internal]
145 static DWORD
WAVE_drvClose(DWORD dwDevID
)
147 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(dwDevID
);
150 HeapFree(GetProcessHeap(), 0, wmw
);
151 mciSetDriverData(dwDevID
, 0);
157 /**************************************************************************
158 * WAVE_mciGetOpenDev [internal]
160 static WINE_MCIWAVE
* WAVE_mciGetOpenDev(UINT wDevID
)
162 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(wDevID
);
164 if (wmw
== NULL
|| wmw
->nUseCount
== 0) {
165 WARN("Invalid wDevID=%u\n", wDevID
);
171 /**************************************************************************
172 * WAVE_ConvertByteToTimeFormat [internal]
174 static DWORD
WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE
* wmw
, DWORD val
, LPDWORD lpRet
)
178 switch (wmw
->dwMciTimeFormat
) {
179 case MCI_FORMAT_MILLISECONDS
:
180 ret
= (val
* 1000) / wmw
->lpWaveFormat
->nAvgBytesPerSec
;
182 case MCI_FORMAT_BYTES
:
185 case MCI_FORMAT_SAMPLES
: /* FIXME: is this correct ? */
186 ret
= (val
* 8) / wmw
->lpWaveFormat
->wBitsPerSample
;
189 WARN("Bad time format %lu!\n", wmw
->dwMciTimeFormat
);
191 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val
, val
, wmw
->dwMciTimeFormat
, ret
);
196 /**************************************************************************
197 * WAVE_ConvertTimeFormatToByte [internal]
199 static DWORD
WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE
* wmw
, DWORD val
)
203 switch (wmw
->dwMciTimeFormat
) {
204 case MCI_FORMAT_MILLISECONDS
:
205 ret
= (val
* wmw
->lpWaveFormat
->nAvgBytesPerSec
) / 1000;
207 case MCI_FORMAT_BYTES
:
210 case MCI_FORMAT_SAMPLES
: /* FIXME: is this correct ? */
211 ret
= (val
* wmw
->lpWaveFormat
->wBitsPerSample
) / 8;
214 WARN("Bad time format %lu!\n", wmw
->dwMciTimeFormat
);
216 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val
, val
, wmw
->dwMciTimeFormat
, ret
);
220 /**************************************************************************
221 * WAVE_mciReadFmt [internal]
223 static DWORD
WAVE_mciReadFmt(WINE_MCIWAVE
* wmw
, MMCKINFO
* pckMainRIFF
)
228 mmckInfo
.ckid
= mmioFOURCC('f', 'm', 't', ' ');
229 if (mmioDescend(wmw
->hFile
, &mmckInfo
, pckMainRIFF
, MMIO_FINDCHUNK
) != 0)
230 return MCIERR_INVALID_FILE
;
231 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
232 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
, mmckInfo
.cksize
);
234 wmw
->lpWaveFormat
= HeapAlloc(GetProcessHeap(), 0, mmckInfo
.cksize
);
235 r
= mmioRead(wmw
->hFile
, (HPSTR
)wmw
->lpWaveFormat
, mmckInfo
.cksize
);
236 if (r
< sizeof(WAVEFORMAT
))
237 return MCIERR_INVALID_FILE
;
239 TRACE("wFormatTag=%04X !\n", wmw
->lpWaveFormat
->wFormatTag
);
240 TRACE("nChannels=%d \n", wmw
->lpWaveFormat
->nChannels
);
241 TRACE("nSamplesPerSec=%ld\n", wmw
->lpWaveFormat
->nSamplesPerSec
);
242 TRACE("nAvgBytesPerSec=%ld\n", wmw
->lpWaveFormat
->nAvgBytesPerSec
);
243 TRACE("nBlockAlign=%d \n", wmw
->lpWaveFormat
->nBlockAlign
);
244 TRACE("wBitsPerSample=%u !\n", wmw
->lpWaveFormat
->wBitsPerSample
);
245 if (r
>= (long)sizeof(WAVEFORMATEX
))
246 TRACE("cbSize=%u !\n", wmw
->lpWaveFormat
->cbSize
);
248 mmioAscend(wmw
->hFile
, &mmckInfo
, 0);
249 mmckInfo
.ckid
= mmioFOURCC('d', 'a', 't', 'a');
250 if (mmioDescend(wmw
->hFile
, &mmckInfo
, pckMainRIFF
, MMIO_FINDCHUNK
) != 0) {
251 TRACE("can't find data chunk\n");
252 return MCIERR_INVALID_FILE
;
254 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
255 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
, mmckInfo
.cksize
);
256 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
257 wmw
->lpWaveFormat
->nChannels
, wmw
->lpWaveFormat
->nSamplesPerSec
);
258 wmw
->dwLength
= mmckInfo
.cksize
;
259 wmw
->dwFileOffset
= mmckInfo
.dwDataOffset
;
263 /**************************************************************************
264 * WAVE_mciOpen [internal]
266 static DWORD
WAVE_mciOpen(UINT wDevID
, DWORD dwFlags
, LPMCI_WAVE_OPEN_PARMSA lpOpenParms
)
270 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)mciGetDriverData(wDevID
);
272 TRACE("(%04X, %08lX, %p)\n", wDevID
, dwFlags
, lpOpenParms
);
273 if (lpOpenParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
274 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
276 if (dwFlags
& MCI_OPEN_SHAREABLE
)
277 return MCIERR_HARDWARE
;
279 if (wmw
->nUseCount
> 0) {
280 /* The driver is already opened on this channel
281 * Wave driver cannot be shared
283 return MCIERR_DEVICE_OPEN
;
287 dwDeviceID
= lpOpenParms
->wDeviceID
;
292 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID
, dwDeviceID
);
294 if (dwFlags
& MCI_OPEN_ELEMENT
) {
295 if (dwFlags
& MCI_OPEN_ELEMENT_ID
) {
296 /* could it be that (DWORD)lpOpenParms->lpstrElementName
297 * contains the hFile value ?
299 dwRet
= MCIERR_UNRECOGNIZED_COMMAND
;
301 LPCSTR lpstrElementName
= lpOpenParms
->lpstrElementName
;
303 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
304 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName
);
305 if (lpstrElementName
&& (strlen(lpstrElementName
) > 0)) {
306 wmw
->hFile
= mmioOpenA((LPSTR
)lpstrElementName
, NULL
,
307 MMIO_ALLOCBUF
| MMIO_READ
| MMIO_DENYWRITE
);
308 if (wmw
->hFile
== 0) {
309 WARN("can't find file='%s' !\n", lpstrElementName
);
310 dwRet
= MCIERR_FILE_NOT_FOUND
;
317 TRACE("hFile=%u\n", wmw
->hFile
);
319 memcpy(&wmw
->openParms
, lpOpenParms
, sizeof(MCI_WAVE_OPEN_PARMSA
));
320 wmw
->wNotifyDeviceID
= dwDeviceID
;
321 wmw
->dwStatus
= MCI_MODE_NOT_READY
; /* while loading file contents */
323 if (dwRet
== 0 && wmw
->hFile
!= 0) {
326 if (mmioDescend(wmw
->hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
327 dwRet
= MCIERR_INVALID_FILE
;
329 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
330 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
, ckMainRIFF
.cksize
);
331 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
332 (ckMainRIFF
.fccType
!= mmioFOURCC('W', 'A', 'V', 'E'))) {
333 dwRet
= MCIERR_INVALID_FILE
;
335 dwRet
= WAVE_mciReadFmt(wmw
, &ckMainRIFF
);
342 if (wmw
->lpWaveFormat
) {
343 switch (wmw
->lpWaveFormat
->wFormatTag
) {
344 case WAVE_FORMAT_PCM
:
345 if (wmw
->lpWaveFormat
->nAvgBytesPerSec
!=
346 wmw
->lpWaveFormat
->nSamplesPerSec
* wmw
->lpWaveFormat
->nBlockAlign
) {
347 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
348 wmw
->lpWaveFormat
->nAvgBytesPerSec
,
349 wmw
->lpWaveFormat
->nSamplesPerSec
*
350 wmw
->lpWaveFormat
->nBlockAlign
);
351 wmw
->lpWaveFormat
->nAvgBytesPerSec
=
352 wmw
->lpWaveFormat
->nSamplesPerSec
*
353 wmw
->lpWaveFormat
->nBlockAlign
;
360 wmw
->dwStatus
= MCI_MODE_STOP
;
364 mmioClose(wmw
->hFile
, 0);
370 /**************************************************************************
371 * WAVE_mciCue [internal]
373 static DWORD
WAVE_mciCue(UINT wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
378 This routine is far from complete. At the moment only a check is done on the
379 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
382 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
387 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
389 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID
, dwParam
, lpParms
);
391 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
393 /* always close elements ? */
394 if (wmw
->hFile
!= 0) {
395 mmioClose(wmw
->hFile
, 0);
399 dwRet
= MMSYSERR_NOERROR
; /* assume success */
401 if ((dwParam
& MCI_WAVE_INPUT
) && !wmw
->fInput
) {
402 dwRet
= waveOutClose(wmw
->hWave
);
403 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
405 } else if (wmw
->fInput
) {
406 dwRet
= waveInClose(wmw
->hWave
);
407 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
411 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
414 /**************************************************************************
415 * WAVE_mciStop [internal]
417 static DWORD
WAVE_mciStop(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
420 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
422 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
424 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
426 /* wait for playback thread (if any) to exit before processing further */
427 switch (wmw
->dwStatus
) {
430 case MCI_MODE_RECORD
:
432 int oldStat
= wmw
->dwStatus
;
433 wmw
->dwStatus
= MCI_MODE_NOT_READY
;
434 if (oldStat
== MCI_MODE_PAUSE
)
435 dwRet
= (wmw
->fInput
) ? waveInReset(wmw
->hWave
) : waveOutReset(wmw
->hWave
);
437 while (wmw
->dwStatus
!= MCI_MODE_STOP
)
445 wmw
->dwStatus
= MCI_MODE_STOP
;
447 if ((dwFlags
& MCI_NOTIFY
) && lpParms
) {
448 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
449 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
455 /**************************************************************************
456 * WAVE_mciClose [internal]
458 static DWORD
WAVE_mciClose(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
461 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
463 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
465 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
467 if (wmw
->dwStatus
!= MCI_MODE_STOP
) {
468 dwRet
= WAVE_mciStop(wDevID
, MCI_WAIT
, lpParms
);
473 if (wmw
->nUseCount
== 0) {
474 if (wmw
->hFile
!= 0) {
475 mmioClose(wmw
->hFile
, 0);
480 HeapFree(GetProcessHeap(), 0, wmw
->lpWaveFormat
);
481 wmw
->lpWaveFormat
= NULL
;
483 if ((dwFlags
& MCI_NOTIFY
) && lpParms
) {
484 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
485 wmw
->wNotifyDeviceID
,
486 (dwRet
== 0) ? MCI_NOTIFY_SUCCESSFUL
: MCI_NOTIFY_FAILURE
);
492 /**************************************************************************
493 * WAVE_mciPlayCallback [internal]
495 static void CALLBACK
WAVE_mciPlayCallback(HWAVEOUT hwo
, UINT uMsg
,
497 DWORD dwParam1
, DWORD dwParam2
)
499 WINE_MCIWAVE
* wmw
= (WINE_MCIWAVE
*)dwInstance
;
506 InterlockedIncrement(&wmw
->dwEventCount
);
507 TRACE("Returning waveHdr=%lx\n", dwParam1
);
508 SetEvent(wmw
->hEvent
);
511 ERR("Unknown uMsg=%d\n", uMsg
);
515 static void WAVE_mciPlayWaitDone(WINE_MCIWAVE
* wmw
)
518 ResetEvent(wmw
->hEvent
);
519 if (InterlockedDecrement(&wmw
->dwEventCount
) >= 0) {
522 InterlockedIncrement(&wmw
->dwEventCount
);
524 WaitForSingleObject(wmw
->hEvent
, INFINITE
);
528 /**************************************************************************
529 * WAVE_mciPlay [internal]
531 static DWORD
WAVE_mciPlay(UINT wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
534 LONG bufsize
, count
, left
;
536 LPWAVEHDR waveHdr
= NULL
;
537 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
540 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
542 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
543 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
546 WARN("cannot play on input device\n");
547 return MCIERR_NONAPPLICABLE_FUNCTION
;
550 if (wmw
->hFile
== 0) {
551 WARN("Can't play: no file='%s' !\n", wmw
->openParms
.lpstrElementName
);
552 return MCIERR_FILE_NOT_FOUND
;
555 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
556 /* FIXME: parameters (start/end) in lpParams may not be used */
557 return WAVE_mciResume(wDevID
, dwFlags
, (LPMCI_GENERIC_PARMS
)lpParms
);
560 /** This function will be called again by a thread when async is used.
561 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
562 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
564 if ((wmw
->dwStatus
!= MCI_MODE_STOP
) && ((wmw
->dwStatus
!= MCI_MODE_PLAY
) && (dwFlags
& MCI_WAIT
))) {
565 return MCIERR_INTERNAL
;
568 wmw
->dwStatus
= MCI_MODE_PLAY
;
570 if (!(dwFlags
& MCI_WAIT
)) {
571 return MCI_SendCommandAsync(wmw
->wNotifyDeviceID
, MCI_PLAY
, dwFlags
,
572 (DWORD
)lpParms
, sizeof(MCI_PLAY_PARMS
));
576 if (lpParms
&& (dwFlags
& MCI_FROM
)) {
577 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwFrom
);
579 if (lpParms
&& (dwFlags
& MCI_TO
)) {
580 end
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
583 TRACE("Playing from byte=%lu to byte=%lu\n", wmw
->dwPosition
, end
);
585 if (end
<= wmw
->dwPosition
)
588 #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
589 ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
591 wmw
->dwPosition
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->dwPosition
);
592 wmw
->dwLength
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->dwLength
);
593 /* go back to begining of chunk plus the requested position */
594 /* FIXME: I'm not sure this is correct, notably because some data linked to
595 * the decompression state machine will not be correcly initialized.
596 * try it this way (other way would be to decompress from 0 up to dwPosition
597 * and to start sending to hWave when dwPosition is reached)
599 mmioSeek(wmw
->hFile
, wmw
->dwFileOffset
+ wmw
->dwPosition
, SEEK_SET
); /* >= 0 */
601 /* By default the device will be opened for output, the MCI_CUE function is there to
602 * change from output to input and back
604 /* FIXME: how to choose between several output channels ? here mapper is forced */
605 dwRet
= waveOutOpen(&wmw
->hWave
, WAVE_MAPPER
, wmw
->lpWaveFormat
,
606 (DWORD
)WAVE_mciPlayCallback
, (DWORD
)wmw
, CALLBACK_FUNCTION
);
609 TRACE("Can't open low level audio device %ld\n", dwRet
);
610 dwRet
= MCIERR_DEVICE_OPEN
;
615 /* make it so that 3 buffers per second are needed */
616 bufsize
= WAVE_ALIGN_ON_BLOCK(wmw
, wmw
->lpWaveFormat
->nAvgBytesPerSec
/ 3);
618 waveHdr
= HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR
) + 2 * bufsize
);
619 waveHdr
[0].lpData
= (char*)waveHdr
+ 2 * sizeof(WAVEHDR
);
620 waveHdr
[1].lpData
= (char*)waveHdr
+ 2 * sizeof(WAVEHDR
) + bufsize
;
621 waveHdr
[0].dwUser
= waveHdr
[1].dwUser
= 0L;
622 waveHdr
[0].dwLoops
= waveHdr
[1].dwLoops
= 0L;
623 waveHdr
[0].dwFlags
= waveHdr
[1].dwFlags
= 0L;
624 waveHdr
[0].dwBufferLength
= waveHdr
[1].dwBufferLength
= bufsize
;
625 if (waveOutPrepareHeader(wmw
->hWave
, &waveHdr
[0], sizeof(WAVEHDR
)) ||
626 waveOutPrepareHeader(wmw
->hWave
, &waveHdr
[1], sizeof(WAVEHDR
))) {
627 dwRet
= MCIERR_INTERNAL
;
632 left
= min(wmw
->dwLength
, end
- wmw
->dwPosition
);
633 wmw
->hEvent
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
634 wmw
->dwEventCount
= 1L; /* for first buffer */
636 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw
->dwPosition
, left
);
638 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
639 while (left
> 0 && wmw
->dwStatus
!= MCI_MODE_STOP
&& wmw
->dwStatus
!= MCI_MODE_NOT_READY
) {
640 count
= mmioRead(wmw
->hFile
, waveHdr
[whidx
].lpData
, min(bufsize
, left
));
641 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize
, count
);
644 /* count is always <= bufsize, so this is correct regarding the
645 * waveOutPrepareHeader function
647 waveHdr
[whidx
].dwBufferLength
= count
;
648 waveHdr
[whidx
].dwFlags
&= ~WHDR_DONE
;
649 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
650 &waveHdr
[whidx
], waveHdr
[whidx
].dwBufferLength
,
651 waveHdr
[whidx
].dwBytesRecorded
);
652 dwRet
= waveOutWrite(wmw
->hWave
, &waveHdr
[whidx
], sizeof(WAVEHDR
));
654 wmw
->dwPosition
+= count
;
655 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw
->dwPosition
);
657 WAVE_mciPlayWaitDone(wmw
);
661 WAVE_mciPlayWaitDone(wmw
); /* to balance first buffer */
663 /* just to get rid of some race conditions between play, stop and pause */
664 waveOutReset(wmw
->hWave
);
666 waveOutUnprepareHeader(wmw
->hWave
, &waveHdr
[0], sizeof(WAVEHDR
));
667 waveOutUnprepareHeader(wmw
->hWave
, &waveHdr
[1], sizeof(WAVEHDR
));
672 HeapFree(GetProcessHeap(), 0, waveHdr
);
675 waveOutClose(wmw
->hWave
);
678 CloseHandle(wmw
->hEvent
);
680 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
681 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
682 wmw
->wNotifyDeviceID
,
683 dwRet
? MCI_NOTIFY_FAILURE
: MCI_NOTIFY_SUCCESSFUL
);
686 wmw
->dwStatus
= MCI_MODE_STOP
;
691 /**************************************************************************
692 * WAVE_mciRecord [internal]
694 static DWORD
WAVE_mciRecord(UINT wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
700 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
702 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
704 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
705 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
708 WARN("cannot record on output device\n");
709 return MCIERR_NONAPPLICABLE_FUNCTION
;
712 if (wmw
->hFile
== 0) {
713 WARN("can't find file='%s' !\n",
714 wmw
->openParms
.lpstrElementName
);
715 return MCIERR_FILE_NOT_FOUND
;
717 start
= 1; end
= 99999;
718 if (dwFlags
& MCI_FROM
) {
719 start
= lpParms
->dwFrom
;
720 TRACE("MCI_FROM=%d \n", start
);
722 if (dwFlags
& MCI_TO
) {
724 TRACE("MCI_TO=%d \n", end
);
727 waveHdr
.lpData
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
728 waveHdr
.dwBufferLength
= bufsize
;
730 waveHdr
.dwFlags
= 0L;
731 waveHdr
.dwLoops
= 0L;
732 dwRet
= waveInPrepareHeader(wmw
->hWave
, &waveHdr
, sizeof(WAVEHDR
));
734 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
735 waveHdr
.dwBytesRecorded
= 0;
736 dwRet
= waveInStart(wmw
->hWave
);
737 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
738 &waveHdr
, waveHdr
.dwBytesRecorded
);
739 if (waveHdr
.dwBytesRecorded
== 0) break;
741 dwRet
= waveInUnprepareHeader(wmw
->hWave
, &waveHdr
, sizeof(WAVEHDR
));
742 HeapFree(GetProcessHeap(), 0, waveHdr
.lpData
);
744 if (dwFlags
& MCI_NOTIFY
) {
745 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
746 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
751 /**************************************************************************
752 * WAVE_mciPause [internal]
754 static DWORD
WAVE_mciPause(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
757 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
759 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
761 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
762 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
764 if (wmw
->dwStatus
== MCI_MODE_PLAY
) {
765 wmw
->dwStatus
= MCI_MODE_PAUSE
;
768 if (wmw
->fInput
) dwRet
= waveInStop(wmw
->hWave
);
769 else dwRet
= waveOutPause(wmw
->hWave
);
771 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
774 /**************************************************************************
775 * WAVE_mciResume [internal]
777 static DWORD
WAVE_mciResume(UINT wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
779 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
782 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
784 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
786 if (wmw
->dwStatus
== MCI_MODE_PAUSE
) {
787 wmw
->dwStatus
= MCI_MODE_PLAY
;
790 if (wmw
->fInput
) dwRet
= waveInStart(wmw
->hWave
);
791 else dwRet
= waveOutRestart(wmw
->hWave
);
792 return (dwRet
== MMSYSERR_NOERROR
) ? 0 : MCIERR_INTERNAL
;
795 /**************************************************************************
796 * WAVE_mciSeek [internal]
798 static DWORD
WAVE_mciSeek(UINT wDevID
, DWORD dwFlags
, LPMCI_SEEK_PARMS lpParms
)
801 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
803 TRACE("(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
805 if (lpParms
== NULL
) {
806 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
807 } else if (wmw
== NULL
) {
808 ret
= MCIERR_INVALID_DEVICE_ID
;
810 WAVE_mciStop(wDevID
, MCI_WAIT
, 0);
812 if (dwFlags
& MCI_SEEK_TO_START
) {
814 } else if (dwFlags
& MCI_SEEK_TO_END
) {
815 wmw
->dwPosition
= wmw
->dwLength
;
816 } else if (dwFlags
& MCI_TO
) {
817 wmw
->dwPosition
= WAVE_ConvertTimeFormatToByte(wmw
, lpParms
->dwTo
);
819 WARN("dwFlag doesn't tell where to seek to...\n");
820 return MCIERR_MISSING_PARAMETER
;
823 TRACE("Seeking to position=%lu bytes\n", wmw
->dwPosition
);
825 if (dwFlags
& MCI_NOTIFY
) {
826 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
827 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
833 /**************************************************************************
834 * WAVE_mciSet [internal]
836 static DWORD
WAVE_mciSet(UINT wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
838 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
840 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
842 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
843 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
845 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
846 switch (lpParms
->dwTimeFormat
) {
847 case MCI_FORMAT_MILLISECONDS
:
848 TRACE("MCI_FORMAT_MILLISECONDS !\n");
849 wmw
->dwMciTimeFormat
= MCI_FORMAT_MILLISECONDS
;
851 case MCI_FORMAT_BYTES
:
852 TRACE("MCI_FORMAT_BYTES !\n");
853 wmw
->dwMciTimeFormat
= MCI_FORMAT_BYTES
;
855 case MCI_FORMAT_SAMPLES
:
856 TRACE("MCI_FORMAT_SAMPLES !\n");
857 wmw
->dwMciTimeFormat
= MCI_FORMAT_SAMPLES
;
860 WARN("Bad time format %lu!\n", lpParms
->dwTimeFormat
);
861 return MCIERR_BAD_TIME_FORMAT
;
864 if (dwFlags
& MCI_SET_VIDEO
) {
865 TRACE("No support for video !\n");
866 return MCIERR_UNSUPPORTED_FUNCTION
;
868 if (dwFlags
& MCI_SET_DOOR_OPEN
) {
869 TRACE("No support for door open !\n");
870 return MCIERR_UNSUPPORTED_FUNCTION
;
872 if (dwFlags
& MCI_SET_DOOR_CLOSED
) {
873 TRACE("No support for door close !\n");
874 return MCIERR_UNSUPPORTED_FUNCTION
;
876 if (dwFlags
& MCI_SET_AUDIO
) {
877 if (dwFlags
& MCI_SET_ON
) {
878 TRACE("MCI_SET_ON audio !\n");
879 } else if (dwFlags
& MCI_SET_OFF
) {
880 TRACE("MCI_SET_OFF audio !\n");
882 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
883 return MCIERR_BAD_INTEGER
;
886 if (lpParms
->dwAudio
& MCI_SET_AUDIO_ALL
)
887 TRACE("MCI_SET_AUDIO_ALL !\n");
888 if (lpParms
->dwAudio
& MCI_SET_AUDIO_LEFT
)
889 TRACE("MCI_SET_AUDIO_LEFT !\n");
890 if (lpParms
->dwAudio
& MCI_SET_AUDIO_RIGHT
)
891 TRACE("MCI_SET_AUDIO_RIGHT !\n");
893 if (dwFlags
& MCI_WAVE_INPUT
)
894 TRACE("MCI_WAVE_INPUT !\n");
895 if (dwFlags
& MCI_WAVE_OUTPUT
)
896 TRACE("MCI_WAVE_OUTPUT !\n");
897 if (dwFlags
& MCI_WAVE_SET_ANYINPUT
)
898 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
899 if (dwFlags
& MCI_WAVE_SET_ANYOUTPUT
)
900 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
901 if (dwFlags
& MCI_WAVE_SET_AVGBYTESPERSEC
)
902 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
903 if (dwFlags
& MCI_WAVE_SET_BITSPERSAMPLE
)
904 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
905 if (dwFlags
& MCI_WAVE_SET_BLOCKALIGN
)
906 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
907 if (dwFlags
& MCI_WAVE_SET_CHANNELS
)
908 TRACE("MCI_WAVE_SET_CHANNELS !\n");
909 if (dwFlags
& MCI_WAVE_SET_FORMATTAG
)
910 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
911 if (dwFlags
& MCI_WAVE_SET_SAMPLESPERSEC
)
912 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
916 /**************************************************************************
917 * WAVE_mciStatus [internal]
919 static DWORD
WAVE_mciStatus(UINT wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
921 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
924 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
925 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
926 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
928 if (dwFlags
& MCI_STATUS_ITEM
) {
929 switch (lpParms
->dwItem
) {
930 case MCI_STATUS_CURRENT_TRACK
:
931 lpParms
->dwReturn
= 1;
932 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms
->dwReturn
);
934 case MCI_STATUS_LENGTH
:
936 lpParms
->dwReturn
= 0;
937 return MCIERR_UNSUPPORTED_FUNCTION
;
939 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
940 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
, wmw
->dwLength
, &ret
);
941 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms
->dwReturn
);
943 case MCI_STATUS_MODE
:
944 TRACE("MCI_STATUS_MODE => %u\n", wmw
->dwStatus
);
945 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwStatus
, wmw
->dwStatus
);
946 ret
= MCI_RESOURCE_RETURNED
;
948 case MCI_STATUS_MEDIA_PRESENT
:
949 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
950 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
951 ret
= MCI_RESOURCE_RETURNED
;
953 case MCI_STATUS_NUMBER_OF_TRACKS
:
954 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
955 lpParms
->dwReturn
= 1;
956 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms
->dwReturn
);
958 case MCI_STATUS_POSITION
:
960 lpParms
->dwReturn
= 0;
961 return MCIERR_UNSUPPORTED_FUNCTION
;
963 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
964 lpParms
->dwReturn
= WAVE_ConvertByteToTimeFormat(wmw
,
965 (dwFlags
& MCI_STATUS_START
) ? 0 : wmw
->dwPosition
,
967 TRACE("MCI_STATUS_POSITION %s => %lu\n",
968 (dwFlags
& MCI_STATUS_START
) ? "start" : "current", lpParms
->dwReturn
);
970 case MCI_STATUS_READY
:
971 lpParms
->dwReturn
= (wmw
->dwStatus
== MCI_MODE_NOT_READY
) ?
972 MAKEMCIRESOURCE(FALSE
, MCI_FALSE
) : MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
973 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms
->dwReturn
));
974 ret
= MCI_RESOURCE_RETURNED
;
976 case MCI_STATUS_TIME_FORMAT
:
977 lpParms
->dwReturn
= MAKEMCIRESOURCE(wmw
->dwMciTimeFormat
, wmw
->dwMciTimeFormat
);
978 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms
->dwReturn
);
979 ret
= MCI_RESOURCE_RETURNED
;
982 TRACE("MCI_WAVE_INPUT !\n");
983 lpParms
->dwReturn
= 0;
984 ret
= MCIERR_WAVE_INPUTUNSPECIFIED
;
986 case MCI_WAVE_OUTPUT
:
987 TRACE("MCI_WAVE_OUTPUT !\n");
990 if (waveOutGetID(wmw
->hWave
, &id
) == MMSYSERR_NOERROR
) {
991 lpParms
->dwReturn
= id
;
993 lpParms
->dwReturn
= 0;
994 ret
= MCIERR_WAVE_INPUTUNSPECIFIED
;
998 case MCI_WAVE_STATUS_AVGBYTESPERSEC
:
1000 lpParms
->dwReturn
= 0;
1001 return MCIERR_UNSUPPORTED_FUNCTION
;
1003 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nAvgBytesPerSec
;
1004 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms
->dwReturn
);
1006 case MCI_WAVE_STATUS_BITSPERSAMPLE
:
1008 lpParms
->dwReturn
= 0;
1009 return MCIERR_UNSUPPORTED_FUNCTION
;
1011 lpParms
->dwReturn
= wmw
->lpWaveFormat
->wBitsPerSample
;
1012 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms
->dwReturn
);
1014 case MCI_WAVE_STATUS_BLOCKALIGN
:
1016 lpParms
->dwReturn
= 0;
1017 return MCIERR_UNSUPPORTED_FUNCTION
;
1019 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nBlockAlign
;
1020 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms
->dwReturn
);
1022 case MCI_WAVE_STATUS_CHANNELS
:
1024 lpParms
->dwReturn
= 0;
1025 return MCIERR_UNSUPPORTED_FUNCTION
;
1027 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nChannels
;
1028 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms
->dwReturn
);
1030 case MCI_WAVE_STATUS_FORMATTAG
:
1032 lpParms
->dwReturn
= 0;
1033 return MCIERR_UNSUPPORTED_FUNCTION
;
1035 lpParms
->dwReturn
= wmw
->lpWaveFormat
->wFormatTag
;
1036 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms
->dwReturn
);
1038 case MCI_WAVE_STATUS_LEVEL
:
1039 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1040 lpParms
->dwReturn
= 0xAAAA5555;
1042 case MCI_WAVE_STATUS_SAMPLESPERSEC
:
1044 lpParms
->dwReturn
= 0;
1045 return MCIERR_UNSUPPORTED_FUNCTION
;
1047 lpParms
->dwReturn
= wmw
->lpWaveFormat
->nSamplesPerSec
;
1048 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms
->dwReturn
);
1051 WARN("unknown command %08lX !\n", lpParms
->dwItem
);
1052 return MCIERR_UNRECOGNIZED_COMMAND
;
1055 if (dwFlags
& MCI_NOTIFY
) {
1056 mciDriverNotify((HWND
)LOWORD(lpParms
->dwCallback
),
1057 wmw
->wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
1062 /**************************************************************************
1063 * WAVE_mciGetDevCaps [internal]
1065 static DWORD
WAVE_mciGetDevCaps(UINT wDevID
, DWORD dwFlags
,
1066 LPMCI_GETDEVCAPS_PARMS lpParms
)
1068 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
1071 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1073 if (lpParms
== NULL
) return MCIERR_NULL_PARAMETER_BLOCK
;
1074 if (wmw
== NULL
) return MCIERR_INVALID_DEVICE_ID
;
1076 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
1077 switch(lpParms
->dwItem
) {
1078 case MCI_GETDEVCAPS_DEVICE_TYPE
:
1079 lpParms
->dwReturn
= MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO
, MCI_DEVTYPE_WAVEFORM_AUDIO
);
1080 ret
= MCI_RESOURCE_RETURNED
;
1082 case MCI_GETDEVCAPS_HAS_AUDIO
:
1083 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1084 ret
= MCI_RESOURCE_RETURNED
;
1086 case MCI_GETDEVCAPS_HAS_VIDEO
:
1087 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
1088 ret
= MCI_RESOURCE_RETURNED
;
1090 case MCI_GETDEVCAPS_USES_FILES
:
1091 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1092 ret
= MCI_RESOURCE_RETURNED
;
1094 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
1095 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1096 ret
= MCI_RESOURCE_RETURNED
;
1098 case MCI_GETDEVCAPS_CAN_RECORD
:
1099 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1100 ret
= MCI_RESOURCE_RETURNED
;
1102 case MCI_GETDEVCAPS_CAN_EJECT
:
1103 lpParms
->dwReturn
= MAKEMCIRESOURCE(FALSE
, MCI_FALSE
);
1104 ret
= MCI_RESOURCE_RETURNED
;
1106 case MCI_GETDEVCAPS_CAN_PLAY
:
1107 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1108 ret
= MCI_RESOURCE_RETURNED
;
1110 case MCI_GETDEVCAPS_CAN_SAVE
:
1111 lpParms
->dwReturn
= MAKEMCIRESOURCE(TRUE
, MCI_TRUE
);
1112 ret
= MCI_RESOURCE_RETURNED
;
1114 case MCI_WAVE_GETDEVCAPS_INPUTS
:
1115 lpParms
->dwReturn
= 1;
1117 case MCI_WAVE_GETDEVCAPS_OUTPUTS
:
1118 lpParms
->dwReturn
= 1;
1121 FIXME("Unknown capability (%08lx) !\n", lpParms
->dwItem
);
1122 return MCIERR_UNRECOGNIZED_COMMAND
;
1125 WARN("No GetDevCaps-Item !\n");
1126 return MCIERR_UNRECOGNIZED_COMMAND
;
1131 /**************************************************************************
1132 * WAVE_mciInfo [internal]
1134 static DWORD
WAVE_mciInfo(UINT wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMSA lpParms
)
1138 WINE_MCIWAVE
* wmw
= WAVE_mciGetOpenDev(wDevID
);
1140 TRACE("(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1142 if (lpParms
== NULL
|| lpParms
->lpstrReturn
== NULL
) {
1143 ret
= MCIERR_NULL_PARAMETER_BLOCK
;
1144 } else if (wmw
== NULL
) {
1145 ret
= MCIERR_INVALID_DEVICE_ID
;
1147 TRACE("buf=%p, len=%lu\n", lpParms
->lpstrReturn
, lpParms
->dwRetSize
);
1149 switch (dwFlags
& ~(MCI_WAIT
|MCI_NOTIFY
)) {
1150 case MCI_INFO_PRODUCT
:
1151 str
= "Wine's audio player";
1154 str
= wmw
->openParms
.lpstrElementName
;
1156 case MCI_WAVE_INPUT
:
1157 str
= "Wine Wave In";
1159 case MCI_WAVE_OUTPUT
:
1160 str
= "Wine Wave Out";
1163 WARN("Don't know this info command (%lu)\n", dwFlags
);
1164 ret
= MCIERR_UNRECOGNIZED_COMMAND
;
1168 if (strlen(str
) + 1 > lpParms
->dwRetSize
) {
1169 ret
= MCIERR_PARAM_OVERFLOW
;
1171 lstrcpynA(lpParms
->lpstrReturn
, str
, lpParms
->dwRetSize
);
1174 lpParms
->lpstrReturn
[0] = 0;
1180 /**************************************************************************
1181 * MCIWAVE_DriverProc [sample driver]
1183 LONG CALLBACK
MCIWAVE_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
1184 DWORD dwParam1
, DWORD dwParam2
)
1186 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1187 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1190 case DRV_LOAD
: return 1;
1191 case DRV_FREE
: return 1;
1192 case DRV_OPEN
: return WAVE_drvOpen((LPSTR
)dwParam1
, (LPMCI_OPEN_DRIVER_PARMSA
)dwParam2
);
1193 case DRV_CLOSE
: return WAVE_drvClose(dwDevID
);
1194 case DRV_ENABLE
: return 1;
1195 case DRV_DISABLE
: return 1;
1196 case DRV_QUERYCONFIGURE
: return 1;
1197 case DRV_CONFIGURE
: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK
); return 1;
1198 case DRV_INSTALL
: return DRVCNF_RESTART
;
1199 case DRV_REMOVE
: return DRVCNF_RESTART
;
1200 case MCI_OPEN_DRIVER
: return WAVE_mciOpen (dwDevID
, dwParam1
, (LPMCI_WAVE_OPEN_PARMSA
) dwParam2
);
1201 case MCI_CLOSE_DRIVER
: return WAVE_mciClose (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1202 case MCI_CUE
: return WAVE_mciCue (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1203 case MCI_PLAY
: return WAVE_mciPlay (dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
) dwParam2
);
1204 case MCI_RECORD
: return WAVE_mciRecord (dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
) dwParam2
);
1205 case MCI_STOP
: return WAVE_mciStop (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1206 case MCI_SET
: return WAVE_mciSet (dwDevID
, dwParam1
, (LPMCI_SET_PARMS
) dwParam2
);
1207 case MCI_PAUSE
: return WAVE_mciPause (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1208 case MCI_RESUME
: return WAVE_mciResume (dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
) dwParam2
);
1209 case MCI_STATUS
: return WAVE_mciStatus (dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
) dwParam2
);
1210 case MCI_GETDEVCAPS
: return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
) dwParam2
);
1211 case MCI_INFO
: return WAVE_mciInfo (dwDevID
, dwParam1
, (LPMCI_INFO_PARMSA
) dwParam2
);
1212 case MCI_SEEK
: return WAVE_mciSeek (dwDevID
, dwParam1
, (LPMCI_SEEK_PARMS
) dwParam2
);
1213 /* commands that should be supported */
1229 FIXME("Unsupported yet command [%lu]\n", wMsg
);
1232 TRACE("Unsupported command [%lu]\n", wMsg
);
1236 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1239 FIXME("is probably wrong msg [%lu]\n", wMsg
);
1240 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1242 return MCIERR_UNRECOGNIZED_COMMAND
;