source: trunk/src/winmm/mciwave/mciwave.cpp@ 2308

Last change on this file since 2308 was 2308, checked in by sandervl, 26 years ago

JW: Ported Wine mci dlls

File size: 39.6 KB
Line 
1/* -*- tab-width: 8; c-basic-offset: 4 -*- */
2/*
3 * Sample Wine Driver for MCI wave forms
4 *
5 * Copyright 1994 Martin Ayotte
6 * 1999 Eric Pouech
7 */
8/*
9 * FIXME:
10 * - record/play should and must be done asynchronous
11 */
12
13#include <os2win.h>
14#include <string.h>
15#include "winuser.h"
16#include "driver.h"
17#include "mmddk.h"
18#include "heapstring.h"
19#include "debugtools.h"
20
21DEFAULT_DEBUG_CHANNEL(mciwave)
22
23typedef struct {
24 UINT wDevID;
25 HANDLE hWave;
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 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 */
40} WINE_MCIWAVE, *PWINE_MCIWAVE;
41
42/* ===================================================================
43 * ===================================================================
44 * FIXME: should be using the new mmThreadXXXX functions from WINMM
45 * instead of those
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 * =================================================================== */
50
51struct SCA {
52 UINT wDevID;
53 UINT wMsg;
54 DWORD dwParam1;
55 DWORD dwParam2;
56 BOOL allocatedCopy;
57};
58
59/**************************************************************************
60 * MCI_SCAStarter [internal]
61 */
62static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
63{
64 struct SCA* sca = (struct SCA*)arg;
65 DWORD ret;
66
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);
75 ExitThread(ret);
76 WARN("Should not happen ? what's wrong \n");
77 /* should not go after this point */
78 return ret;
79}
80
81/**************************************************************************
82 * MCI_SendCommandAsync [internal]
83 */
84static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
85 DWORD dwParam2, UINT size)
86{
87 struct SCA* sca = (SCA*)HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA));
88
89 if (sca == 0)
90 return MCIERR_OUT_OF_MEMORY;
91
92 sca->wDevID = wDevID;
93 sca->wMsg = wMsg;
94 sca->dwParam1 = dwParam1;
95
96 if (size) {
97 sca->dwParam2 = (DWORD)HeapAlloc(GetProcessHeap(), 0, size);
98 if (sca->dwParam2 == 0) {
99 HeapFree(GetProcessHeap(), 0, sca);
100 return MCIERR_OUT_OF_MEMORY;
101 }
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
105 */
106 memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
107 } else {
108 sca->dwParam2 = dwParam2;
109 sca->allocatedCopy = FALSE;
110 }
111
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);
115 }
116 return 0;
117}
118
119/*======================================================================*
120 * MCI WAVE implemantation *
121 *======================================================================*/
122
123static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
124
125/**************************************************************************
126 * MCIWAVE_drvOpen [internal]
127 */
128static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
129{
130 WINE_MCIWAVE* wmw = PWINE_MCIWAVE(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE)));
131
132 if (!wmw)
133 return 0;
134
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;
140}
141
142/**************************************************************************
143 * MCIWAVE_drvClose [internal]
144 */
145static DWORD WAVE_drvClose(DWORD dwDevID)
146{
147 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
148
149 if (wmw) {
150 HeapFree(GetProcessHeap(), 0, wmw);
151 mciSetDriverData(dwDevID, 0);
152 return 1;
153 }
154 return 0;
155}
156
157/**************************************************************************
158 * WAVE_mciGetOpenDev [internal]
159 */
160static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
161{
162 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
163
164 if (wmw == NULL || wmw->nUseCount == 0) {
165 WARN("Invalid wDevID=%u\n", wDevID);
166 return 0;
167 }
168 return wmw;
169}
170
171/**************************************************************************
172 * WAVE_ConvertByteToTimeFormat [internal]
173 */
174static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
175{
176 DWORD ret = 0;
177
178 switch (wmw->dwMciTimeFormat) {
179 case MCI_FORMAT_MILLISECONDS:
180 ret = (val * 1000) / wmw->lpWaveFormat->nAvgBytesPerSec;
181 break;
182 case MCI_FORMAT_BYTES:
183 ret = val;
184 break;
185 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
186 ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
187 break;
188 default:
189 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
190 }
191 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
192 *lpRet = 0;
193 return ret;
194}
195
196/**************************************************************************
197 * WAVE_ConvertTimeFormatToByte [internal]
198 */
199static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
200{
201 DWORD ret = 0;
202
203 switch (wmw->dwMciTimeFormat) {
204 case MCI_FORMAT_MILLISECONDS:
205 ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
206 break;
207 case MCI_FORMAT_BYTES:
208 ret = val;
209 break;
210 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
211 ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
212 break;
213 default:
214 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
215 }
216 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
217 return ret;
218}
219
220/**************************************************************************
221 * WAVE_mciReadFmt [internal]
222 */
223static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
224{
225 MMCKINFO mmckInfo;
226 long r;
227
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);
233
234 wmw->lpWaveFormat = (WAVEFORMATEX*)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;
238
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);
247
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;
253 }
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;
260 return 0;
261}
262
263/**************************************************************************
264 * WAVE_mciOpen [internal]
265 */
266static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
267{
268 DWORD dwRet = 0;
269 DWORD dwDeviceID;
270 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
271
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;
275
276 if (dwFlags & MCI_OPEN_SHAREABLE)
277 return MCIERR_HARDWARE;
278
279 if (wmw->nUseCount > 0) {
280 /* The driver is already opened on this channel
281 * Wave driver cannot be shared
282 */
283 return MCIERR_DEVICE_OPEN;
284 }
285 wmw->nUseCount++;
286
287 dwDeviceID = lpOpenParms->wDeviceID;
288
289 wmw->fInput = FALSE;
290 wmw->hWave = 0;
291
292 TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
293
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 ?
298 */
299 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
300 } else {
301 LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
302
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;
311 }
312 } else {
313 wmw->hFile = 0;
314 }
315 }
316 }
317 TRACE("hFile=%u\n", wmw->hFile);
318
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 */
322
323 if (dwRet == 0 && wmw->hFile != 0) {
324 MMCKINFO ckMainRIFF;
325
326 if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
327 dwRet = MCIERR_INVALID_FILE;
328 } else {
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;
334 } else {
335 dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
336 }
337 }
338 } else {
339 wmw->dwLength = 0;
340 }
341 if (dwRet == 0) {
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;
354 }
355 break;
356 }
357 }
358 wmw->dwPosition = 0;
359
360 wmw->dwStatus = MCI_MODE_STOP;
361 } else {
362 wmw->nUseCount--;
363 if (wmw->hFile != 0)
364 mmioClose(wmw->hFile, 0);
365 wmw->hFile = 0;
366 }
367 return dwRet;
368}
369
370/**************************************************************************
371 * WAVE_mciCue [internal]
372 */
373static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
374{
375 /*
376 FIXME
377
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
380 is the default.
381
382 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
383 are ignored
384 */
385
386 DWORD dwRet;
387 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
388
389 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
390
391 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
392
393 /* always close elements ? */
394 if (wmw->hFile != 0) {
395 mmioClose(wmw->hFile, 0);
396 wmw->hFile = 0;
397 }
398
399 dwRet = MMSYSERR_NOERROR; /* assume success */
400
401 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
402 dwRet = waveOutClose(wmw->hWave);
403 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
404 wmw->fInput = TRUE;
405 } else if (wmw->fInput) {
406 dwRet = waveInClose(wmw->hWave);
407 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
408 wmw->fInput = FALSE;
409 }
410 wmw->hWave = 0;
411 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
412}
413
414/**************************************************************************
415 * WAVE_mciStop [internal]
416 */
417static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
418{
419 DWORD dwRet = 0;
420 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
421
422 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
423
424 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
425
426 /* wait for playback thread (if any) to exit before processing further */
427 switch (wmw->dwStatus) {
428 case MCI_MODE_PAUSE:
429 case MCI_MODE_PLAY:
430 case MCI_MODE_RECORD:
431 {
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);
436 }
437 while (((volatile WINE_MCIWAVE*)wmw)->dwStatus != MCI_MODE_STOP)
438 Sleep(10);
439 break;
440 }
441
442 wmw->dwPosition = 0;
443
444 /* sanity resets */
445 wmw->dwStatus = MCI_MODE_STOP;
446
447 if ((dwFlags & MCI_NOTIFY) && lpParms) {
448 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
449 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
450 }
451
452 return dwRet;
453}
454
455/**************************************************************************
456 * WAVE_mciClose [internal]
457 */
458static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
459{
460 DWORD dwRet = 0;
461 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
462
463 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
464
465 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
466
467 if (wmw->dwStatus != MCI_MODE_STOP) {
468 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
469 }
470
471 wmw->nUseCount--;
472
473 if (wmw->nUseCount == 0) {
474 if (wmw->hFile != 0) {
475 mmioClose(wmw->hFile, 0);
476 wmw->hFile = 0;
477 }
478 }
479
480 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
481 wmw->lpWaveFormat = NULL;
482
483 if ((dwFlags & MCI_NOTIFY) && lpParms) {
484 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
485 wmw->wNotifyDeviceID,
486 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
487 }
488
489 return 0;
490}
491
492/**************************************************************************
493 * WAVE_mciPlayCallback [internal]
494 */
495static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
496 DWORD dwInstance,
497 DWORD dwParam1, DWORD dwParam2)
498{
499 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
500
501 switch (uMsg) {
502 case WOM_OPEN:
503 case WOM_CLOSE:
504 break;
505 case WOM_DONE:
506 InterlockedIncrement((LPLONG)&wmw->dwEventCount);
507 TRACE("Returning waveHdr=%lx\n", dwParam1);
508 SetEvent(wmw->hEvent);
509 break;
510 default:
511 ERR("Unknown uMsg=%d\n", uMsg);
512 }
513}
514
515static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
516{
517 for (;;) {
518 ResetEvent(wmw->hEvent);
519 if (InterlockedDecrement((LPLONG)&wmw->dwEventCount) >= 0) {
520 break;
521 }
522 InterlockedIncrement((LPLONG)&wmw->dwEventCount);
523
524 WaitForSingleObject(wmw->hEvent, INFINITE);
525 }
526}
527
528/**************************************************************************
529 * WAVE_mciPlay [internal]
530 */
531static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
532{
533 DWORD end;
534 LONG bufsize, count, left;
535 DWORD dwRet = 0;
536 LPWAVEHDR waveHdr = NULL;
537 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
538 int whidx;
539
540 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
541
542 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
543 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
544
545 if (wmw->fInput) {
546 WARN("cannot play on input device\n");
547 return MCIERR_NONAPPLICABLE_FUNCTION;
548 }
549
550 if (wmw->hFile == 0) {
551 WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
552 return MCIERR_FILE_NOT_FOUND;
553 }
554
555 if (!(dwFlags & MCI_WAIT)) {
556 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
557 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
558 }
559
560 if (wmw->dwStatus != MCI_MODE_STOP) {
561 if (wmw->dwStatus == MCI_MODE_PAUSE) {
562 /* FIXME: parameters (start/end) in lpParams may not be used */
563 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
564 }
565 return MCIERR_INTERNAL;
566 }
567
568 end = 0xFFFFFFFF;
569 if (lpParms && (dwFlags & MCI_FROM)) {
570 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
571 }
572 if (lpParms && (dwFlags & MCI_TO)) {
573 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
574 }
575
576 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
577
578 if (end <= wmw->dwPosition)
579 return TRUE;
580
581#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
582((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
583
584 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
585 wmw->dwLength = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwLength);
586 /* go back to begining of chunk plus the requested position */
587 /* FIXME: I'm not sure this is correct, notably because some data linked to
588 * the decompression state machine will not be correcly initialized.
589 * try it this way (other way would be to decompress from 0 up to dwPosition
590 * and to start sending to hWave when dwPosition is reached)
591 */
592 mmioSeek(wmw->hFile, wmw->dwFileOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
593
594 /* By default the device will be opened for output, the MCI_CUE function is there to
595 * change from output to input and back
596 */
597 /* FIXME: how to choose between several output channels ? here mapper is forced */
598 dwRet = waveOutOpen(&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
599 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
600
601 if (dwRet != 0) {
602 TRACE("Can't open low level audio device %ld\n", dwRet);
603 dwRet = MCIERR_DEVICE_OPEN;
604 wmw->hWave = 0;
605 goto cleanUp;
606 }
607
608 /* make it so that 3 buffers per second are needed */
609 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
610
611 waveHdr = (wavehdr_tag*)HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
612 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
613 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
614 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
615 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
616 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
617 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
618 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
619 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
620 dwRet = MCIERR_INTERNAL;
621 goto cleanUp;
622 }
623
624 whidx = 0;
625 left = MIN(wmw->dwLength, end - wmw->dwPosition);
626 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
627 wmw->dwEventCount = 1L; /* for first buffer */
628
629 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
630 wmw->dwStatus = MCI_MODE_PLAY;
631
632 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
633 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
634 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, MIN(bufsize, left));
635 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
636 if (count < 1)
637 break;
638 /* count is always <= bufsize, so this is correct regarding the
639 * waveOutPrepareHeader function
640 */
641 waveHdr[whidx].dwBufferLength = count;
642 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
643 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
644 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
645 waveHdr[whidx].dwBytesRecorded);
646 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
647 left -= count;
648 wmw->dwPosition += count;
649 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
650
651 WAVE_mciPlayWaitDone(wmw);
652 whidx ^= 1;
653 }
654
655 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
656
657 /* just to get rid of some race conditions between play, stop and pause */
658 waveOutReset(wmw->hWave);
659
660 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
661 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
662
663 dwRet = 0;
664
665cleanUp:
666 HeapFree(GetProcessHeap(), 0, waveHdr);
667
668 if (wmw->hWave) {
669 waveOutClose(wmw->hWave);
670 wmw->hWave = 0;
671 }
672 CloseHandle(wmw->hEvent);
673
674 if (lpParms && (dwFlags & MCI_NOTIFY)) {
675 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
676 wmw->wNotifyDeviceID,
677 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
678 }
679
680 wmw->dwStatus = MCI_MODE_STOP;
681
682 return dwRet;
683}
684
685/**************************************************************************
686 * WAVE_mciRecord [internal]
687 */
688static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
689{
690 int start, end;
691 LONG bufsize;
692 WAVEHDR waveHdr;
693 DWORD dwRet;
694 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
695
696 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
697
698 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
699 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
700
701 if (!wmw->fInput) {
702 WARN("cannot record on output device\n");
703 return MCIERR_NONAPPLICABLE_FUNCTION;
704 }
705
706 if (wmw->hFile == 0) {
707 WARN("can't find file='%s' !\n",
708 wmw->openParms.lpstrElementName);
709 return MCIERR_FILE_NOT_FOUND;
710 }
711 start = 1; end = 99999;
712 if (dwFlags & MCI_FROM) {
713 start = lpParms->dwFrom;
714 TRACE("MCI_FROM=%d \n", start);
715 }
716 if (dwFlags & MCI_TO) {
717 end = lpParms->dwTo;
718 TRACE("MCI_TO=%d \n", end);
719 }
720 bufsize = 64000;
721 waveHdr.lpData = (CHAR*)HeapAlloc(GetProcessHeap(), 0, bufsize);
722 waveHdr.dwBufferLength = bufsize;
723 waveHdr.dwUser = 0L;
724 waveHdr.dwFlags = 0L;
725 waveHdr.dwLoops = 0L;
726 dwRet = waveInPrepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
727
728 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
729 waveHdr.dwBytesRecorded = 0;
730 dwRet = waveInStart(wmw->hWave);
731 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
732 &waveHdr, waveHdr.dwBytesRecorded);
733 if (waveHdr.dwBytesRecorded == 0) break;
734 }
735 dwRet = waveInUnprepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
736 HeapFree(GetProcessHeap(), 0, waveHdr.lpData);
737
738 if (dwFlags & MCI_NOTIFY) {
739 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
740 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
741 }
742 return 0;
743}
744
745/**************************************************************************
746 * WAVE_mciPause [internal]
747 */
748static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
749{
750 DWORD dwRet;
751 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
752
753 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
754
755 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
756 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
757
758 if (wmw->dwStatus == MCI_MODE_PLAY) {
759 wmw->dwStatus = MCI_MODE_PAUSE;
760 }
761
762 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
763 else dwRet = waveOutPause(wmw->hWave);
764
765 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
766}
767
768/**************************************************************************
769 * WAVE_mciResume [internal]
770 */
771static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
772{
773 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
774 DWORD dwRet = 0;
775
776 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
777
778 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
779
780 if (wmw->dwStatus == MCI_MODE_PAUSE) {
781 wmw->dwStatus = MCI_MODE_PLAY;
782 }
783
784 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
785 else dwRet = waveOutRestart(wmw->hWave);
786 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
787}
788
789/**************************************************************************
790 * WAVE_mciSeek [internal]
791 */
792static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
793{
794 DWORD ret = 0;
795 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
796
797 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
798
799 if (lpParms == NULL) {
800 ret = MCIERR_NULL_PARAMETER_BLOCK;
801 } else if (wmw == NULL) {
802 ret = MCIERR_INVALID_DEVICE_ID;
803 } else {
804 WAVE_mciStop(wDevID, MCI_WAIT, 0);
805
806 if (dwFlags & MCI_SEEK_TO_START) {
807 wmw->dwPosition = 0;
808 } else if (dwFlags & MCI_SEEK_TO_END) {
809 wmw->dwPosition = wmw->dwLength;
810 } else if (dwFlags & MCI_TO) {
811 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
812 } else {
813 WARN("dwFlag doesn't tell where to seek to...\n");
814 return MCIERR_MISSING_PARAMETER;
815 }
816
817 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
818
819 if (dwFlags & MCI_NOTIFY) {
820 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
821 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
822 }
823 }
824 return ret;
825}
826
827/**************************************************************************
828 * WAVE_mciSet [internal]
829 */
830static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
831{
832 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
833
834 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
835
836 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
837 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
838
839 if (dwFlags & MCI_SET_TIME_FORMAT) {
840 switch (lpParms->dwTimeFormat) {
841 case MCI_FORMAT_MILLISECONDS:
842 TRACE("MCI_FORMAT_MILLISECONDS !\n");
843 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
844 break;
845 case MCI_FORMAT_BYTES:
846 TRACE("MCI_FORMAT_BYTES !\n");
847 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
848 break;
849 case MCI_FORMAT_SAMPLES:
850 TRACE("MCI_FORMAT_SAMPLES !\n");
851 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
852 break;
853 default:
854 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
855 return MCIERR_BAD_TIME_FORMAT;
856 }
857 }
858 if (dwFlags & MCI_SET_VIDEO) {
859 TRACE("No support for video !\n");
860 return MCIERR_UNSUPPORTED_FUNCTION;
861 }
862 if (dwFlags & MCI_SET_DOOR_OPEN) {
863 TRACE("No support for door open !\n");
864 return MCIERR_UNSUPPORTED_FUNCTION;
865 }
866 if (dwFlags & MCI_SET_DOOR_CLOSED) {
867 TRACE("No support for door close !\n");
868 return MCIERR_UNSUPPORTED_FUNCTION;
869 }
870 if (dwFlags & MCI_SET_AUDIO) {
871 if (dwFlags & MCI_SET_ON) {
872 TRACE("MCI_SET_ON audio !\n");
873 } else if (dwFlags & MCI_SET_OFF) {
874 TRACE("MCI_SET_OFF audio !\n");
875 } else {
876 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
877 return MCIERR_BAD_INTEGER;
878 }
879
880 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
881 TRACE("MCI_SET_AUDIO_ALL !\n");
882 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
883 TRACE("MCI_SET_AUDIO_LEFT !\n");
884 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
885 TRACE("MCI_SET_AUDIO_RIGHT !\n");
886 }
887 if (dwFlags & MCI_WAVE_INPUT)
888 TRACE("MCI_WAVE_INPUT !\n");
889 if (dwFlags & MCI_WAVE_OUTPUT)
890 TRACE("MCI_WAVE_OUTPUT !\n");
891 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
892 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
893 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
894 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
895 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
896 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
897 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
898 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
899 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
900 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
901 if (dwFlags & MCI_WAVE_SET_CHANNELS)
902 TRACE("MCI_WAVE_SET_CHANNELS !\n");
903 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
904 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
905 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
906 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
907 return 0;
908}
909
910/**************************************************************************
911 * WAVE_mciStatus [internal]
912 */
913static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
914{
915 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
916 DWORD ret = 0;
917
918 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
919 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
920 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
921
922 if (dwFlags & MCI_STATUS_ITEM) {
923 switch (lpParms->dwItem) {
924 case MCI_STATUS_CURRENT_TRACK:
925 lpParms->dwReturn = 1;
926 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
927 break;
928 case MCI_STATUS_LENGTH:
929 if (!wmw->hFile) {
930 lpParms->dwReturn = 0;
931 return MCIERR_UNSUPPORTED_FUNCTION;
932 }
933 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
934 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
935 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
936 break;
937 case MCI_STATUS_MODE:
938 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
939 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
940 ret = MCI_RESOURCE_RETURNED;
941 break;
942 case MCI_STATUS_MEDIA_PRESENT:
943 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
944 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
945 ret = MCI_RESOURCE_RETURNED;
946 break;
947 case MCI_STATUS_NUMBER_OF_TRACKS:
948 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
949 lpParms->dwReturn = 1;
950 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
951 break;
952 case MCI_STATUS_POSITION:
953 if (!wmw->hFile) {
954 lpParms->dwReturn = 0;
955 return MCIERR_UNSUPPORTED_FUNCTION;
956 }
957 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
958 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
959 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
960 &ret);
961 TRACE("MCI_STATUS_POSITION %s => %lu\n",
962 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
963 break;
964 case MCI_STATUS_READY:
965 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
966 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
967 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
968 ret = MCI_RESOURCE_RETURNED;
969 break;
970 case MCI_STATUS_TIME_FORMAT:
971 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
972 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
973 ret = MCI_RESOURCE_RETURNED;
974 break;
975 case MCI_WAVE_INPUT:
976 TRACE("MCI_WAVE_INPUT !\n");
977 lpParms->dwReturn = 0;
978 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
979 break;
980 case MCI_WAVE_OUTPUT:
981 TRACE("MCI_WAVE_OUTPUT !\n");
982 {
983 UINT id;
984 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
985 lpParms->dwReturn = id;
986 } else {
987 lpParms->dwReturn = 0;
988 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
989 }
990 }
991 break;
992 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
993 if (!wmw->hFile) {
994 lpParms->dwReturn = 0;
995 return MCIERR_UNSUPPORTED_FUNCTION;
996 }
997 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
998 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
999 break;
1000 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1001 if (!wmw->hFile) {
1002 lpParms->dwReturn = 0;
1003 return MCIERR_UNSUPPORTED_FUNCTION;
1004 }
1005 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1006 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1007 break;
1008 case MCI_WAVE_STATUS_BLOCKALIGN:
1009 if (!wmw->hFile) {
1010 lpParms->dwReturn = 0;
1011 return MCIERR_UNSUPPORTED_FUNCTION;
1012 }
1013 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1014 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1015 break;
1016 case MCI_WAVE_STATUS_CHANNELS:
1017 if (!wmw->hFile) {
1018 lpParms->dwReturn = 0;
1019 return MCIERR_UNSUPPORTED_FUNCTION;
1020 }
1021 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1022 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1023 break;
1024 case MCI_WAVE_STATUS_FORMATTAG:
1025 if (!wmw->hFile) {
1026 lpParms->dwReturn = 0;
1027 return MCIERR_UNSUPPORTED_FUNCTION;
1028 }
1029 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1030 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1031 break;
1032 case MCI_WAVE_STATUS_LEVEL:
1033 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1034 lpParms->dwReturn = 0xAAAA5555;
1035 break;
1036 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1037 if (!wmw->hFile) {
1038 lpParms->dwReturn = 0;
1039 return MCIERR_UNSUPPORTED_FUNCTION;
1040 }
1041 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1042 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1043 break;
1044 default:
1045 WARN("unknown command %08lX !\n", lpParms->dwItem);
1046 return MCIERR_UNRECOGNIZED_COMMAND;
1047 }
1048 }
1049 if (dwFlags & MCI_NOTIFY) {
1050 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
1051 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
1052 }
1053 return ret;
1054}
1055
1056/**************************************************************************
1057 * WAVE_mciGetDevCaps [internal]
1058 */
1059static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1060 LPMCI_GETDEVCAPS_PARMS lpParms)
1061{
1062 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1063 DWORD ret = 0;
1064
1065 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1066
1067 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1068 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1069
1070 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1071 switch(lpParms->dwItem) {
1072 case MCI_GETDEVCAPS_DEVICE_TYPE:
1073 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1074 ret = MCI_RESOURCE_RETURNED;
1075 break;
1076 case MCI_GETDEVCAPS_HAS_AUDIO:
1077 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1078 ret = MCI_RESOURCE_RETURNED;
1079 break;
1080 case MCI_GETDEVCAPS_HAS_VIDEO:
1081 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1082 ret = MCI_RESOURCE_RETURNED;
1083 break;
1084 case MCI_GETDEVCAPS_USES_FILES:
1085 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1086 ret = MCI_RESOURCE_RETURNED;
1087 break;
1088 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1089 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1090 ret = MCI_RESOURCE_RETURNED;
1091 break;
1092 case MCI_GETDEVCAPS_CAN_RECORD:
1093 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1094 ret = MCI_RESOURCE_RETURNED;
1095 break;
1096 case MCI_GETDEVCAPS_CAN_EJECT:
1097 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1098 ret = MCI_RESOURCE_RETURNED;
1099 break;
1100 case MCI_GETDEVCAPS_CAN_PLAY:
1101 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1102 ret = MCI_RESOURCE_RETURNED;
1103 break;
1104 case MCI_GETDEVCAPS_CAN_SAVE:
1105 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1106 ret = MCI_RESOURCE_RETURNED;
1107 break;
1108 case MCI_WAVE_GETDEVCAPS_INPUTS:
1109 lpParms->dwReturn = 1;
1110 break;
1111 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1112 lpParms->dwReturn = 1;
1113 break;
1114 default:
1115 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1116 return MCIERR_UNRECOGNIZED_COMMAND;
1117 }
1118 } else {
1119 WARN("No GetDevCaps-Item !\n");
1120 return MCIERR_UNRECOGNIZED_COMMAND;
1121 }
1122 return ret;
1123}
1124
1125/**************************************************************************
1126 * WAVE_mciInfo [internal]
1127 */
1128static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1129{
1130 DWORD ret = 0;
1131 LPCSTR str = 0;
1132 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1133
1134 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1135
1136 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1137 ret = MCIERR_NULL_PARAMETER_BLOCK;
1138 } else if (wmw == NULL) {
1139 ret = MCIERR_INVALID_DEVICE_ID;
1140 } else {
1141 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1142
1143 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1144 case MCI_INFO_PRODUCT:
1145 str = "Wine's audio player";
1146 break;
1147 case MCI_INFO_FILE:
1148 str = wmw->openParms.lpstrElementName;
1149 break;
1150 case MCI_WAVE_INPUT:
1151 str = "Wine Wave In";
1152 break;
1153 case MCI_WAVE_OUTPUT:
1154 str = "Wine Wave Out";
1155 break;
1156 default:
1157 WARN("Don't know this info command (%lu)\n", dwFlags);
1158 ret = MCIERR_UNRECOGNIZED_COMMAND;
1159 }
1160 }
1161 if (str) {
1162 if (strlen(str) + 1 > lpParms->dwRetSize) {
1163 ret = MCIERR_PARAM_OVERFLOW;
1164 } else {
1165 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1166 }
1167 } else {
1168 lpParms->lpstrReturn[0] = 0;
1169 }
1170
1171 return ret;
1172}
1173
1174/**************************************************************************
1175 * MCIWAVE_DriverProc [sample driver]
1176 */
1177LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1178 DWORD dwParam1, DWORD dwParam2)
1179{
1180 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1181 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1182
1183 switch(wMsg) {
1184 case DRV_LOAD: return 1;
1185 case DRV_FREE: return 1;
1186 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1187 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1188 case DRV_ENABLE: return 1;
1189 case DRV_DISABLE: return 1;
1190 case DRV_QUERYCONFIGURE: return 1;
1191 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1192 case DRV_INSTALL: return DRVCNF_RESTART;
1193 case DRV_REMOVE: return DRVCNF_RESTART;
1194 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
1195 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1196 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1197 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1198 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1199 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1200 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1201 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1202 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1203 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1204 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1205 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
1206 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1207 /* commands that should be supported */
1208 case MCI_LOAD:
1209 case MCI_SAVE:
1210 case MCI_FREEZE:
1211 case MCI_PUT:
1212 case MCI_REALIZE:
1213 case MCI_UNFREEZE:
1214 case MCI_UPDATE:
1215 case MCI_WHERE:
1216 case MCI_STEP:
1217 case MCI_SPIN:
1218 case MCI_ESCAPE:
1219 case MCI_COPY:
1220 case MCI_CUT:
1221 case MCI_DELETE:
1222 case MCI_PASTE:
1223 FIXME("Unsupported yet command [%lu]\n", wMsg);
1224 break;
1225 case MCI_WINDOW:
1226 TRACE("Unsupported command [%lu]\n", wMsg);
1227 break;
1228 case MCI_OPEN:
1229 case MCI_CLOSE:
1230 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1231 break;
1232 default:
1233 FIXME("is probably wrong msg [%lu]\n", wMsg);
1234 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1235 }
1236 return MCIERR_UNRECOGNIZED_COMMAND;
1237}
Note: See TracBrowser for help on using the repository browser.