1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
21 #include <sys/ioctl.h>
29 #include "multimedia.h"
31 #define MAX_MCIWAVEDRV (1)
34 int nUseCount; /* Incremented for each shared open */
35 BOOL16 fShareable; /* TRUE if first open was shareable */
36 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
37 HANDLE16 hCallback; /* Callback handle for pending notification */
38 HMMIO32 hFile; /* mmio file handle open as Element */
39 MCI_WAVE_OPEN_PARMS32A openParms;
40 WAVEOPENDESC waveDesc;
41 PCMWAVEFORMAT WaveFormat;
43 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
44 WORD dwStatus; /* one from MCI_MODE_xxxx */
45 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
46 DWORD dwFileOffset; /* Offset of chunk in mmio file */
47 DWORD dwLength; /* number of bytes in chunk for playing */
48 DWORD dwPosition; /* position in bytes in chunk for playing */
51 static WINE_MCIWAVE MCIWaveDev[MAX_MCIWAVEDRV];
53 /*======================================================================*
54 * MCI WAVE implemantation *
55 *======================================================================*/
57 /**************************************************************************
58 * WAVE_mciGetOpenDev [internal]
60 static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT16 wDevID)
62 if (wDevID >= MAX_MCIWAVEDRV || MCIWaveDev[wDevID].nUseCount == 0) {
63 WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
66 return &MCIWaveDev[wDevID];
69 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val)
73 switch (wmw->dwMciTimeFormat) {
74 case MCI_FORMAT_MILLISECONDS:
75 ret = (val * 1000) / wmw->WaveFormat.wf.nAvgBytesPerSec;
77 case MCI_FORMAT_BYTES:
80 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
81 ret = (val * 8) / wmw->WaveFormat.wBitsPerSample;
84 WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
86 TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
90 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
94 switch (wmw->dwMciTimeFormat) {
95 case MCI_FORMAT_MILLISECONDS:
96 ret = (val * wmw->WaveFormat.wf.nAvgBytesPerSec) / 1000;
98 case MCI_FORMAT_BYTES:
101 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
102 ret = (val * wmw->WaveFormat.wBitsPerSample) / 8;
105 WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
107 TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
111 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
115 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
116 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
117 return MCIERR_INVALID_FILE;
118 TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
119 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
120 if (mmioRead32(wmw->hFile, (HPSTR)&wmw->WaveFormat,
121 (long)sizeof(PCMWAVEFORMAT)) != (long)sizeof(PCMWAVEFORMAT))
122 return MCIERR_INVALID_FILE;
124 TRACE(mciwave, "wFormatTag=%04X !\n", wmw->WaveFormat.wf.wFormatTag);
125 TRACE(mciwave, "nChannels=%d \n", wmw->WaveFormat.wf.nChannels);
126 TRACE(mciwave, "nSamplesPerSec=%ld\n", wmw->WaveFormat.wf.nSamplesPerSec);
127 TRACE(mciwave, "nAvgBytesPerSec=%ld\n", wmw->WaveFormat.wf.nAvgBytesPerSec);
128 TRACE(mciwave, "nBlockAlign=%d \n", wmw->WaveFormat.wf.nBlockAlign);
129 TRACE(mciwave, "wBitsPerSample=%u !\n", wmw->WaveFormat.wBitsPerSample);
130 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
131 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
132 return MCIERR_INVALID_FILE;
133 TRACE(mciwave,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
134 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
135 TRACE(mciwave, "nChannels=%d nSamplesPerSec=%ld\n",
136 wmw->WaveFormat.wf.nChannels, wmw->WaveFormat.wf.nSamplesPerSec);
137 wmw->dwLength = mmckInfo.cksize;
138 wmw->dwFileOffset = mmioSeek32(wmw->hFile, 0, SEEK_CUR); /* >= 0 */
142 /**************************************************************************
143 * WAVE_mciOpen [internal]
145 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS32A lpOpenParms)
151 TRACE(mciwave,"(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
152 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
154 if (wDevID >= MAX_MCIWAVEDRV) {
155 WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
156 return MCIERR_INVALID_DEVICE_ID;
159 wmw = &MCIWaveDev[wDevID];
161 if (wmw->nUseCount > 0) {
162 /* The driver already open on this channel */
163 /* If the driver was opened shareable before and this open specifies */
164 /* shareable then increment the use count */
165 if (wmw->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
168 return MCIERR_MUST_USE_SHAREABLE;
171 wmw->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
174 dwDeviceID = lpOpenParms->wDeviceID;
178 TRACE(mciwave, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
180 if (dwFlags & MCI_OPEN_ELEMENT) {
181 LPCSTR lpstrElementName;
183 lpstrElementName = lpOpenParms->lpstrElementName;
185 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
186 TRACE(mciwave,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
187 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
188 wmw->hFile = mmioOpen32A(lpstrElementName, NULL,
189 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
190 if (wmw->hFile == 0) {
191 WARN(mciwave, "can't find file='%s' !\n", lpstrElementName);
192 return MCIERR_FILE_NOT_FOUND;
198 TRACE(mciwave,"hFile=%u\n", wmw->hFile);
200 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMS32A));
201 wmw->wNotifyDeviceID = dwDeviceID;
202 wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
204 wmw->waveDesc.hWave = 0;
206 if (wmw->hFile != 0) {
209 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
210 dwRet = MCIERR_INVALID_FILE;
212 TRACE(mciwave, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
213 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
214 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
215 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
216 dwRet = MCIERR_INVALID_FILE;
218 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
225 wmw->WaveFormat.wf.nAvgBytesPerSec =
226 wmw->WaveFormat.wf.nSamplesPerSec * wmw->WaveFormat.wf.nBlockAlign;
227 wmw->waveDesc.lpFormat = (LPWAVEFORMAT)&wmw->WaveFormat;
230 /* By default the device will be opened for output, the MCI_CUE function is there to
231 * change from output to input and back
233 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
234 wmw->dwStatus = MCI_MODE_STOP;
238 mmioClose32(wmw->hFile, 0);
244 /**************************************************************************
245 * WAVE_mciCue [internal]
247 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
252 This routine is far from complete. At the moment only a check is done on the
253 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
256 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
261 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
263 TRACE(mciwave,"(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
265 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
267 /* always close elements ? */
268 if (wmw->hFile != 0) {
269 mmioClose32(wmw->hFile, 0);
273 dwRet = MMSYSERR_NOERROR; /* assume success */
275 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
276 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
277 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
278 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
280 } else if (wmw->fInput) {
281 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
282 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
283 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
286 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
289 /**************************************************************************
290 * WAVE_mciStop [internal]
292 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
295 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
297 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
299 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
300 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
302 wmw->dwStatus = MCI_MODE_STOP;
304 TRACE(mciwave, "wmw->dwStatus=%d\n", wmw->dwStatus);
307 dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
309 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
311 if (dwFlags & MCI_NOTIFY) {
312 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
313 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
314 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
317 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
320 /**************************************************************************
321 * WAVE_mciClose [internal]
323 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
326 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
328 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
330 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
332 if (wmw->dwStatus != MCI_MODE_STOP) {
333 WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
336 wmw->dwStatus = MCI_MODE_STOP;
339 if (wmw->nUseCount == 0) {
340 if (wmw->hFile != 0) {
341 mmioClose32(wmw->hFile, 0);
344 if (wmw->fInput) dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
345 else dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
347 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
350 if (lpParms && (dwFlags & MCI_NOTIFY)) {
351 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
352 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
353 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
358 /**************************************************************************
359 * WAVE_mciPlay [internal]
361 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
367 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
369 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
371 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
374 WARN(mciwave, "cannot play on input device\n");
375 return MCIERR_NONAPPLICABLE_FUNCTION;
378 if (wmw->hFile == 0) {
379 WARN(mciwave, "Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
380 return MCIERR_FILE_NOT_FOUND;
383 if (!(dwFlags & MCI_WAIT)) {
384 /** FIXME: I'm not 100% sure that wNotifyDeviceID is the right value in all cases ??? */
385 return MCI_SendCommandAsync32(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags, (DWORD)lpParms);
389 if (lpParms && (dwFlags & MCI_FROM)) {
390 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
392 if (lpParms && (dwFlags & MCI_TO)) {
393 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
396 TRACE(mciwave, "Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
398 /* go back to begining of chunk */
399 mmioSeek32(wmw->hFile, wmw->dwFileOffset, SEEK_SET); /* >= 0 */
401 /* at 22050 bytes per sec => 30 ms by block */
403 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
404 wmw->WaveHdr.lpData = (LPSTR)GlobalLock16(hData);
406 wmw->dwStatus = MCI_MODE_PLAY;
408 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
409 while (wmw->dwStatus != MCI_MODE_STOP) {
410 wmw->WaveHdr.dwUser = 0L;
411 wmw->WaveHdr.dwFlags = 0L;
412 wmw->WaveHdr.dwLoops = 0L;
413 dwRet = wodMessage(wDevID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
414 count = mmioRead32(wmw->hFile, wmw->WaveHdr.lpData, bufsize);
415 TRACE(mciwave,"mmioRead bufsize=%ld count=%ld\n", bufsize, count);
416 if (count < 1) break;
417 wmw->WaveHdr.dwBufferLength = count;
418 wmw->WaveHdr.dwBytesRecorded = 0;
419 TRACE(mciwave,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
420 &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
421 dwRet = wodMessage(wDevID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
422 /* FIXME: should use callback mechanisms from audio driver */
424 while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
427 wmw->dwPosition += count;
428 TRACE(mciwave,"after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
429 dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
432 if (wmw->WaveHdr.lpData != NULL) {
433 GlobalUnlock16(hData);
435 wmw->WaveHdr.lpData = NULL;
437 wmw->dwStatus = MCI_MODE_STOP;
438 if (lpParms && (dwFlags & MCI_NOTIFY)) {
439 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
440 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
441 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
447 /**************************************************************************
448 * WAVE_mciRecord [internal]
450 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
457 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
459 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
461 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
464 WARN(mciwave, "cannot record on output device\n");
465 return MCIERR_NONAPPLICABLE_FUNCTION;
468 if (wmw->hFile == 0) {
469 WARN(mciwave, "can't find file='%s' !\n",
470 wmw->openParms.lpstrElementName);
471 return MCIERR_FILE_NOT_FOUND;
473 start = 1; end = 99999;
474 if (dwFlags & MCI_FROM) {
475 start = lpParms->dwFrom;
476 TRACE(mciwave, "MCI_FROM=%d \n", start);
478 if (dwFlags & MCI_TO) {
480 TRACE(mciwave,"MCI_TO=%d \n", end);
483 lpWaveHdr = &wmw->WaveHdr;
484 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
485 lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
486 lpWaveHdr->dwBufferLength = bufsize;
487 lpWaveHdr->dwUser = 0L;
488 lpWaveHdr->dwFlags = 0L;
489 lpWaveHdr->dwLoops = 0L;
490 dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
491 TRACE(mciwave,"after WIDM_PREPARE \n");
493 lpWaveHdr->dwBytesRecorded = 0;
494 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
495 TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
496 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
497 if (lpWaveHdr->dwBytesRecorded == 0) break;
499 TRACE(mciwave,"before WIDM_UNPREPARE \n");
500 dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
501 TRACE(mciwave,"after WIDM_UNPREPARE \n");
502 if (lpWaveHdr->lpData != NULL) {
503 GlobalUnlock16(hData);
505 lpWaveHdr->lpData = NULL;
507 if (dwFlags & MCI_NOTIFY) {
508 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
509 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
510 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
515 /**************************************************************************
516 * WAVE_mciPause [internal]
518 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
521 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
523 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
525 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
526 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
528 if (wmw->dwStatus == MCI_MODE_PLAY) {
529 wmw->dwStatus = MCI_MODE_PAUSE;
532 if (wmw->fInput) dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
533 else dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
535 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
539 /**************************************************************************
540 * WAVE_mciResume [internal]
542 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
544 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
547 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
549 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
550 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
552 if (wmw->dwStatus == MCI_MODE_PAUSE) {
553 wmw->dwStatus = MCI_MODE_PLAY;
557 if (wmw->fInput) dwRet = widMessage(wDevID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
558 else dwRet = wodMessage(wDevID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
559 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
566 /**************************************************************************
567 * WAVE_mciSeek [internal]
569 static DWORD WAVE_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
572 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
574 TRACE(mciwave, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
576 if (lpParms == NULL) {
577 ret = MCIERR_NULL_PARAMETER_BLOCK;
578 } else if (wmw == NULL) {
579 ret = MCIERR_INVALID_DEVICE_ID;
581 WAVE_mciStop(wDevID, MCI_WAIT, 0);
583 if (dwFlags & MCI_SEEK_TO_START) {
585 } else if (dwFlags & MCI_SEEK_TO_END) {
586 wmw->dwPosition = 0xFFFFFFFF; /* fixme */
587 } else if (dwFlags & MCI_TO) {
588 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
590 WARN(mciwave, "dwFlag doesn't tell where to seek to...\n");
591 return MCIERR_MISSING_PARAMETER;
594 TRACE(mciwave, "Seeking to position=%lu bytes\n", wmw->dwPosition);
596 if (dwFlags & MCI_NOTIFY) {
597 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
598 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
599 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
605 /**************************************************************************
606 * WAVE_mciSet [internal]
608 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
610 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
612 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
613 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
614 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
616 if (dwFlags & MCI_SET_TIME_FORMAT) {
617 switch (lpParms->dwTimeFormat) {
618 case MCI_FORMAT_MILLISECONDS:
619 TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
620 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
622 case MCI_FORMAT_BYTES:
623 TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
624 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
626 case MCI_FORMAT_SAMPLES:
627 TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
628 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
631 WARN(mciwave,"Bad time format %lu!\n", lpParms->dwTimeFormat);
632 return MCIERR_BAD_TIME_FORMAT;
635 if (dwFlags & MCI_SET_VIDEO) {
636 TRACE(mciwave, "No support for video !\n");
637 return MCIERR_UNSUPPORTED_FUNCTION;
639 if (dwFlags & MCI_SET_DOOR_OPEN) {
640 TRACE(mciwave, "No support for door open !\n");
641 return MCIERR_UNSUPPORTED_FUNCTION;
643 if (dwFlags & MCI_SET_DOOR_CLOSED) {
644 TRACE(mciwave, "No support for door close !\n");
645 return MCIERR_UNSUPPORTED_FUNCTION;
647 if (dwFlags & MCI_SET_AUDIO) {
648 if (dwFlags & MCI_SET_ON) {
649 TRACE(mciwave, "MCI_SET_ON audio !\n");
650 } else if (dwFlags & MCI_SET_OFF) {
651 TRACE(mciwave, "MCI_SET_OFF audio !\n");
653 WARN(mciwave, "MCI_SET_AUDIO without SET_ON or SET_OFF\n");
654 return MCIERR_BAD_INTEGER;
657 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
658 TRACE(mciwave, "MCI_SET_AUDIO_ALL !\n");
659 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
660 TRACE(mciwave, "MCI_SET_AUDIO_LEFT !\n");
661 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
662 TRACE(mciwave, "MCI_SET_AUDIO_RIGHT !\n");
664 if (dwFlags & MCI_WAVE_INPUT)
665 TRACE(mciwave, "MCI_WAVE_INPUT !\n");
666 if (dwFlags & MCI_WAVE_OUTPUT)
667 TRACE(mciwave, "MCI_WAVE_OUTPUT !\n");
668 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
669 TRACE(mciwave, "MCI_WAVE_SET_ANYINPUT !\n");
670 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
671 TRACE(mciwave, "MCI_WAVE_SET_ANYOUTPUT !\n");
672 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
673 TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
674 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
675 TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
676 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
677 TRACE(mciwave, "MCI_WAVE_SET_BLOCKALIGN !\n");
678 if (dwFlags & MCI_WAVE_SET_CHANNELS)
679 TRACE(mciwave, "MCI_WAVE_SET_CHANNELS !\n");
680 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
681 TRACE(mciwave, "MCI_WAVE_SET_FORMATTAG !\n");
682 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
683 TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
688 /**************************************************************************
689 * WAVE_mciStatus [internal]
691 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
693 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
695 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
696 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
697 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
699 if (dwFlags & MCI_STATUS_ITEM) {
700 switch(lpParms->dwItem) {
701 case MCI_STATUS_CURRENT_TRACK:
702 lpParms->dwReturn = 1;
703 TRACE(mciwave, "MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
705 case MCI_STATUS_LENGTH:
706 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
707 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength);
708 TRACE(mciwave, "MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
710 case MCI_STATUS_MODE:
711 lpParms->dwReturn = wmw->dwStatus;
712 TRACE(mciwave, "MCI_STATUS_MODE => %lu\n", lpParms->dwReturn);
714 case MCI_STATUS_MEDIA_PRESENT:
715 TRACE(mciwave, "MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
716 lpParms->dwReturn = TRUE;
718 case MCI_STATUS_NUMBER_OF_TRACKS:
719 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
720 lpParms->dwReturn = 1;
721 TRACE(mciwave, "MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
723 case MCI_STATUS_POSITION:
724 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
725 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
726 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
727 TRACE(mciwave, "MCI_STATUS_POSITION %s => %lu\n",
728 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
730 case MCI_STATUS_READY:
731 lpParms->dwReturn = (wmw->dwStatus != MCI_MODE_NOT_READY);
732 TRACE(mciwave,"MCI_STATUS_READY => %lu!\n", lpParms->dwReturn);
734 case MCI_STATUS_TIME_FORMAT:
735 lpParms->dwReturn = wmw->dwMciTimeFormat;
736 TRACE(mciwave, "MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
739 TRACE(mciwave,"MCI_WAVE_INPUT !\n");
740 lpParms->dwReturn = 0;
742 case MCI_WAVE_OUTPUT:
743 TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
744 lpParms->dwReturn = 0;
746 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
747 lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
748 TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
750 case MCI_WAVE_STATUS_BITSPERSAMPLE:
751 lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
752 TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
754 case MCI_WAVE_STATUS_BLOCKALIGN:
755 lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
756 TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
758 case MCI_WAVE_STATUS_CHANNELS:
759 lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
760 TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
762 case MCI_WAVE_STATUS_FORMATTAG:
763 lpParms->dwReturn = wmw->WaveFormat.wf.
765 TRACE(mciwave,"MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
767 case MCI_WAVE_STATUS_LEVEL:
768 TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
769 lpParms->dwReturn = 0xAAAA5555;
771 case MCI_WAVE_STATUS_SAMPLESPERSEC:
772 lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
773 TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
776 WARN(mciwave,"unknown command %08lX !\n", lpParms->dwItem);
777 return MCIERR_UNRECOGNIZED_COMMAND;
780 if (dwFlags & MCI_NOTIFY) {
781 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
782 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
783 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
788 /**************************************************************************
789 * WAVE_mciGetDevCaps [internal]
791 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
792 LPMCI_GETDEVCAPS_PARMS lpParms)
794 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
796 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
798 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
799 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
801 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
802 switch(lpParms->dwItem) {
803 case MCI_GETDEVCAPS_DEVICE_TYPE:
804 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
806 case MCI_GETDEVCAPS_HAS_AUDIO:
807 lpParms->dwReturn = TRUE;
809 case MCI_GETDEVCAPS_HAS_VIDEO:
810 lpParms->dwReturn = FALSE;
812 case MCI_GETDEVCAPS_USES_FILES:
813 lpParms->dwReturn = TRUE;
815 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
816 lpParms->dwReturn = TRUE;
818 case MCI_GETDEVCAPS_CAN_RECORD:
819 lpParms->dwReturn = TRUE;
821 case MCI_GETDEVCAPS_CAN_EJECT:
822 lpParms->dwReturn = FALSE;
824 case MCI_GETDEVCAPS_CAN_PLAY:
825 lpParms->dwReturn = TRUE;
827 case MCI_GETDEVCAPS_CAN_SAVE:
828 lpParms->dwReturn = TRUE;
830 case MCI_WAVE_GETDEVCAPS_INPUTS:
831 lpParms->dwReturn = 1;
833 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
834 lpParms->dwReturn = 1;
837 TRACE(mciwave, "Unknown capability (%08lx) !\n", lpParms->dwItem);
838 return MCIERR_UNRECOGNIZED_COMMAND;
844 /**************************************************************************
845 * WAVE_mciInfo [internal]
847 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
851 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
853 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
855 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
856 ret = MCIERR_NULL_PARAMETER_BLOCK;
857 } else if (wmw == NULL) {
858 ret = MCIERR_INVALID_DEVICE_ID;
860 TRACE(mciwave, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
863 case MCI_INFO_PRODUCT:
864 str = "Wine's audio player";
867 str = wmw->openParms.lpstrElementName;
870 str = "Wine Wave In";
872 case MCI_WAVE_OUTPUT:
873 str = "Wine Wave Out";
876 WARN(mciwave, "Don't know this info command (%lu)\n", dwFlags);
877 return MCIERR_UNRECOGNIZED_COMMAND;
881 if (strlen(str) + 1 > lpParms->dwRetSize) {
882 ret = MCIERR_PARAM_OVERFLOW;
884 lstrcpyn32A(lpParms->lpstrReturn, str, lpParms->dwRetSize);
887 lpParms->lpstrReturn[0] = 0;
893 /**************************************************************************
894 * WAVE_DriverProc32 [sample driver]
896 LONG MCIWAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
897 DWORD dwParam1, DWORD dwParam2)
899 TRACE(mciwave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n",
900 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
903 case DRV_LOAD: return 1;
904 case DRV_FREE: return 1;
905 case DRV_OPEN: return 1;
906 case DRV_CLOSE: return 1;
907 case DRV_ENABLE: return 1;
908 case DRV_DISABLE: return 1;
909 case DRV_QUERYCONFIGURE: return 1;
910 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
911 case DRV_INSTALL: return DRVCNF_RESTART;
912 case DRV_REMOVE: return DRVCNF_RESTART;
913 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS32A)dwParam2);
914 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
915 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
916 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
917 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
918 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
919 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
920 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
921 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
922 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
923 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
924 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMS16) dwParam2);
925 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
942 WARN(mciwave, "Unsupported command=%s\n", MCI_CommandToString(wMsg));
946 FIXME(mciwave, "Shouldn't receive a MCI_OPEN or CLOSE message\n");
949 FIXME(mciwave, "is probably wrong msg=%s\n", MCI_CommandToString(wMsg));
950 return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
952 return MCIERR_UNRECOGNIZED_COMMAND;