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

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

JW: Updated to Wine level 20000109 + corrected compile errors

File size: 39.8 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 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
34 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
35 DWORD dwFileOffset; /* Offset of chunk in mmio file */
36 DWORD dwLength; /* number of bytes in chunk for playing */
37 DWORD dwPosition; /* position in bytes in chunk for playing */
38 HANDLE hEvent; /* for synchronization */
39 DWORD dwEventCount; /* for synchronization */
40} WINE_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 = (WINE_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 (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 (wmw->dwStatus == MCI_MODE_PAUSE) {
556 /* FIXME: parameters (start/end) in lpParams may not be used */
557 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
558 }
559
560 /** This function will be called again by a thread when async is used.
561 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
562 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
563 */
564 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
565 return MCIERR_INTERNAL;
566 }
567
568 wmw->dwStatus = MCI_MODE_PLAY;
569
570 if (!(dwFlags & MCI_WAIT)) {
571 return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_PLAY, dwFlags,
572 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
573 }
574
575 end = 0xFFFFFFFF;
576 if (lpParms && (dwFlags & MCI_FROM)) {
577 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
578 }
579 if (lpParms && (dwFlags & MCI_TO)) {
580 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
581 }
582
583 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
584
585 if (end <= wmw->dwPosition)
586 return TRUE;
587
588#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
589((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
590
591 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
592 wmw->dwLength = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwLength);
593 /* go back to begining of chunk plus the requested position */
594 /* FIXME: I'm not sure this is correct, notably because some data linked to
595 * the decompression state machine will not be correcly initialized.
596 * try it this way (other way would be to decompress from 0 up to dwPosition
597 * and to start sending to hWave when dwPosition is reached)
598 */
599 mmioSeek(wmw->hFile, wmw->dwFileOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
600
601 /* By default the device will be opened for output, the MCI_CUE function is there to
602 * change from output to input and back
603 */
604 /* FIXME: how to choose between several output channels ? here mapper is forced */
605 dwRet = waveOutOpen(&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
606 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
607
608 if (dwRet != 0) {
609 TRACE("Can't open low level audio device %ld\n", dwRet);
610 dwRet = MCIERR_DEVICE_OPEN;
611 wmw->hWave = 0;
612 goto cleanUp;
613 }
614
615 /* make it so that 3 buffers per second are needed */
616 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
617
618 waveHdr = (wavehdr_tag*)HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
619 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
620 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
621 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
622 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
623 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
624 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
625 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
626 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
627 dwRet = MCIERR_INTERNAL;
628 goto cleanUp;
629 }
630
631 whidx = 0;
632 left = MIN(wmw->dwLength, end - wmw->dwPosition);
633 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
634 wmw->dwEventCount = 1L; /* for first buffer */
635
636 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
637
638 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
639 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
640 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, MIN(bufsize, left));
641 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
642 if (count < 1)
643 break;
644 /* count is always <= bufsize, so this is correct regarding the
645 * waveOutPrepareHeader function
646 */
647 waveHdr[whidx].dwBufferLength = count;
648 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
649 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
650 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
651 waveHdr[whidx].dwBytesRecorded);
652 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
653 left -= count;
654 wmw->dwPosition += count;
655 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
656
657 WAVE_mciPlayWaitDone(wmw);
658 whidx ^= 1;
659 }
660
661 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
662
663 /* just to get rid of some race conditions between play, stop and pause */
664 waveOutReset(wmw->hWave);
665
666 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
667 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
668
669 dwRet = 0;
670
671cleanUp:
672 HeapFree(GetProcessHeap(), 0, waveHdr);
673
674 if (wmw->hWave) {
675 waveOutClose(wmw->hWave);
676 wmw->hWave = 0;
677 }
678 CloseHandle(wmw->hEvent);
679
680 if (lpParms && (dwFlags & MCI_NOTIFY)) {
681 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
682 wmw->wNotifyDeviceID,
683 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
684 }
685
686 wmw->dwStatus = MCI_MODE_STOP;
687
688 return dwRet;
689}
690
691/**************************************************************************
692 * WAVE_mciRecord [internal]
693 */
694static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
695{
696 int start, end;
697 LONG bufsize;
698 WAVEHDR waveHdr;
699 DWORD dwRet;
700 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
701
702 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
703
704 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
705 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
706
707 if (!wmw->fInput) {
708 WARN("cannot record on output device\n");
709 return MCIERR_NONAPPLICABLE_FUNCTION;
710 }
711
712 if (wmw->hFile == 0) {
713 WARN("can't find file='%s' !\n",
714 wmw->openParms.lpstrElementName);
715 return MCIERR_FILE_NOT_FOUND;
716 }
717 start = 1; end = 99999;
718 if (dwFlags & MCI_FROM) {
719 start = lpParms->dwFrom;
720 TRACE("MCI_FROM=%d \n", start);
721 }
722 if (dwFlags & MCI_TO) {
723 end = lpParms->dwTo;
724 TRACE("MCI_TO=%d \n", end);
725 }
726 bufsize = 64000;
727 waveHdr.lpData = (char*)HeapAlloc(GetProcessHeap(), 0, bufsize);
728 waveHdr.dwBufferLength = bufsize;
729 waveHdr.dwUser = 0L;
730 waveHdr.dwFlags = 0L;
731 waveHdr.dwLoops = 0L;
732 dwRet = waveInPrepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
733
734 for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
735 waveHdr.dwBytesRecorded = 0;
736 dwRet = waveInStart(wmw->hWave);
737 TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
738 &waveHdr, waveHdr.dwBytesRecorded);
739 if (waveHdr.dwBytesRecorded == 0) break;
740 }
741 dwRet = waveInUnprepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
742 HeapFree(GetProcessHeap(), 0, waveHdr.lpData);
743
744 if (dwFlags & MCI_NOTIFY) {
745 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
746 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
747 }
748 return 0;
749}
750
751/**************************************************************************
752 * WAVE_mciPause [internal]
753 */
754static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
755{
756 DWORD dwRet;
757 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
758
759 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
760
761 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
762 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
763
764 if (wmw->dwStatus == MCI_MODE_PLAY) {
765 wmw->dwStatus = MCI_MODE_PAUSE;
766 }
767
768 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
769 else dwRet = waveOutPause(wmw->hWave);
770
771 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
772}
773
774/**************************************************************************
775 * WAVE_mciResume [internal]
776 */
777static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
778{
779 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
780 DWORD dwRet = 0;
781
782 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
783
784 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
785
786 if (wmw->dwStatus == MCI_MODE_PAUSE) {
787 wmw->dwStatus = MCI_MODE_PLAY;
788 }
789
790 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
791 else dwRet = waveOutRestart(wmw->hWave);
792 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
793}
794
795/**************************************************************************
796 * WAVE_mciSeek [internal]
797 */
798static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
799{
800 DWORD ret = 0;
801 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
802
803 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
804
805 if (lpParms == NULL) {
806 ret = MCIERR_NULL_PARAMETER_BLOCK;
807 } else if (wmw == NULL) {
808 ret = MCIERR_INVALID_DEVICE_ID;
809 } else {
810 WAVE_mciStop(wDevID, MCI_WAIT, 0);
811
812 if (dwFlags & MCI_SEEK_TO_START) {
813 wmw->dwPosition = 0;
814 } else if (dwFlags & MCI_SEEK_TO_END) {
815 wmw->dwPosition = wmw->dwLength;
816 } else if (dwFlags & MCI_TO) {
817 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
818 } else {
819 WARN("dwFlag doesn't tell where to seek to...\n");
820 return MCIERR_MISSING_PARAMETER;
821 }
822
823 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
824
825 if (dwFlags & MCI_NOTIFY) {
826 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
827 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
828 }
829 }
830 return ret;
831}
832
833/**************************************************************************
834 * WAVE_mciSet [internal]
835 */
836static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
837{
838 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
839
840 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
841
842 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
843 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
844
845 if (dwFlags & MCI_SET_TIME_FORMAT) {
846 switch (lpParms->dwTimeFormat) {
847 case MCI_FORMAT_MILLISECONDS:
848 TRACE("MCI_FORMAT_MILLISECONDS !\n");
849 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
850 break;
851 case MCI_FORMAT_BYTES:
852 TRACE("MCI_FORMAT_BYTES !\n");
853 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
854 break;
855 case MCI_FORMAT_SAMPLES:
856 TRACE("MCI_FORMAT_SAMPLES !\n");
857 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
858 break;
859 default:
860 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
861 return MCIERR_BAD_TIME_FORMAT;
862 }
863 }
864 if (dwFlags & MCI_SET_VIDEO) {
865 TRACE("No support for video !\n");
866 return MCIERR_UNSUPPORTED_FUNCTION;
867 }
868 if (dwFlags & MCI_SET_DOOR_OPEN) {
869 TRACE("No support for door open !\n");
870 return MCIERR_UNSUPPORTED_FUNCTION;
871 }
872 if (dwFlags & MCI_SET_DOOR_CLOSED) {
873 TRACE("No support for door close !\n");
874 return MCIERR_UNSUPPORTED_FUNCTION;
875 }
876 if (dwFlags & MCI_SET_AUDIO) {
877 if (dwFlags & MCI_SET_ON) {
878 TRACE("MCI_SET_ON audio !\n");
879 } else if (dwFlags & MCI_SET_OFF) {
880 TRACE("MCI_SET_OFF audio !\n");
881 } else {
882 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
883 return MCIERR_BAD_INTEGER;
884 }
885
886 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
887 TRACE("MCI_SET_AUDIO_ALL !\n");
888 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
889 TRACE("MCI_SET_AUDIO_LEFT !\n");
890 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
891 TRACE("MCI_SET_AUDIO_RIGHT !\n");
892 }
893 if (dwFlags & MCI_WAVE_INPUT)
894 TRACE("MCI_WAVE_INPUT !\n");
895 if (dwFlags & MCI_WAVE_OUTPUT)
896 TRACE("MCI_WAVE_OUTPUT !\n");
897 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
898 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
899 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
900 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
901 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
902 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC !\n");
903 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
904 TRACE("MCI_WAVE_SET_BITSPERSAMPLE !\n");
905 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
906 TRACE("MCI_WAVE_SET_BLOCKALIGN !\n");
907 if (dwFlags & MCI_WAVE_SET_CHANNELS)
908 TRACE("MCI_WAVE_SET_CHANNELS !\n");
909 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
910 TRACE("MCI_WAVE_SET_FORMATTAG !\n");
911 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
912 TRACE("MCI_WAVE_SET_SAMPLESPERSEC !\n");
913 return 0;
914}
915
916/**************************************************************************
917 * WAVE_mciStatus [internal]
918 */
919static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
920{
921 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
922 DWORD ret = 0;
923
924 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
925 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
926 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
927
928 if (dwFlags & MCI_STATUS_ITEM) {
929 switch (lpParms->dwItem) {
930 case MCI_STATUS_CURRENT_TRACK:
931 lpParms->dwReturn = 1;
932 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
933 break;
934 case MCI_STATUS_LENGTH:
935 if (!wmw->hFile) {
936 lpParms->dwReturn = 0;
937 return MCIERR_UNSUPPORTED_FUNCTION;
938 }
939 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
940 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
941 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
942 break;
943 case MCI_STATUS_MODE:
944 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
945 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
946 ret = MCI_RESOURCE_RETURNED;
947 break;
948 case MCI_STATUS_MEDIA_PRESENT:
949 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
950 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
951 ret = MCI_RESOURCE_RETURNED;
952 break;
953 case MCI_STATUS_NUMBER_OF_TRACKS:
954 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
955 lpParms->dwReturn = 1;
956 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
957 break;
958 case MCI_STATUS_POSITION:
959 if (!wmw->hFile) {
960 lpParms->dwReturn = 0;
961 return MCIERR_UNSUPPORTED_FUNCTION;
962 }
963 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
964 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
965 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
966 &ret);
967 TRACE("MCI_STATUS_POSITION %s => %lu\n",
968 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
969 break;
970 case MCI_STATUS_READY:
971 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
972 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
973 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
974 ret = MCI_RESOURCE_RETURNED;
975 break;
976 case MCI_STATUS_TIME_FORMAT:
977 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, wmw->dwMciTimeFormat);
978 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
979 ret = MCI_RESOURCE_RETURNED;
980 break;
981 case MCI_WAVE_INPUT:
982 TRACE("MCI_WAVE_INPUT !\n");
983 lpParms->dwReturn = 0;
984 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
985 break;
986 case MCI_WAVE_OUTPUT:
987 TRACE("MCI_WAVE_OUTPUT !\n");
988 {
989 UINT id;
990 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
991 lpParms->dwReturn = id;
992 } else {
993 lpParms->dwReturn = 0;
994 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
995 }
996 }
997 break;
998 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
999 if (!wmw->hFile) {
1000 lpParms->dwReturn = 0;
1001 return MCIERR_UNSUPPORTED_FUNCTION;
1002 }
1003 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1004 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1005 break;
1006 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1007 if (!wmw->hFile) {
1008 lpParms->dwReturn = 0;
1009 return MCIERR_UNSUPPORTED_FUNCTION;
1010 }
1011 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1012 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1013 break;
1014 case MCI_WAVE_STATUS_BLOCKALIGN:
1015 if (!wmw->hFile) {
1016 lpParms->dwReturn = 0;
1017 return MCIERR_UNSUPPORTED_FUNCTION;
1018 }
1019 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1020 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1021 break;
1022 case MCI_WAVE_STATUS_CHANNELS:
1023 if (!wmw->hFile) {
1024 lpParms->dwReturn = 0;
1025 return MCIERR_UNSUPPORTED_FUNCTION;
1026 }
1027 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1028 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1029 break;
1030 case MCI_WAVE_STATUS_FORMATTAG:
1031 if (!wmw->hFile) {
1032 lpParms->dwReturn = 0;
1033 return MCIERR_UNSUPPORTED_FUNCTION;
1034 }
1035 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1036 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1037 break;
1038 case MCI_WAVE_STATUS_LEVEL:
1039 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1040 lpParms->dwReturn = 0xAAAA5555;
1041 break;
1042 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1043 if (!wmw->hFile) {
1044 lpParms->dwReturn = 0;
1045 return MCIERR_UNSUPPORTED_FUNCTION;
1046 }
1047 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1048 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1049 break;
1050 default:
1051 WARN("unknown command %08lX !\n", lpParms->dwItem);
1052 return MCIERR_UNRECOGNIZED_COMMAND;
1053 }
1054 }
1055 if (dwFlags & MCI_NOTIFY) {
1056 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
1057 wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
1058 }
1059 return ret;
1060}
1061
1062/**************************************************************************
1063 * WAVE_mciGetDevCaps [internal]
1064 */
1065static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1066 LPMCI_GETDEVCAPS_PARMS lpParms)
1067{
1068 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1069 DWORD ret = 0;
1070
1071 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1072
1073 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1074 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1075
1076 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1077 switch(lpParms->dwItem) {
1078 case MCI_GETDEVCAPS_DEVICE_TYPE:
1079 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1080 ret = MCI_RESOURCE_RETURNED;
1081 break;
1082 case MCI_GETDEVCAPS_HAS_AUDIO:
1083 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1084 ret = MCI_RESOURCE_RETURNED;
1085 break;
1086 case MCI_GETDEVCAPS_HAS_VIDEO:
1087 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1088 ret = MCI_RESOURCE_RETURNED;
1089 break;
1090 case MCI_GETDEVCAPS_USES_FILES:
1091 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1092 ret = MCI_RESOURCE_RETURNED;
1093 break;
1094 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1095 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1096 ret = MCI_RESOURCE_RETURNED;
1097 break;
1098 case MCI_GETDEVCAPS_CAN_RECORD:
1099 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1100 ret = MCI_RESOURCE_RETURNED;
1101 break;
1102 case MCI_GETDEVCAPS_CAN_EJECT:
1103 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1104 ret = MCI_RESOURCE_RETURNED;
1105 break;
1106 case MCI_GETDEVCAPS_CAN_PLAY:
1107 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1108 ret = MCI_RESOURCE_RETURNED;
1109 break;
1110 case MCI_GETDEVCAPS_CAN_SAVE:
1111 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1112 ret = MCI_RESOURCE_RETURNED;
1113 break;
1114 case MCI_WAVE_GETDEVCAPS_INPUTS:
1115 lpParms->dwReturn = 1;
1116 break;
1117 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1118 lpParms->dwReturn = 1;
1119 break;
1120 default:
1121 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1122 return MCIERR_UNRECOGNIZED_COMMAND;
1123 }
1124 } else {
1125 WARN("No GetDevCaps-Item !\n");
1126 return MCIERR_UNRECOGNIZED_COMMAND;
1127 }
1128 return ret;
1129}
1130
1131/**************************************************************************
1132 * WAVE_mciInfo [internal]
1133 */
1134static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1135{
1136 DWORD ret = 0;
1137 LPCSTR str = 0;
1138 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1139
1140 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1141
1142 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1143 ret = MCIERR_NULL_PARAMETER_BLOCK;
1144 } else if (wmw == NULL) {
1145 ret = MCIERR_INVALID_DEVICE_ID;
1146 } else {
1147 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1148
1149 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1150 case MCI_INFO_PRODUCT:
1151 str = "Wine's audio player";
1152 break;
1153 case MCI_INFO_FILE:
1154 str = wmw->openParms.lpstrElementName;
1155 break;
1156 case MCI_WAVE_INPUT:
1157 str = "Wine Wave In";
1158 break;
1159 case MCI_WAVE_OUTPUT:
1160 str = "Wine Wave Out";
1161 break;
1162 default:
1163 WARN("Don't know this info command (%lu)\n", dwFlags);
1164 ret = MCIERR_UNRECOGNIZED_COMMAND;
1165 }
1166 }
1167 if (str) {
1168 if (strlen(str) + 1 > lpParms->dwRetSize) {
1169 ret = MCIERR_PARAM_OVERFLOW;
1170 } else {
1171 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1172 }
1173 } else {
1174 lpParms->lpstrReturn[0] = 0;
1175 }
1176
1177 return ret;
1178}
1179
1180/**************************************************************************
1181 * MCIWAVE_DriverProc [sample driver]
1182 */
1183LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1184 DWORD dwParam1, DWORD dwParam2)
1185{
1186 TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1187 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1188
1189 switch(wMsg) {
1190 case DRV_LOAD: return 1;
1191 case DRV_FREE: return 1;
1192 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1193 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1194 case DRV_ENABLE: return 1;
1195 case DRV_DISABLE: return 1;
1196 case DRV_QUERYCONFIGURE: return 1;
1197 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1198 case DRV_INSTALL: return DRVCNF_RESTART;
1199 case DRV_REMOVE: return DRVCNF_RESTART;
1200 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
1201 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1202 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1203 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1204 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1205 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1206 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1207 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1208 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1209 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1210 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1211 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
1212 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1213 /* commands that should be supported */
1214 case MCI_LOAD:
1215 case MCI_SAVE:
1216 case MCI_FREEZE:
1217 case MCI_PUT:
1218 case MCI_REALIZE:
1219 case MCI_UNFREEZE:
1220 case MCI_UPDATE:
1221 case MCI_WHERE:
1222 case MCI_STEP:
1223 case MCI_SPIN:
1224 case MCI_ESCAPE:
1225 case MCI_COPY:
1226 case MCI_CUT:
1227 case MCI_DELETE:
1228 case MCI_PASTE:
1229 FIXME("Unsupported yet command [%lu]\n", wMsg);
1230 break;
1231 case MCI_WINDOW:
1232 TRACE("Unsupported command [%lu]\n", wMsg);
1233 break;
1234 case MCI_OPEN:
1235 case MCI_CLOSE:
1236 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1237 break;
1238 default:
1239 FIXME("is probably wrong msg [%lu]\n", wMsg);
1240 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1241 }
1242 return MCIERR_UNRECOGNIZED_COMMAND;
1243}
Note: See TracBrowser for help on using the repository browser.