New debug scheme with explicit debug channels declaration.
[wine/hacks.git] / multimedia / mciwave.c
blob216fae625e46e997b7d8e7941bbe4d09ef53c320
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
6 */
7 /*
8 * FIXME:
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
13 #define EMULATE_SB16
15 #define DEBUG_MCIWAVE
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include "wine/winuser16.h"
24 #include "driver.h"
25 #include "multimedia.h"
26 #include "mmsystem.h"
27 #include "heap.h"
28 #include "debug.h"
30 DEFAULT_DEBUG_CHANNEL(mciwave)
32 #define MAX_MCIWAVEDRV (1)
34 typedef struct {
35 int nUseCount; /* Incremented for each shared open */
36 BOOL16 fShareable; /* TRUE if first open was shareable */
37 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
38 HANDLE16 hCallback; /* Callback handle for pending notification */
39 HMMIO hFile; /* mmio file handle open as Element */
40 MCI_WAVE_OPEN_PARMSA openParms;
41 WAVEOPENDESC waveDesc;
42 PCMWAVEFORMAT WaveFormat;
43 WAVEHDR WaveHdr;
44 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
45 WORD dwStatus; /* one from MCI_MODE_xxxx */
46 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
47 DWORD dwFileOffset; /* Offset of chunk in mmio file */
48 DWORD dwLength; /* number of bytes in chunk for playing */
49 DWORD dwPosition; /* position in bytes in chunk for playing */
50 } WINE_MCIWAVE;
52 static WINE_MCIWAVE MCIWaveDev[MAX_MCIWAVEDRV];
54 /*======================================================================*
55 * MCI WAVE implemantation *
56 *======================================================================*/
58 /**************************************************************************
59 * WAVE_mciGetOpenDev [internal]
61 static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT16 wDevID)
63 if (wDevID >= MAX_MCIWAVEDRV || MCIWaveDev[wDevID].nUseCount == 0) {
64 WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
65 return 0;
67 return &MCIWaveDev[wDevID];
70 static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val)
72 DWORD ret = 0;
74 switch (wmw->dwMciTimeFormat) {
75 case MCI_FORMAT_MILLISECONDS:
76 ret = (val * 1000) / wmw->WaveFormat.wf.nAvgBytesPerSec;
77 break;
78 case MCI_FORMAT_BYTES:
79 ret = val;
80 break;
81 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
82 ret = (val * 8) / wmw->WaveFormat.wBitsPerSample;
83 break;
84 default:
85 WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
87 TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
88 return ret;
91 static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
93 DWORD ret = 0;
95 switch (wmw->dwMciTimeFormat) {
96 case MCI_FORMAT_MILLISECONDS:
97 ret = (val * wmw->WaveFormat.wf.nAvgBytesPerSec) / 1000;
98 break;
99 case MCI_FORMAT_BYTES:
100 ret = val;
101 break;
102 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
103 ret = (val * wmw->WaveFormat.wBitsPerSample) / 8;
104 break;
105 default:
106 WARN(mciwave, "Bad time format %lu!\n", wmw->dwMciTimeFormat);
108 TRACE(mciwave, "val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
109 return ret;
112 static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
114 MMCKINFO mmckInfo;
116 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
117 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
118 return MCIERR_INVALID_FILE;
119 TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
120 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
121 if (mmioRead(wmw->hFile, (HPSTR)&wmw->WaveFormat,
122 (long)sizeof(PCMWAVEFORMAT)) != (long)sizeof(PCMWAVEFORMAT))
123 return MCIERR_INVALID_FILE;
125 TRACE(mciwave, "wFormatTag=%04X !\n", wmw->WaveFormat.wf.wFormatTag);
126 TRACE(mciwave, "nChannels=%d \n", wmw->WaveFormat.wf.nChannels);
127 TRACE(mciwave, "nSamplesPerSec=%ld\n", wmw->WaveFormat.wf.nSamplesPerSec);
128 TRACE(mciwave, "nAvgBytesPerSec=%ld\n", wmw->WaveFormat.wf.nAvgBytesPerSec);
129 TRACE(mciwave, "nBlockAlign=%d \n", wmw->WaveFormat.wf.nBlockAlign);
130 TRACE(mciwave, "wBitsPerSample=%u !\n", wmw->WaveFormat.wBitsPerSample);
131 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
132 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
133 return MCIERR_INVALID_FILE;
134 TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
135 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
136 TRACE(mciwave, "nChannels=%d nSamplesPerSec=%ld\n",
137 wmw->WaveFormat.wf.nChannels, wmw->WaveFormat.wf.nSamplesPerSec);
138 wmw->dwLength = mmckInfo.cksize;
139 wmw->dwFileOffset = mmioSeek(wmw->hFile, 0, SEEK_CUR); /* >= 0 */
140 return 0;
143 /**************************************************************************
144 * WAVE_mciOpen [internal]
146 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
148 DWORD dwRet = 0;
149 DWORD dwDeviceID;
150 WINE_MCIWAVE* wmw;
152 TRACE(mciwave, "(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
153 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
155 if (wDevID >= MAX_MCIWAVEDRV) {
156 WARN(mciwave, "Invalid wDevID=%u\n", wDevID);
157 return MCIERR_INVALID_DEVICE_ID;
159 if (dwFlags & MCI_OPEN_SHAREABLE)
160 return MCIERR_HARDWARE;
162 wmw = &MCIWaveDev[wDevID];
164 if (wmw->nUseCount > 0) {
165 /* The driver is already opened on this channel
166 * Wave driver cannot be shared
168 return MCIERR_DEVICE_OPEN;
170 wmw->nUseCount++;
172 dwDeviceID = lpOpenParms->wDeviceID;
174 wmw->fInput = FALSE;
176 TRACE(mciwave, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
178 if (dwFlags & MCI_OPEN_ELEMENT) {
179 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
180 /* could it be that (DWORD)lpOpenParms->lpstrElementName
181 * contains the hFile value ?
183 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
184 } else {
185 LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
187 /*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
188 TRACE(mciwave, "MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
189 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
190 wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL,
191 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
192 if (wmw->hFile == 0) {
193 WARN(mciwave, "can't find file='%s' !\n", lpstrElementName);
194 dwRet = MCIERR_FILE_NOT_FOUND;
196 } else {
197 wmw->hFile = 0;
201 TRACE(mciwave, "hFile=%u\n", wmw->hFile);
203 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
204 wmw->wNotifyDeviceID = dwDeviceID;
205 wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
207 wmw->waveDesc.hWave = 0;
209 if (dwRet == 0 && wmw->hFile != 0) {
210 MMCKINFO ckMainRIFF;
212 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
213 dwRet = MCIERR_INVALID_FILE;
214 } else {
215 TRACE(mciwave, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
216 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
217 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
218 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
219 dwRet = MCIERR_INVALID_FILE;
220 } else {
221 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
224 } else {
225 wmw->dwLength = 0;
227 if (dwRet == 0) {
228 wmw->WaveFormat.wf.nAvgBytesPerSec =
229 wmw->WaveFormat.wf.nSamplesPerSec * wmw->WaveFormat.wf.nBlockAlign;
230 wmw->waveDesc.lpFormat = (LPWAVEFORMAT)&wmw->WaveFormat;
231 wmw->dwPosition = 0;
233 wmw->dwStatus = MCI_MODE_STOP;
234 } else {
235 wmw->nUseCount--;
236 if (wmw->hFile != 0)
237 mmioClose(wmw->hFile, 0);
238 wmw->hFile = 0;
240 return dwRet;
243 /**************************************************************************
244 * WAVE_mciCue [internal]
246 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
249 FIXME
251 This routine is far from complete. At the moment only a check is done on the
252 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
253 is the default.
255 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
256 are ignored
259 DWORD dwRet;
260 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
262 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
264 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
266 /* always close elements ? */
267 if (wmw->hFile != 0) {
268 mmioClose(wmw->hFile, 0);
269 wmw->hFile = 0;
272 dwRet = MMSYSERR_NOERROR; /* assume success */
274 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
275 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
276 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
277 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
278 wmw->fInput = TRUE;
279 } else if (wmw->fInput) {
280 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
281 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
282 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
283 wmw->fInput = FALSE;
285 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
288 /**************************************************************************
289 * WAVE_mciStop [internal]
291 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
293 DWORD dwRet;
294 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
296 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
298 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
299 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
301 wmw->dwStatus = MCI_MODE_STOP;
302 wmw->dwPosition = 0;
303 TRACE(mciwave, "wmw->dwStatus=%d\n", wmw->dwStatus);
305 if (wmw->fInput)
306 dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
307 else
308 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
310 if (dwFlags & MCI_NOTIFY) {
311 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
312 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
313 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
316 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
319 /**************************************************************************
320 * WAVE_mciClose [internal]
322 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
324 DWORD dwRet = 0;
325 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
327 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
329 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
331 if (wmw->dwStatus != MCI_MODE_STOP) {
332 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
335 wmw->nUseCount--;
337 if (wmw->nUseCount == 0) {
338 DWORD mmRet;
339 if (wmw->hFile != 0) {
340 mmioClose(wmw->hFile, 0);
341 wmw->hFile = 0;
343 mmRet = (wmw->fInput) ? widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L) :
344 wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
346 if (mmRet != MMSYSERR_NOERROR) dwRet = MCIERR_INTERNAL;
349 if ((dwFlags & MCI_NOTIFY) && lpParms) {
350 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
351 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
352 wmw->wNotifyDeviceID,
353 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
355 return 0;
358 /**************************************************************************
359 * WAVE_mciPlay [internal]
361 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
363 DWORD end;
364 LONG bufsize, count;
365 HGLOBAL16 hData;
366 DWORD dwRet;
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;
372 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
374 if (wmw->fInput) {
375 WARN(mciwave, "cannot play on input device\n");
376 return MCIERR_NONAPPLICABLE_FUNCTION;
379 if (wmw->hFile == 0) {
380 WARN(mciwave, "Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
381 return MCIERR_FILE_NOT_FOUND;
384 if (!(dwFlags & MCI_WAIT)) {
385 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
386 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
389 end = 0xFFFFFFFF;
390 if (lpParms && (dwFlags & MCI_FROM)) {
391 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
393 if (lpParms && (dwFlags & MCI_TO)) {
394 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
397 TRACE(mciwave, "Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
399 /* go back to begining of chunk */
400 mmioSeek(wmw->hFile, wmw->dwFileOffset, SEEK_SET); /* >= 0 */
402 /* By default the device will be opened for output, the MCI_CUE function is there to
403 * change from output to input and back
405 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&wmw->waveDesc, CALLBACK_NULL);
406 if (dwRet != 0) {
407 TRACE(mciwave, "Can't open low level audio device %ld\n", dwRet);
408 return MCIERR_DEVICE_OPEN;
411 /* at 22050 bytes per sec => 30 ms by block */
412 bufsize = 10240;
413 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
414 wmw->WaveHdr.lpData = (LPSTR)GlobalLock16(hData);
416 wmw->dwStatus = MCI_MODE_PLAY;
418 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
419 while (wmw->dwStatus != MCI_MODE_STOP) {
420 wmw->WaveHdr.dwUser = 0L;
421 wmw->WaveHdr.dwFlags = 0L;
422 wmw->WaveHdr.dwLoops = 0L;
423 count = mmioRead(wmw->hFile, wmw->WaveHdr.lpData, bufsize);
424 TRACE(mciwave, "mmioRead bufsize=%ld count=%ld\n", bufsize, count);
425 if (count < 1)
426 break;
427 dwRet = wodMessage(wDevID, WODM_PREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
428 wmw->WaveHdr.dwBufferLength = count;
429 wmw->WaveHdr.dwBytesRecorded = 0;
430 TRACE(mciwave, "before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
431 &wmw->WaveHdr, wmw->WaveHdr.dwBufferLength, wmw->WaveHdr.dwBytesRecorded);
432 dwRet = wodMessage(wDevID, WODM_WRITE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
433 /* FIXME: should use callback mechanisms from audio driver */
434 #if 1
435 while (!(wmw->WaveHdr.dwFlags & WHDR_DONE))
436 Sleep(1);
437 #endif
438 wmw->dwPosition += count;
439 TRACE(mciwave, "after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
440 dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, (DWORD)&wmw->WaveHdr, sizeof(WAVEHDR));
443 if (wmw->WaveHdr.lpData != NULL) {
444 GlobalUnlock16(hData);
445 GlobalFree16(hData);
446 wmw->WaveHdr.lpData = NULL;
449 wodMessage(wDevID, WODM_STOP, 0, 0L, 0L);
450 wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
452 wmw->dwStatus = MCI_MODE_STOP;
453 if (lpParms && (dwFlags & MCI_NOTIFY)) {
454 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
455 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
456 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
458 return 0;
461 /**************************************************************************
462 * WAVE_mciRecord [internal]
464 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
466 int start, end;
467 LONG bufsize;
468 HGLOBAL16 hData;
469 LPWAVEHDR lpWaveHdr;
470 DWORD dwRet;
471 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
473 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
475 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
476 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
478 if (!wmw->fInput) {
479 WARN(mciwave, "cannot record on output device\n");
480 return MCIERR_NONAPPLICABLE_FUNCTION;
483 if (wmw->hFile == 0) {
484 WARN(mciwave, "can't find file='%s' !\n",
485 wmw->openParms.lpstrElementName);
486 return MCIERR_FILE_NOT_FOUND;
488 start = 1; end = 99999;
489 if (dwFlags & MCI_FROM) {
490 start = lpParms->dwFrom;
491 TRACE(mciwave, "MCI_FROM=%d \n", start);
493 if (dwFlags & MCI_TO) {
494 end = lpParms->dwTo;
495 TRACE(mciwave, "MCI_TO=%d \n", end);
497 bufsize = 64000;
498 lpWaveHdr = &wmw->WaveHdr;
499 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
500 lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
501 lpWaveHdr->dwBufferLength = bufsize;
502 lpWaveHdr->dwUser = 0L;
503 lpWaveHdr->dwFlags = 0L;
504 lpWaveHdr->dwLoops = 0L;
505 dwRet = widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
506 TRACE(mciwave, "after WIDM_PREPARE \n");
507 while (TRUE) {
508 lpWaveHdr->dwBytesRecorded = 0;
509 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
510 TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
511 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
512 if (lpWaveHdr->dwBytesRecorded == 0) break;
514 TRACE(mciwave, "before WIDM_UNPREPARE \n");
515 dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
516 TRACE(mciwave, "after WIDM_UNPREPARE \n");
517 if (lpWaveHdr->lpData != NULL) {
518 GlobalUnlock16(hData);
519 GlobalFree16(hData);
520 lpWaveHdr->lpData = NULL;
522 if (dwFlags & MCI_NOTIFY) {
523 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
524 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
525 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
527 return 0;
530 /**************************************************************************
531 * WAVE_mciPause [internal]
533 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
535 DWORD dwRet;
536 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
538 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
540 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
541 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
543 if (wmw->dwStatus == MCI_MODE_PLAY) {
544 wmw->dwStatus = MCI_MODE_PAUSE;
547 if (wmw->fInput) dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
548 else dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
550 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
553 /**************************************************************************
554 * WAVE_mciResume [internal]
556 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
558 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
559 DWORD dwRet = 0;
561 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
563 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
564 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
566 if (wmw->dwStatus == MCI_MODE_PAUSE) {
567 wmw->dwStatus = MCI_MODE_PLAY;
570 #if 0
571 if (wmw->fInput) dwRet = widMessage(wDevID, WIDM_PLAY, 0, dwFlags, (DWORD)lpParms);
572 else dwRet = wodMessage(wDevID, WODM_PLAY, 0, dwFlags, (DWORD)lpParms);
573 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
574 #else
575 return dwRet;
576 #endif
580 /**************************************************************************
581 * WAVE_mciSeek [internal]
583 static DWORD WAVE_mciSeek(UINT16 wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
585 DWORD ret = 0;
586 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
588 TRACE(mciwave, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
590 if (lpParms == NULL) {
591 ret = MCIERR_NULL_PARAMETER_BLOCK;
592 } else if (wmw == NULL) {
593 ret = MCIERR_INVALID_DEVICE_ID;
594 } else {
595 WAVE_mciStop(wDevID, MCI_WAIT, 0);
597 if (dwFlags & MCI_SEEK_TO_START) {
598 wmw->dwPosition = 0;
599 } else if (dwFlags & MCI_SEEK_TO_END) {
600 wmw->dwPosition = 0xFFFFFFFF; /* fixme */
601 } else if (dwFlags & MCI_TO) {
602 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
603 } else {
604 WARN(mciwave, "dwFlag doesn't tell where to seek to...\n");
605 return MCIERR_MISSING_PARAMETER;
608 TRACE(mciwave, "Seeking to position=%lu bytes\n", wmw->dwPosition);
610 if (dwFlags & MCI_NOTIFY) {
611 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
612 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
613 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
616 return ret;
619 /**************************************************************************
620 * WAVE_mciSet [internal]
622 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
624 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
626 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
628 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
629 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
631 if (dwFlags & MCI_SET_TIME_FORMAT) {
632 switch (lpParms->dwTimeFormat) {
633 case MCI_FORMAT_MILLISECONDS:
634 TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
635 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
636 break;
637 case MCI_FORMAT_BYTES:
638 TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
639 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
640 break;
641 case MCI_FORMAT_SAMPLES:
642 TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
643 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
644 break;
645 default:
646 WARN(mciwave, "Bad time format %lu!\n", lpParms->dwTimeFormat);
647 return MCIERR_BAD_TIME_FORMAT;
650 if (dwFlags & MCI_SET_VIDEO) {
651 TRACE(mciwave, "No support for video !\n");
652 return MCIERR_UNSUPPORTED_FUNCTION;
654 if (dwFlags & MCI_SET_DOOR_OPEN) {
655 TRACE(mciwave, "No support for door open !\n");
656 return MCIERR_UNSUPPORTED_FUNCTION;
658 if (dwFlags & MCI_SET_DOOR_CLOSED) {
659 TRACE(mciwave, "No support for door close !\n");
660 return MCIERR_UNSUPPORTED_FUNCTION;
662 if (dwFlags & MCI_SET_AUDIO) {
663 if (dwFlags & MCI_SET_ON) {
664 TRACE(mciwave, "MCI_SET_ON audio !\n");
665 } else if (dwFlags & MCI_SET_OFF) {
666 TRACE(mciwave, "MCI_SET_OFF audio !\n");
667 } else {
668 WARN(mciwave, "MCI_SET_AUDIO without SET_ON or SET_OFF\n");
669 return MCIERR_BAD_INTEGER;
672 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
673 TRACE(mciwave, "MCI_SET_AUDIO_ALL !\n");
674 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
675 TRACE(mciwave, "MCI_SET_AUDIO_LEFT !\n");
676 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
677 TRACE(mciwave, "MCI_SET_AUDIO_RIGHT !\n");
679 if (dwFlags & MCI_WAVE_INPUT)
680 TRACE(mciwave, "MCI_WAVE_INPUT !\n");
681 if (dwFlags & MCI_WAVE_OUTPUT)
682 TRACE(mciwave, "MCI_WAVE_OUTPUT !\n");
683 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
684 TRACE(mciwave, "MCI_WAVE_SET_ANYINPUT !\n");
685 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
686 TRACE(mciwave, "MCI_WAVE_SET_ANYOUTPUT !\n");
687 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
688 TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
689 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
690 TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
691 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
692 TRACE(mciwave, "MCI_WAVE_SET_BLOCKALIGN !\n");
693 if (dwFlags & MCI_WAVE_SET_CHANNELS)
694 TRACE(mciwave, "MCI_WAVE_SET_CHANNELS !\n");
695 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
696 TRACE(mciwave, "MCI_WAVE_SET_FORMATTAG !\n");
697 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
698 TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
699 return 0;
702 /**************************************************************************
703 * WAVE_mciStatus [internal]
705 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
707 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
709 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
710 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
711 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
713 if (dwFlags & MCI_STATUS_ITEM) {
714 switch(lpParms->dwItem) {
715 case MCI_STATUS_CURRENT_TRACK:
716 lpParms->dwReturn = 1;
717 TRACE(mciwave, "MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
718 break;
719 case MCI_STATUS_LENGTH:
720 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
721 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength);
722 TRACE(mciwave, "MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
723 break;
724 case MCI_STATUS_MODE:
725 lpParms->dwReturn = wmw->dwStatus;
726 TRACE(mciwave, "MCI_STATUS_MODE => %lu\n", lpParms->dwReturn);
727 break;
728 case MCI_STATUS_MEDIA_PRESENT:
729 TRACE(mciwave, "MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
730 lpParms->dwReturn = TRUE;
731 break;
732 case MCI_STATUS_NUMBER_OF_TRACKS:
733 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
734 lpParms->dwReturn = 1;
735 TRACE(mciwave, "MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
736 break;
737 case MCI_STATUS_POSITION:
738 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
739 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
740 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
741 TRACE(mciwave, "MCI_STATUS_POSITION %s => %lu\n",
742 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
743 break;
744 case MCI_STATUS_READY:
745 lpParms->dwReturn = (wmw->dwStatus != MCI_MODE_NOT_READY);
746 TRACE(mciwave, "MCI_STATUS_READY => %lu!\n", lpParms->dwReturn);
747 break;
748 case MCI_STATUS_TIME_FORMAT:
749 lpParms->dwReturn = wmw->dwMciTimeFormat;
750 TRACE(mciwave, "MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
751 break;
752 case MCI_WAVE_INPUT:
753 TRACE(mciwave, "MCI_WAVE_INPUT !\n");
754 lpParms->dwReturn = 0;
755 break;
756 case MCI_WAVE_OUTPUT:
757 TRACE(mciwave, "MCI_WAVE_OUTPUT !\n");
758 lpParms->dwReturn = 0;
759 break;
760 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
761 lpParms->dwReturn = wmw->WaveFormat.wf.nAvgBytesPerSec;
762 TRACE(mciwave, "MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
763 break;
764 case MCI_WAVE_STATUS_BITSPERSAMPLE:
765 lpParms->dwReturn = wmw->WaveFormat.wBitsPerSample;
766 TRACE(mciwave, "MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
767 break;
768 case MCI_WAVE_STATUS_BLOCKALIGN:
769 lpParms->dwReturn = wmw->WaveFormat.wf.nBlockAlign;
770 TRACE(mciwave, "MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
771 break;
772 case MCI_WAVE_STATUS_CHANNELS:
773 lpParms->dwReturn = wmw->WaveFormat.wf.nChannels;
774 TRACE(mciwave, "MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
775 break;
776 case MCI_WAVE_STATUS_FORMATTAG:
777 lpParms->dwReturn = wmw->WaveFormat.wf.wFormatTag;
778 TRACE(mciwave, "MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
779 break;
780 case MCI_WAVE_STATUS_LEVEL:
781 TRACE(mciwave, "MCI_WAVE_STATUS_LEVEL !\n");
782 lpParms->dwReturn = 0xAAAA5555;
783 break;
784 case MCI_WAVE_STATUS_SAMPLESPERSEC:
785 lpParms->dwReturn = wmw->WaveFormat.wf.nSamplesPerSec;
786 TRACE(mciwave, "MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
787 break;
788 default:
789 WARN(mciwave, "unknown command %08lX !\n", lpParms->dwItem);
790 return MCIERR_UNRECOGNIZED_COMMAND;
793 if (dwFlags & MCI_NOTIFY) {
794 TRACE(mciwave, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
795 mciDriverNotify16((HWND16)LOWORD(lpParms->dwCallback),
796 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
798 return 0;
801 /**************************************************************************
802 * WAVE_mciGetDevCaps [internal]
804 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
805 LPMCI_GETDEVCAPS_PARMS lpParms)
807 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
809 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
811 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
812 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
814 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
815 switch(lpParms->dwItem) {
816 case MCI_GETDEVCAPS_DEVICE_TYPE:
817 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
818 break;
819 case MCI_GETDEVCAPS_HAS_AUDIO:
820 lpParms->dwReturn = TRUE;
821 break;
822 case MCI_GETDEVCAPS_HAS_VIDEO:
823 lpParms->dwReturn = FALSE;
824 break;
825 case MCI_GETDEVCAPS_USES_FILES:
826 lpParms->dwReturn = TRUE;
827 break;
828 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
829 lpParms->dwReturn = TRUE;
830 break;
831 case MCI_GETDEVCAPS_CAN_RECORD:
832 lpParms->dwReturn = TRUE;
833 break;
834 case MCI_GETDEVCAPS_CAN_EJECT:
835 lpParms->dwReturn = FALSE;
836 break;
837 case MCI_GETDEVCAPS_CAN_PLAY:
838 lpParms->dwReturn = TRUE;
839 break;
840 case MCI_GETDEVCAPS_CAN_SAVE:
841 lpParms->dwReturn = TRUE;
842 break;
843 case MCI_WAVE_GETDEVCAPS_INPUTS:
844 lpParms->dwReturn = 1;
845 break;
846 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
847 lpParms->dwReturn = 1;
848 break;
849 default:
850 TRACE(mciwave, "Unknown capability (%08lx) !\n", lpParms->dwItem);
851 return MCIERR_UNRECOGNIZED_COMMAND;
854 return 0;
857 /**************************************************************************
858 * WAVE_mciInfo [internal]
860 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
862 DWORD ret = 0;
863 LPCSTR str = 0;
864 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
866 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
868 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
869 ret = MCIERR_NULL_PARAMETER_BLOCK;
870 } else if (wmw == NULL) {
871 ret = MCIERR_INVALID_DEVICE_ID;
872 } else {
873 TRACE(mciwave, "buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
875 switch(dwFlags) {
876 case MCI_INFO_PRODUCT:
877 str = "Wine's audio player";
878 break;
879 case MCI_INFO_FILE:
880 str = wmw->openParms.lpstrElementName;
881 break;
882 case MCI_WAVE_INPUT:
883 str = "Wine Wave In";
884 break;
885 case MCI_WAVE_OUTPUT:
886 str = "Wine Wave Out";
887 break;
888 default:
889 WARN(mciwave, "Don't know this info command (%lu)\n", dwFlags);
890 ret = MCIERR_UNRECOGNIZED_COMMAND;
893 if (str) {
894 if (strlen(str) + 1 > lpParms->dwRetSize) {
895 ret = MCIERR_PARAM_OVERFLOW;
896 } else {
897 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
899 } else {
900 lpParms->lpstrReturn[0] = 0;
903 return ret;
906 /**************************************************************************
907 * MCIWAVE_DriverProc [sample driver]
909 LONG MCIWAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
910 DWORD dwParam1, DWORD dwParam2)
912 TRACE(mciwave, "(%08lX, %04X, %08lX, %08lX, %08lX)\n",
913 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
915 switch(wMsg) {
916 case DRV_LOAD: return 1;
917 case DRV_FREE: return 1;
918 case DRV_OPEN: return 1;
919 case DRV_CLOSE: return 1;
920 case DRV_ENABLE: return 1;
921 case DRV_DISABLE: return 1;
922 case DRV_QUERYCONFIGURE: return 1;
923 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
924 case DRV_INSTALL: return DRVCNF_RESTART;
925 case DRV_REMOVE: return DRVCNF_RESTART;
926 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
927 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
928 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
929 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
930 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
931 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
932 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
933 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
934 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
935 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
936 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
937 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMS16) dwParam2);
938 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
939 case MCI_LOAD:
940 case MCI_SAVE:
941 case MCI_FREEZE:
942 case MCI_PUT:
943 case MCI_REALIZE:
944 case MCI_UNFREEZE:
945 case MCI_UPDATE:
946 case MCI_WHERE:
947 case MCI_WINDOW:
948 case MCI_STEP:
949 case MCI_SPIN:
950 case MCI_ESCAPE:
951 case MCI_COPY:
952 case MCI_CUT:
953 case MCI_DELETE:
954 case MCI_PASTE:
955 WARN(mciwave, "Unsupported command=%s\n", MCI_CommandToString(wMsg));
956 break;
957 case MCI_OPEN:
958 case MCI_CLOSE:
959 FIXME(mciwave, "Shouldn't receive a MCI_OPEN or CLOSE message\n");
960 break;
961 default:
962 FIXME(mciwave, "is probably wrong msg=%s\n", MCI_CommandToString(wMsg));
963 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
965 return MCIERR_UNRECOGNIZED_COMMAND;