source: trunk/src/winmm/mciwave/mciwave.c@ 21787

Last change on this file since 21787 was 10410, checked in by sandervl, 22 years ago

MCI updates from Wine

File size: 53.1 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,2000 Eric Pouech
7 * 2000 Francois Jacques
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <stdarg.h>
25
26#include "winerror.h"
27#include "windef.h"
28#include "winbase.h"
29#include "wingdi.h"
30#include "winuser.h"
31#include "mmddk.h"
32#include "wownt32.h"
33#include "digitalv.h"
34#include "wine/debug.h"
35
36WINE_DEFAULT_DEBUG_CHANNEL(mciwave);
37
38typedef struct {
39 UINT wDevID;
40 HANDLE hWave;
41 int nUseCount; /* Incremented for each shared open */
42 BOOL fShareable; /* TRUE if first open was shareable */
43 HMMIO hFile; /* mmio file handle open as Element */
44 MCI_WAVE_OPEN_PARMSA openParms;
45 WAVEFORMATEX wfxRef;
46 LPWAVEFORMATEX lpWaveFormat;
47 BOOL fInput; /* FALSE = Output, TRUE = Input */
48 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
49 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
50 DWORD dwPosition; /* position in bytes in chunk */
51 HANDLE hEvent; /* for synchronization */
52 DWORD dwEventCount; /* for synchronization */
53 BOOL bTemporaryFile; /* temporary file (MCI_RECORD) */
54 MMCKINFO ckMainRIFF; /* main RIFF chunk */
55 MMCKINFO ckWaveData; /* data chunk */
56} WINE_MCIWAVE;
57
58/* ===================================================================
59 * ===================================================================
60 * FIXME: should be using the new mmThreadXXXX functions from WINMM
61 * instead of those
62 * it would require to add a wine internal flag to mmThreadCreate
63 * in order to pass a 32 bit function instead of a 16 bit one
64 * ===================================================================
65 * =================================================================== */
66
67struct SCA {
68 UINT wDevID;
69 UINT wMsg;
70 DWORD dwParam1;
71 DWORD dwParam2;
72};
73
74/**************************************************************************
75 * MCI_SCAStarter [internal]
76 */
77static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
78{
79 struct SCA* sca = (struct SCA*)arg;
80 DWORD ret;
81
82 TRACE("In thread before async command (%08x,%u,%08lx,%08lx)\n",
83 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
84 ret = mciSendCommandA(sca->wDevID, sca->wMsg, sca->dwParam1 | MCI_WAIT, sca->dwParam2);
85 TRACE("In thread after async command (%08x,%u,%08lx,%08lx)\n",
86 sca->wDevID, sca->wMsg, sca->dwParam1, sca->dwParam2);
87 HeapFree(GetProcessHeap(), 0, sca);
88 ExitThread(ret);
89 WARN("Should not happen ? what's wrong \n");
90 /* should not go after this point */
91 return ret;
92}
93
94/**************************************************************************
95 * MCI_SendCommandAsync [internal]
96 */
97static DWORD MCI_SendCommandAsync(UINT wDevID, UINT wMsg, DWORD dwParam1,
98 DWORD dwParam2, UINT size)
99{
100 struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
101
102 if (sca == 0)
103 return MCIERR_OUT_OF_MEMORY;
104
105 sca->wDevID = wDevID;
106 sca->wMsg = wMsg;
107 sca->dwParam1 = dwParam1;
108
109 if (size && dwParam2) {
110 sca->dwParam2 = (DWORD)sca + sizeof(struct SCA);
111 /* copy structure passed by program in dwParam2 to be sure
112 * we can still use it whatever the program does
113 */
114 memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
115 } else {
116 sca->dwParam2 = dwParam2;
117 }
118
119 if (CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL) == 0) {
120 WARN("Couldn't allocate thread for async command handling, sending synchonously\n");
121 return MCI_SCAStarter(&sca);
122 }
123 return 0;
124}
125
126/*======================================================================*
127 * MCI WAVE implemantation *
128 *======================================================================*/
129
130static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
131
132/**************************************************************************
133 * MCIWAVE_drvOpen [internal]
134 */
135static DWORD WAVE_drvOpen(LPSTR str, LPMCI_OPEN_DRIVER_PARMSA modp)
136{
137 WINE_MCIWAVE* wmw;
138
139 if (modp == NULL) return 0xFFFFFFFF;
140
141 wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
142
143 if (!wmw)
144 return 0;
145
146 wmw->wDevID = modp->wDeviceID;
147 mciSetDriverData(wmw->wDevID, (DWORD)wmw);
148 modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
149 modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
150
151 wmw->wfxRef.wFormatTag = WAVE_FORMAT_PCM;
152 wmw->wfxRef.nChannels = 1; /* MONO */
153 wmw->wfxRef.nSamplesPerSec = 11025;
154 wmw->wfxRef.nAvgBytesPerSec = 11025;
155 wmw->wfxRef.nBlockAlign = 1;
156 wmw->wfxRef.wBitsPerSample = 8;
157 wmw->wfxRef.cbSize = 0; /* don't care */
158
159 return modp->wDeviceID;
160}
161
162/**************************************************************************
163 * MCIWAVE_drvClose [internal]
164 */
165static DWORD WAVE_drvClose(DWORD dwDevID)
166{
167 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
168
169 if (wmw) {
170 HeapFree(GetProcessHeap(), 0, wmw);
171 mciSetDriverData(dwDevID, 0);
172 return 1;
173 }
174 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
175}
176
177/**************************************************************************
178 * WAVE_mciGetOpenDev [internal]
179 */
180static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
181{
182 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
183
184 if (wmw == NULL || wmw->nUseCount == 0) {
185 WARN("Invalid wDevID=%u\n", wDevID);
186 return 0;
187 }
188 return wmw;
189}
190
191/**************************************************************************
192 * WAVE_ConvertByteToTimeFormat [internal]
193 */
194static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
195{
196 DWORD ret = 0;
197
198 switch (wmw->dwMciTimeFormat) {
199 case MCI_FORMAT_MILLISECONDS:
200 ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec);
201 break;
202 case MCI_FORMAT_BYTES:
203 ret = val;
204 break;
205 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
206 ret = (val * 8) / wmw->lpWaveFormat->wBitsPerSample;
207 break;
208 default:
209 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
210 }
211 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
212 *lpRet = 0;
213 return ret;
214}
215
216/**************************************************************************
217 * WAVE_ConvertTimeFormatToByte [internal]
218 */
219static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
220{
221 DWORD ret = 0;
222
223 switch (wmw->dwMciTimeFormat) {
224 case MCI_FORMAT_MILLISECONDS:
225 ret = (val * wmw->lpWaveFormat->nAvgBytesPerSec) / 1000;
226 break;
227 case MCI_FORMAT_BYTES:
228 ret = val;
229 break;
230 case MCI_FORMAT_SAMPLES: /* FIXME: is this correct ? */
231 ret = (val * wmw->lpWaveFormat->wBitsPerSample) / 8;
232 break;
233 default:
234 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
235 }
236 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
237 return ret;
238}
239
240/**************************************************************************
241 * WAVE_mciReadFmt [internal]
242 */
243static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
244{
245 MMCKINFO mmckInfo;
246 long r;
247
248 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
249 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
250 return MCIERR_INVALID_FILE;
251 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
252 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
253
254 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
255 if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
256 r = mmioRead(wmw->hFile, (HPSTR)wmw->lpWaveFormat, mmckInfo.cksize);
257 if (r < sizeof(WAVEFORMAT))
258 return MCIERR_INVALID_FILE;
259
260 TRACE("wFormatTag=%04X !\n", wmw->lpWaveFormat->wFormatTag);
261 TRACE("nChannels=%d \n", wmw->lpWaveFormat->nChannels);
262 TRACE("nSamplesPerSec=%ld\n", wmw->lpWaveFormat->nSamplesPerSec);
263 TRACE("nAvgBytesPerSec=%ld\n", wmw->lpWaveFormat->nAvgBytesPerSec);
264 TRACE("nBlockAlign=%d \n", wmw->lpWaveFormat->nBlockAlign);
265 TRACE("wBitsPerSample=%u !\n", wmw->lpWaveFormat->wBitsPerSample);
266 if (r >= (long)sizeof(WAVEFORMATEX))
267 TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
268
269 mmioAscend(wmw->hFile, &mmckInfo, 0);
270 wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
271 if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
272 TRACE("can't find data chunk\n");
273 return MCIERR_INVALID_FILE;
274 }
275 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
276 (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
277 TRACE("nChannels=%d nSamplesPerSec=%ld\n",
278 wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
279
280 return 0;
281}
282
283/**************************************************************************
284 * WAVE_mciCreateRIFFSkeleton [internal]
285 */
286static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
287{
288 MMCKINFO ckWaveFormat;
289 LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF);
290 LPMMCKINFO lpckWaveData = &(wmw->ckWaveData);
291
292 lpckRIFF->ckid = FOURCC_RIFF;
293 lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
294 lpckRIFF->cksize = 0;
295
296 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF))
297 goto err;
298
299 ckWaveFormat.fccType = 0;
300 ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' ');
301 ckWaveFormat.cksize = sizeof(PCMWAVEFORMAT);
302
303 if (!wmw->lpWaveFormat)
304 {
305 wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmw->lpWaveFormat));
306 if (!wmw->lpWaveFormat) return MMSYSERR_NOMEM;
307 memcpy(wmw->lpWaveFormat, &wmw->wfxRef, sizeof(wmw->wfxRef));
308 }
309
310 /* we can only record PCM files... there is no way in the MCI API to specify
311 * the necessary data to initialize the extra bytes of the WAVEFORMATEX
312 * structure
313 */
314 if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
315 goto err;
316
317 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
318 goto err;
319
320 if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, sizeof(PCMWAVEFORMAT)))
321 goto err;
322
323 if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
324 goto err;
325
326 lpckWaveData->cksize = 0;
327 lpckWaveData->fccType = 0;
328 lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a');
329
330 /* create data chunk */
331 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
332 goto err;
333
334 return 0;
335
336err:
337 if (wmw->lpWaveFormat)
338 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
339 wmw->lpWaveFormat = NULL;
340 return MCIERR_INVALID_FILE;
341}
342
343/**************************************************************************
344 * WAVE_mciOpen [internal]
345 */
346static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpOpenParms)
347{
348 DWORD dwRet = 0;
349 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
350 CHAR* pszTmpFileName = 0;
351
352 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
353 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
354 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
355
356 if (dwFlags & MCI_OPEN_SHAREABLE)
357 return MCIERR_HARDWARE;
358
359 if (wmw->nUseCount > 0) {
360 /* The driver is already opened on this channel
361 * Wave driver cannot be shared
362 */
363 return MCIERR_DEVICE_OPEN;
364 }
365
366 wmw->nUseCount++;
367
368 wmw->fInput = FALSE;
369 wmw->hWave = 0;
370 wmw->dwStatus = MCI_MODE_NOT_READY;
371
372 TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
373
374 if (dwFlags & MCI_OPEN_ELEMENT) {
375 if (dwFlags & MCI_OPEN_ELEMENT_ID) {
376 /* could it be that (DWORD)lpOpenParms->lpstrElementName
377 * contains the hFile value ?
378 */
379 dwRet = MCIERR_UNRECOGNIZED_COMMAND;
380 } else {
381 if (strlen(lpOpenParms->lpstrElementName) > 0) {
382 lpOpenParms->lpstrElementName = lpOpenParms->lpstrElementName;
383
384 /* FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
385 TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
386
387 if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) {
388 wmw->hFile = mmioOpenA((LPSTR)lpOpenParms->lpstrElementName, NULL,
389 MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
390
391 if (wmw->hFile == 0) {
392 WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName);
393 dwRet = MCIERR_FILE_NOT_FOUND;
394 }
395 else
396 {
397 LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF;
398
399 /* make sure we're are the beginning of the file */
400 mmioSeek(wmw->hFile, 0, SEEK_SET);
401
402 /* first reading of this file. read the waveformat chunk */
403 if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
404 dwRet = MCIERR_INVALID_FILE;
405 } else {
406 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
407 (LPSTR)&(lpckMainRIFF->ckid),
408 (LPSTR) &(lpckMainRIFF->fccType),
409 (lpckMainRIFF->cksize));
410
411 if ((lpckMainRIFF->ckid != FOURCC_RIFF) ||
412 lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
413 dwRet = MCIERR_INVALID_FILE;
414 } else {
415 dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
416 }
417 }
418 }
419 }
420 else {
421 wmw->hFile = 0;
422 }
423 }
424 else {
425 CHAR szTmpPath[MAX_PATH];
426 CHAR szPrefix[4] = "TMP\0";
427
428 pszTmpFileName = HeapAlloc(GetProcessHeap(),
429 HEAP_ZERO_MEMORY,
430 MAX_PATH * sizeof(*pszTmpFileName));
431
432 if (!GetTempPathA(sizeof(szTmpPath), szTmpPath)) {
433 WARN("can't retrieve temp path!\n");
434 HeapFree(GetProcessHeap(), 0, pszTmpFileName);
435 return MCIERR_FILE_NOT_FOUND;
436 }
437
438 if (!GetTempFileNameA(szTmpPath, szPrefix, 0, pszTmpFileName)) {
439 WARN("can't retrieve temp file name!\n");
440 HeapFree(GetProcessHeap(), 0, pszTmpFileName);
441 return MCIERR_FILE_NOT_FOUND;
442 }
443
444 wmw->bTemporaryFile = TRUE;
445
446 TRACE("MCI_OPEN_ELEMENT '%s' !\n", pszTmpFileName);
447
448 if (pszTmpFileName && (strlen(pszTmpFileName) > 0)) {
449
450 wmw->hFile = mmioOpenA(pszTmpFileName, NULL,
451 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
452
453 if (wmw->hFile == 0) {
454 /* temporary file could not be created. clean filename. */
455 HeapFree(GetProcessHeap(), 0, pszTmpFileName);
456 WARN("can't create file='%s' !\n", pszTmpFileName);
457 dwRet = MCIERR_FILE_NOT_FOUND;
458 }
459 }
460 }
461 }
462 }
463
464 TRACE("hFile=%p\n", wmw->hFile);
465
466 memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
467
468 if (wmw->bTemporaryFile == TRUE)
469 {
470 /* Additional openParms is temporary file's name */
471 wmw->openParms.lpstrElementName = pszTmpFileName;
472 }
473
474 if (dwRet == 0) {
475 if (wmw->lpWaveFormat) {
476 switch (wmw->lpWaveFormat->wFormatTag) {
477 case WAVE_FORMAT_PCM:
478 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
479 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
480 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
481 wmw->lpWaveFormat->nAvgBytesPerSec,
482 wmw->lpWaveFormat->nSamplesPerSec *
483 wmw->lpWaveFormat->nBlockAlign);
484 wmw->lpWaveFormat->nAvgBytesPerSec =
485 wmw->lpWaveFormat->nSamplesPerSec *
486 wmw->lpWaveFormat->nBlockAlign;
487 }
488 break;
489 }
490 }
491 wmw->dwPosition = 0;
492
493 wmw->dwStatus = MCI_MODE_STOP;
494 } else {
495 wmw->nUseCount--;
496 if (wmw->hFile != 0)
497 mmioClose(wmw->hFile, 0);
498 wmw->hFile = 0;
499 }
500 return dwRet;
501}
502
503/**************************************************************************
504 * WAVE_mciCue [internal]
505 */
506static DWORD WAVE_mciCue(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
507{
508 /*
509 FIXME
510
511 This routine is far from complete. At the moment only a check is done on the
512 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
513 is the default.
514
515 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
516 are ignored
517 */
518
519 DWORD dwRet;
520 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
521
522 FIXME("(%u, %08lX, %p); likely to fail\n", wDevID, dwParam, lpParms);
523
524 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
525
526 /* always close elements ? */
527 if (wmw->hFile != 0) {
528 mmioClose(wmw->hFile, 0);
529 wmw->hFile = 0;
530 }
531
532 dwRet = MMSYSERR_NOERROR; /* assume success */
533
534 if ((dwParam & MCI_WAVE_INPUT) && !wmw->fInput) {
535 dwRet = waveOutClose(wmw->hWave);
536 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
537 wmw->fInput = TRUE;
538 } else if (wmw->fInput) {
539 dwRet = waveInClose(wmw->hWave);
540 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
541 wmw->fInput = FALSE;
542 }
543 wmw->hWave = 0;
544 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
545}
546
547/**************************************************************************
548 * WAVE_mciStop [internal]
549 */
550static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
551{
552 DWORD dwRet = 0;
553 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
554
555 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
556
557 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
558
559 /* wait for playback thread (if any) to exit before processing further */
560 switch (wmw->dwStatus) {
561 case MCI_MODE_PAUSE:
562 case MCI_MODE_PLAY:
563 case MCI_MODE_RECORD:
564 {
565 int oldStat = wmw->dwStatus;
566 wmw->dwStatus = MCI_MODE_NOT_READY;
567 if (oldStat == MCI_MODE_PAUSE)
568 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
569 }
570 while (wmw->dwStatus != MCI_MODE_STOP)
571 Sleep(10);
572 break;
573 }
574
575 wmw->dwPosition = 0;
576
577 /* sanity resets */
578 wmw->dwStatus = MCI_MODE_STOP;
579
580 if ((dwFlags & MCI_NOTIFY) && lpParms) {
581 mciDriverNotify(lpParms->dwCallback,
582 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
583 }
584
585 return dwRet;
586}
587
588/**************************************************************************
589 * WAVE_mciClose [internal]
590 */
591static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
592{
593 DWORD dwRet = 0;
594 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
595
596 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
597
598 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
599
600 if (wmw->dwStatus != MCI_MODE_STOP) {
601 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
602 }
603
604 wmw->nUseCount--;
605
606 if (wmw->nUseCount == 0) {
607 if (wmw->hFile != 0) {
608 mmioClose(wmw->hFile, 0);
609 wmw->hFile = 0;
610 }
611 }
612
613 /* That string got allocated in mciOpen because no filename was specified
614 * in MCI_OPEN_PARMS stucture. Cast-away const from string since it was
615 * allocated by mciOpen, *NOT* the application.
616 */
617 if (wmw->bTemporaryFile)
618 {
619 HeapFree(GetProcessHeap(), 0, (char*)wmw->openParms.lpstrElementName);
620 wmw->openParms.lpstrElementName = NULL;
621 }
622
623 HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
624 wmw->lpWaveFormat = NULL;
625
626 if ((dwFlags & MCI_NOTIFY) && lpParms) {
627 mciDriverNotify(lpParms->dwCallback,
628 wmw->openParms.wDeviceID,
629 (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
630 }
631
632 return 0;
633}
634
635/**************************************************************************
636 * WAVE_mciPlayCallback [internal]
637 */
638static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
639 DWORD dwInstance,
640 DWORD dwParam1, DWORD dwParam2)
641{
642 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
643
644 switch (uMsg) {
645 case WOM_OPEN:
646 case WOM_CLOSE:
647 break;
648 case WOM_DONE:
649 InterlockedIncrement(&wmw->dwEventCount);
650 TRACE("Returning waveHdr=%lx\n", dwParam1);
651 SetEvent(wmw->hEvent);
652 break;
653 default:
654 ERR("Unknown uMsg=%d\n", uMsg);
655 }
656}
657
658/******************************************************************
659 * WAVE_mciPlayWaitDone
660 *
661 *
662 */
663static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
664{
665 for (;;) {
666 ResetEvent(wmw->hEvent);
667 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
668 break;
669 }
670 InterlockedIncrement(&wmw->dwEventCount);
671
672 WaitForSingleObject(wmw->hEvent, INFINITE);
673 }
674}
675
676/**************************************************************************
677 * WAVE_mciPlay [internal]
678 */
679static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
680{
681 DWORD end;
682 LONG bufsize, count, left;
683 DWORD dwRet = 0;
684 LPWAVEHDR waveHdr = NULL;
685 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
686 int whidx;
687
688 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
689
690 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
691 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
692
693 /* FIXME : since there is no way to determine in which mode the device is
694 * open (recording/playback) automatically switch from a mode to another
695 */
696 wmw->fInput = FALSE;
697
698 if (wmw->fInput) {
699 WARN("cannot play on input device\n");
700 return MCIERR_NONAPPLICABLE_FUNCTION;
701 }
702
703 if (wmw->hFile == 0) {
704 WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
705 return MCIERR_FILE_NOT_FOUND;
706 }
707
708 if (wmw->dwStatus == MCI_MODE_PAUSE) {
709 /* FIXME: parameters (start/end) in lpParams may not be used */
710 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
711 }
712
713 /** This function will be called again by a thread when async is used.
714 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
715 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
716 */
717 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_PLAY) && (dwFlags & MCI_WAIT))) {
718 return MCIERR_INTERNAL;
719 }
720
721 wmw->dwStatus = MCI_MODE_PLAY;
722
723 if (!(dwFlags & MCI_WAIT)) {
724 return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_PLAY, dwFlags,
725 (DWORD)lpParms, sizeof(MCI_PLAY_PARMS));
726 }
727
728 end = 0xFFFFFFFF;
729 if (lpParms && (dwFlags & MCI_FROM)) {
730 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
731 }
732 if (lpParms && (dwFlags & MCI_TO)) {
733 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
734 }
735
736 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
737
738 if (end <= wmw->dwPosition)
739 return TRUE;
740
741
742#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
743((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
744
745 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
746 wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
747
748 if (dwRet == 0) {
749 if (wmw->lpWaveFormat) {
750 switch (wmw->lpWaveFormat->wFormatTag) {
751 case WAVE_FORMAT_PCM:
752 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
753 wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
754 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
755 wmw->lpWaveFormat->nAvgBytesPerSec,
756 wmw->lpWaveFormat->nSamplesPerSec *
757 wmw->lpWaveFormat->nBlockAlign);
758 wmw->lpWaveFormat->nAvgBytesPerSec =
759 wmw->lpWaveFormat->nSamplesPerSec *
760 wmw->lpWaveFormat->nBlockAlign;
761 }
762 break;
763 }
764 }
765 } else {
766 TRACE("can't retrieve wave format %ld\n", dwRet);
767 goto cleanUp;
768 }
769
770
771 /* go back to beginning of chunk plus the requested position */
772 /* FIXME: I'm not sure this is correct, notably because some data linked to
773 * the decompression state machine will not be correcly initialized.
774 * try it this way (other way would be to decompress from 0 up to dwPosition
775 * and to start sending to hWave when dwPosition is reached)
776 */
777 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
778
779 /* By default the device will be opened for output, the MCI_CUE function is there to
780 * change from output to input and back
781 */
782 /* FIXME: how to choose between several output channels ? here mapper is forced */
783 dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
784 (DWORD)WAVE_mciPlayCallback, (DWORD)wmw, CALLBACK_FUNCTION);
785
786 if (dwRet != 0) {
787 TRACE("Can't open low level audio device %ld\n", dwRet);
788 dwRet = MCIERR_DEVICE_OPEN;
789 wmw->hWave = 0;
790 goto cleanUp;
791 }
792
793 /* make it so that 3 buffers per second are needed */
794 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
795
796 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
797 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
798 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
799 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
800 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
801 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
802 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
803 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
804 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
805 dwRet = MCIERR_INTERNAL;
806 goto cleanUp;
807 }
808
809 whidx = 0;
810 left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition);
811 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
812 wmw->dwEventCount = 1L; /* for first buffer */
813
814 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
815
816 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
817 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
818 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
819 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
820 if (count < 1)
821 break;
822 /* count is always <= bufsize, so this is correct regarding the
823 * waveOutPrepareHeader function
824 */
825 waveHdr[whidx].dwBufferLength = count;
826 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
827 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
828 &waveHdr[whidx], waveHdr[whidx].dwBufferLength,
829 waveHdr[whidx].dwBytesRecorded);
830 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
831 left -= count;
832 wmw->dwPosition += count;
833 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
834
835 WAVE_mciPlayWaitDone(wmw);
836 whidx ^= 1;
837 }
838
839 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
840
841 /* just to get rid of some race conditions between play, stop and pause */
842 waveOutReset(wmw->hWave);
843
844 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
845 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
846
847 dwRet = 0;
848
849cleanUp:
850 HeapFree(GetProcessHeap(), 0, waveHdr);
851
852 if (wmw->hWave) {
853 waveOutClose(wmw->hWave);
854 wmw->hWave = 0;
855 }
856 CloseHandle(wmw->hEvent);
857
858 if (lpParms && (dwFlags & MCI_NOTIFY)) {
859 mciDriverNotify(lpParms->dwCallback,
860 wmw->openParms.wDeviceID,
861 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
862 }
863
864 wmw->dwStatus = MCI_MODE_STOP;
865
866 return dwRet;
867}
868
869/**************************************************************************
870 * WAVE_mciPlayCallback [internal]
871 */
872static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
873 DWORD dwInstance,
874 DWORD dwParam1, DWORD dwParam2)
875{
876 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
877 LPWAVEHDR lpWaveHdr;
878 LONG count = 0;
879
880 switch (uMsg) {
881 case WIM_OPEN:
882 case WIM_CLOSE:
883 break;
884 case WIM_DATA:
885 lpWaveHdr = (LPWAVEHDR) dwParam1;
886
887 InterlockedIncrement(&wmw->dwEventCount);
888
889 count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
890
891 lpWaveHdr->dwFlags &= ~WHDR_DONE;
892 if (count > 0)
893 wmw->dwPosition += count;
894 /* else error reporting ?? */
895 if (wmw->dwStatus == MCI_MODE_RECORD)
896 {
897 /* Only queue up another buffer if we are recording. We could receive this
898 message also when waveInReset() is called, since it notifies on all wave
899 buffers that are outstanding. Queueing up more sometimes causes waveInClose
900 to fail. */
901 waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
902 TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
903 }
904
905 SetEvent(wmw->hEvent);
906 break;
907 default:
908 ERR("Unknown uMsg=%d\n", uMsg);
909 }
910}
911
912/******************************************************************
913 * bWAVE_mciRecordWaitDone
914 *
915 */
916static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
917{
918 for (;;) {
919 ResetEvent(wmw->hEvent);
920 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
921 break;
922 }
923 InterlockedIncrement(&wmw->dwEventCount);
924
925 WaitForSingleObject(wmw->hEvent, INFINITE);
926 }
927}
928
929/**************************************************************************
930 * WAVE_mciRecord [internal]
931 */
932static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
933{
934 DWORD end;
935 DWORD dwRet = MMSYSERR_NOERROR;
936 LONG bufsize;
937 LPWAVEHDR waveHdr = NULL;
938 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
939
940
941 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
942
943 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
944 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
945
946 /* FIXME : since there is no way to determine in which mode the device is
947 * open (recording/playback) automatically switch from a mode to another
948 */
949 wmw->fInput = TRUE;
950
951 if (!wmw->fInput) {
952 WARN("cannot record on output device\n");
953 return MCIERR_NONAPPLICABLE_FUNCTION;
954 }
955
956 if (wmw->dwStatus == MCI_MODE_PAUSE) {
957 /* FIXME: parameters (start/end) in lpParams may not be used */
958 return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
959 }
960
961 /** This function will be called again by a thread when async is used.
962 * We have to set MCI_MODE_PLAY before we do this so that the app can spin
963 * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
964 */
965 if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
966 return MCIERR_INTERNAL;
967 }
968
969 wmw->dwStatus = MCI_MODE_RECORD;
970
971 if (!(dwFlags & MCI_WAIT)) {
972 return MCI_SendCommandAsync(wmw->openParms.wDeviceID, MCI_RECORD, dwFlags,
973 (DWORD)lpParms, sizeof(MCI_RECORD_PARMS));
974 }
975
976 if (!wmw->lpWaveFormat) {
977 /* new RIFF file */
978 dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
979 } else {
980 FIXME("Should descend into data chunk. Please report.\n");
981 }
982
983 end = 0xFFFFFFFF;
984 if (lpParms && (dwFlags & MCI_FROM)) {
985 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
986 }
987
988 if (lpParms && (dwFlags & MCI_TO)) {
989 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
990 }
991
992 TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
993
994 if (end <= wmw->dwPosition)
995 {
996 return TRUE;
997 }
998
999#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1000((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1001
1002 wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
1003 wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1004
1005 /* go back to beginning of chunk plus the requested position */
1006 /* FIXME: I'm not sure this is correct, notably because some data linked to
1007 * the decompression state machine will not be correcly initialized.
1008 * try it this way (other way would be to decompress from 0 up to dwPosition
1009 * and to start sending to hWave when dwPosition is reached)
1010 */
1011 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1012
1013 /* By default the device will be opened for output, the MCI_CUE function is there to
1014 * change from output to input and back
1015 */
1016 /* FIXME: how to choose between several output channels ? here mapper is forced */
1017 dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
1018 (DWORD)WAVE_mciRecordCallback, (DWORD)wmw, CALLBACK_FUNCTION);
1019
1020 if (dwRet != MMSYSERR_NOERROR) {
1021 TRACE("Can't open low level audio device %ld\n", dwRet);
1022 dwRet = MCIERR_DEVICE_OPEN;
1023 wmw->hWave = 0;
1024 goto cleanUp;
1025 }
1026
1027 /* make it so that 3 buffers per second are needed */
1028 bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1029
1030 waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1031 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1032 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1033 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
1034 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
1035 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
1036 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1037
1038 if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1039 waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1040 dwRet = MCIERR_INTERNAL;
1041 goto cleanUp;
1042 }
1043
1044 if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1045 waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1046 dwRet = MCIERR_INTERNAL;
1047 goto cleanUp;
1048 }
1049
1050 wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1051 wmw->dwEventCount = 1L; /* for first buffer */
1052
1053 TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1054
1055 dwRet = waveInStart(wmw->hWave);
1056
1057 while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1058 WAVE_mciRecordWaitDone(wmw);
1059 }
1060
1061 /* needed so that the callback above won't add again the buffers returned by the reset */
1062 wmw->dwStatus = MCI_MODE_STOP;
1063
1064 waveInReset(wmw->hWave);
1065
1066 waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1067 waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1068
1069 dwRet = 0;
1070
1071cleanUp:
1072 HeapFree(GetProcessHeap(), 0, waveHdr);
1073
1074 if (wmw->hWave) {
1075 waveInClose(wmw->hWave);
1076 wmw->hWave = 0;
1077 }
1078 CloseHandle(wmw->hEvent);
1079
1080 /* need to update the size of the data chunk */
1081 if (mmioAscend(wmw->hFile, &wmw->ckWaveData, 0) != MMSYSERR_NOERROR) {
1082 TRACE("failed on ascend\n");
1083 }
1084
1085 if (lpParms && (dwFlags & MCI_NOTIFY)) {
1086 mciDriverNotify(lpParms->dwCallback,
1087 wmw->openParms.wDeviceID,
1088 dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1089 }
1090
1091 wmw->dwStatus = MCI_MODE_STOP;
1092
1093 return dwRet;
1094
1095}
1096
1097/**************************************************************************
1098 * WAVE_mciPause [internal]
1099 */
1100static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1101{
1102 DWORD dwRet;
1103 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1104
1105 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1106
1107 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1108 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1109
1110 if (wmw->dwStatus == MCI_MODE_PLAY) {
1111 wmw->dwStatus = MCI_MODE_PAUSE;
1112 }
1113
1114 if (wmw->fInput) dwRet = waveInStop(wmw->hWave);
1115 else dwRet = waveOutPause(wmw->hWave);
1116
1117 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1118}
1119
1120/**************************************************************************
1121 * WAVE_mciResume [internal]
1122 */
1123static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1124{
1125 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1126 DWORD dwRet = 0;
1127
1128 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1129
1130 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1131
1132 if (wmw->dwStatus == MCI_MODE_PAUSE) {
1133 wmw->dwStatus = MCI_MODE_PLAY;
1134 }
1135
1136 if (wmw->fInput) dwRet = waveInStart(wmw->hWave);
1137 else dwRet = waveOutRestart(wmw->hWave);
1138 return (dwRet == MMSYSERR_NOERROR) ? 0 : MCIERR_INTERNAL;
1139}
1140
1141/**************************************************************************
1142 * WAVE_mciSeek [internal]
1143 */
1144static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1145{
1146 DWORD ret = 0;
1147 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1148
1149 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1150
1151 if (lpParms == NULL) {
1152 ret = MCIERR_NULL_PARAMETER_BLOCK;
1153 } else if (wmw == NULL) {
1154 ret = MCIERR_INVALID_DEVICE_ID;
1155 } else {
1156 WAVE_mciStop(wDevID, MCI_WAIT, 0);
1157
1158 if (dwFlags & MCI_SEEK_TO_START) {
1159 wmw->dwPosition = 0;
1160 } else if (dwFlags & MCI_SEEK_TO_END) {
1161 wmw->dwPosition = wmw->ckWaveData.cksize;
1162 } else if (dwFlags & MCI_TO) {
1163 wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1164 } else {
1165 WARN("dwFlag doesn't tell where to seek to...\n");
1166 return MCIERR_MISSING_PARAMETER;
1167 }
1168
1169 TRACE("Seeking to position=%lu bytes\n", wmw->dwPosition);
1170
1171 if (dwFlags & MCI_NOTIFY) {
1172 mciDriverNotify(lpParms->dwCallback,
1173 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1174 }
1175 }
1176 return ret;
1177}
1178
1179/**************************************************************************
1180 * WAVE_mciSet [internal]
1181 */
1182static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1183{
1184 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1185
1186 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1187
1188 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1189 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1190
1191 if (dwFlags & MCI_SET_TIME_FORMAT) {
1192 switch (lpParms->dwTimeFormat) {
1193 case MCI_FORMAT_MILLISECONDS:
1194 TRACE("MCI_FORMAT_MILLISECONDS !\n");
1195 wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1196 break;
1197 case MCI_FORMAT_BYTES:
1198 TRACE("MCI_FORMAT_BYTES !\n");
1199 wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1200 break;
1201 case MCI_FORMAT_SAMPLES:
1202 TRACE("MCI_FORMAT_SAMPLES !\n");
1203 wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1204 break;
1205 default:
1206 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
1207 return MCIERR_BAD_TIME_FORMAT;
1208 }
1209 }
1210 if (dwFlags & MCI_SET_VIDEO) {
1211 TRACE("No support for video !\n");
1212 return MCIERR_UNSUPPORTED_FUNCTION;
1213 }
1214 if (dwFlags & MCI_SET_DOOR_OPEN) {
1215 TRACE("No support for door open !\n");
1216 return MCIERR_UNSUPPORTED_FUNCTION;
1217 }
1218 if (dwFlags & MCI_SET_DOOR_CLOSED) {
1219 TRACE("No support for door close !\n");
1220 return MCIERR_UNSUPPORTED_FUNCTION;
1221 }
1222 if (dwFlags & MCI_SET_AUDIO) {
1223 if (dwFlags & MCI_SET_ON) {
1224 TRACE("MCI_SET_ON audio !\n");
1225 } else if (dwFlags & MCI_SET_OFF) {
1226 TRACE("MCI_SET_OFF audio !\n");
1227 } else {
1228 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1229 return MCIERR_BAD_INTEGER;
1230 }
1231
1232 if (lpParms->dwAudio & MCI_SET_AUDIO_ALL)
1233 TRACE("MCI_SET_AUDIO_ALL !\n");
1234 if (lpParms->dwAudio & MCI_SET_AUDIO_LEFT)
1235 TRACE("MCI_SET_AUDIO_LEFT !\n");
1236 if (lpParms->dwAudio & MCI_SET_AUDIO_RIGHT)
1237 TRACE("MCI_SET_AUDIO_RIGHT !\n");
1238 }
1239 if (dwFlags & MCI_WAVE_INPUT)
1240 TRACE("MCI_WAVE_INPUT !\n");
1241 if (dwFlags & MCI_WAVE_OUTPUT)
1242 TRACE("MCI_WAVE_OUTPUT !\n");
1243 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
1244 TRACE("MCI_WAVE_SET_ANYINPUT !\n");
1245 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
1246 TRACE("MCI_WAVE_SET_ANYOUTPUT !\n");
1247 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1248 wmw->wfxRef.nAvgBytesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nAvgBytesPerSec;
1249 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %ld\n", wmw->wfxRef.nAvgBytesPerSec);
1250 }
1251 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1252 wmw->wfxRef.wBitsPerSample = ((LPMCI_WAVE_SET_PARMS)lpParms)->wBitsPerSample;
1253 TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1254 }
1255 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1256 wmw->wfxRef.nBlockAlign = ((LPMCI_WAVE_SET_PARMS)lpParms)->nBlockAlign;
1257 TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1258 }
1259 if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1260 wmw->wfxRef.nChannels = ((LPMCI_WAVE_SET_PARMS)lpParms)->nChannels;
1261 TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1262 }
1263 if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1264 wmw->wfxRef.wFormatTag = ((LPMCI_WAVE_SET_PARMS)lpParms)->wFormatTag;
1265 TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", wmw->wfxRef.wFormatTag);
1266 }
1267 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1268 wmw->wfxRef.nSamplesPerSec = ((LPMCI_WAVE_SET_PARMS)lpParms)->nSamplesPerSec;
1269 TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %ld\n", wmw->wfxRef.nSamplesPerSec);
1270 }
1271 return 0;
1272}
1273
1274/**************************************************************************
1275 * WAVE_mciSave [internal]
1276 */
1277static DWORD WAVE_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_SAVE_PARMS lpParms)
1278{
1279 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1280 DWORD ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1281 WPARAM wparam = MCI_NOTIFY_FAILURE;
1282
1283 TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1284 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1285 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1286
1287 if (dwFlags & MCI_WAIT)
1288 {
1289 FIXME("MCI_WAIT not implemented\n");
1290 }
1291
1292 ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1293 ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1294
1295
1296 ret = mmioClose(wmw->hFile, 0);
1297
1298 /*
1299 If the destination file already exists, it has to be overwritten. (Behaviour
1300 verified in Windows (2000)). If it doesn't overwrite, it is breaking one of
1301 my applications. We are making use of mmioRename, which WILL NOT overwrite
1302 the destination file (which is what Windows does, also verified in Win2K)
1303 So, lets delete the destination file before calling mmioRename. If the
1304 destination file DOESN'T exist, the delete will fail silently. Let's also be
1305 careful not to lose our previous error code.
1306 */
1307 tmpRet = GetLastError();
1308 DeleteFileA (lpParms->lpfilename);
1309 SetLastError(tmpRet);
1310
1311 if (0 == mmioRenameA(wmw->openParms.lpstrElementName, lpParms->lpfilename, 0, 0 )) {
1312 ret = ERROR_SUCCESS;
1313 }
1314
1315 if (dwFlags & MCI_NOTIFY) {
1316 if (ret == ERROR_SUCCESS) wparam = MCI_NOTIFY_SUCCESSFUL;
1317
1318 mciDriverNotify(lpParms->dwCallback,
1319 wmw->openParms.wDeviceID, wparam);
1320 }
1321
1322 return ret;
1323}
1324
1325/**************************************************************************
1326 * WAVE_mciStatus [internal]
1327 */
1328static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1329{
1330 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1331 DWORD ret = 0;
1332
1333 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1334 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1335 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1336
1337 if (dwFlags & MCI_STATUS_ITEM) {
1338 switch (lpParms->dwItem) {
1339 case MCI_STATUS_CURRENT_TRACK:
1340 lpParms->dwReturn = 1;
1341 TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1342 break;
1343 case MCI_STATUS_LENGTH:
1344 if (!wmw->hFile) {
1345 lpParms->dwReturn = 0;
1346 return MCIERR_UNSUPPORTED_FUNCTION;
1347 }
1348 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1349 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
1350 TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1351 break;
1352 case MCI_STATUS_MODE:
1353 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1354 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1355 ret = MCI_RESOURCE_RETURNED;
1356 break;
1357 case MCI_STATUS_MEDIA_PRESENT:
1358 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1359 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1360 ret = MCI_RESOURCE_RETURNED;
1361 break;
1362 case MCI_STATUS_NUMBER_OF_TRACKS:
1363 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1364 lpParms->dwReturn = 1;
1365 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu!\n", lpParms->dwReturn);
1366 break;
1367 case MCI_STATUS_POSITION:
1368 if (!wmw->hFile) {
1369 lpParms->dwReturn = 0;
1370 return MCIERR_UNSUPPORTED_FUNCTION;
1371 }
1372 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1373 lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1374 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition,
1375 &ret);
1376 TRACE("MCI_STATUS_POSITION %s => %lu\n",
1377 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1378 break;
1379 case MCI_STATUS_READY:
1380 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1381 MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1382 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1383 ret = MCI_RESOURCE_RETURNED;
1384 break;
1385 case MCI_STATUS_TIME_FORMAT:
1386 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, MCI_FORMAT_RETURN_BASE + wmw->dwMciTimeFormat);
1387 TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1388 ret = MCI_RESOURCE_RETURNED;
1389 break;
1390 case MCI_WAVE_INPUT:
1391 TRACE("MCI_WAVE_INPUT !\n");
1392 lpParms->dwReturn = 0;
1393 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1394 break;
1395 case MCI_WAVE_OUTPUT:
1396 TRACE("MCI_WAVE_OUTPUT !\n");
1397 {
1398 UINT id;
1399 if (waveOutGetID(wmw->hWave, &id) == MMSYSERR_NOERROR) {
1400 lpParms->dwReturn = id;
1401 } else {
1402 lpParms->dwReturn = 0;
1403 ret = MCIERR_WAVE_INPUTUNSPECIFIED;
1404 }
1405 }
1406 break;
1407 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1408 if (!wmw->hFile) {
1409 lpParms->dwReturn = 0;
1410 return MCIERR_UNSUPPORTED_FUNCTION;
1411 }
1412 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1413 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu!\n", lpParms->dwReturn);
1414 break;
1415 case MCI_WAVE_STATUS_BITSPERSAMPLE:
1416 if (!wmw->hFile) {
1417 lpParms->dwReturn = 0;
1418 return MCIERR_UNSUPPORTED_FUNCTION;
1419 }
1420 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1421 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu!\n", lpParms->dwReturn);
1422 break;
1423 case MCI_WAVE_STATUS_BLOCKALIGN:
1424 if (!wmw->hFile) {
1425 lpParms->dwReturn = 0;
1426 return MCIERR_UNSUPPORTED_FUNCTION;
1427 }
1428 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1429 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu!\n", lpParms->dwReturn);
1430 break;
1431 case MCI_WAVE_STATUS_CHANNELS:
1432 if (!wmw->hFile) {
1433 lpParms->dwReturn = 0;
1434 return MCIERR_UNSUPPORTED_FUNCTION;
1435 }
1436 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1437 TRACE("MCI_WAVE_STATUS_CHANNELS => %lu!\n", lpParms->dwReturn);
1438 break;
1439 case MCI_WAVE_STATUS_FORMATTAG:
1440 if (!wmw->hFile) {
1441 lpParms->dwReturn = 0;
1442 return MCIERR_UNSUPPORTED_FUNCTION;
1443 }
1444 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1445 TRACE("MCI_WAVE_FORMATTAG => %lu!\n", lpParms->dwReturn);
1446 break;
1447 case MCI_WAVE_STATUS_LEVEL:
1448 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1449 lpParms->dwReturn = 0xAAAA5555;
1450 break;
1451 case MCI_WAVE_STATUS_SAMPLESPERSEC:
1452 if (!wmw->hFile) {
1453 lpParms->dwReturn = 0;
1454 return MCIERR_UNSUPPORTED_FUNCTION;
1455 }
1456 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1457 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu!\n", lpParms->dwReturn);
1458 break;
1459 default:
1460 WARN("unknown command %08lX !\n", lpParms->dwItem);
1461 return MCIERR_UNRECOGNIZED_COMMAND;
1462 }
1463 }
1464 if (dwFlags & MCI_NOTIFY) {
1465 mciDriverNotify(lpParms->dwCallback,
1466 wmw->openParms.wDeviceID, MCI_NOTIFY_SUCCESSFUL);
1467 }
1468 return ret;
1469}
1470
1471/**************************************************************************
1472 * WAVE_mciGetDevCaps [internal]
1473 */
1474static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags,
1475 LPMCI_GETDEVCAPS_PARMS lpParms)
1476{
1477 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1478 DWORD ret = 0;
1479
1480 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1481
1482 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1483 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1484
1485 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1486 switch(lpParms->dwItem) {
1487 case MCI_GETDEVCAPS_DEVICE_TYPE:
1488 lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1489 ret = MCI_RESOURCE_RETURNED;
1490 break;
1491 case MCI_GETDEVCAPS_HAS_AUDIO:
1492 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1493 ret = MCI_RESOURCE_RETURNED;
1494 break;
1495 case MCI_GETDEVCAPS_HAS_VIDEO:
1496 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1497 ret = MCI_RESOURCE_RETURNED;
1498 break;
1499 case MCI_GETDEVCAPS_USES_FILES:
1500 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1501 ret = MCI_RESOURCE_RETURNED;
1502 break;
1503 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1504 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1505 ret = MCI_RESOURCE_RETURNED;
1506 break;
1507 case MCI_GETDEVCAPS_CAN_RECORD:
1508 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1509 ret = MCI_RESOURCE_RETURNED;
1510 break;
1511 case MCI_GETDEVCAPS_CAN_EJECT:
1512 lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1513 ret = MCI_RESOURCE_RETURNED;
1514 break;
1515 case MCI_GETDEVCAPS_CAN_PLAY:
1516 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1517 ret = MCI_RESOURCE_RETURNED;
1518 break;
1519 case MCI_GETDEVCAPS_CAN_SAVE:
1520 lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1521 ret = MCI_RESOURCE_RETURNED;
1522 break;
1523 case MCI_WAVE_GETDEVCAPS_INPUTS:
1524 lpParms->dwReturn = 1;
1525 break;
1526 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1527 lpParms->dwReturn = 1;
1528 break;
1529 default:
1530 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1531 return MCIERR_UNRECOGNIZED_COMMAND;
1532 }
1533 } else {
1534 WARN("No GetDevCaps-Item !\n");
1535 return MCIERR_UNRECOGNIZED_COMMAND;
1536 }
1537 return ret;
1538}
1539
1540/**************************************************************************
1541 * WAVE_mciInfo [internal]
1542 */
1543static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSA lpParms)
1544{
1545 DWORD ret = 0;
1546 LPCSTR str = 0;
1547 WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1548
1549 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1550
1551 if (lpParms == NULL || lpParms->lpstrReturn == NULL) {
1552 ret = MCIERR_NULL_PARAMETER_BLOCK;
1553 } else if (wmw == NULL) {
1554 ret = MCIERR_INVALID_DEVICE_ID;
1555 } else {
1556 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1557
1558 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1559 case MCI_INFO_PRODUCT:
1560 str = "Wine's audio player";
1561 break;
1562 case MCI_INFO_FILE:
1563 str = wmw->openParms.lpstrElementName;
1564 break;
1565 case MCI_WAVE_INPUT:
1566 str = "Wine Wave In";
1567 break;
1568 case MCI_WAVE_OUTPUT:
1569 str = "Wine Wave Out";
1570 break;
1571 default:
1572 WARN("Don't know this info command (%lu)\n", dwFlags);
1573 ret = MCIERR_UNRECOGNIZED_COMMAND;
1574 }
1575 }
1576 if (str) {
1577 if (strlen(str) + 1 > lpParms->dwRetSize) {
1578 ret = MCIERR_PARAM_OVERFLOW;
1579 } else {
1580 lstrcpynA(lpParms->lpstrReturn, str, lpParms->dwRetSize);
1581 }
1582 } else {
1583 lpParms->lpstrReturn[0] = 0;
1584 }
1585
1586 return ret;
1587}
1588
1589/**************************************************************************
1590 * DriverProc (MCIWAVE.@)
1591 */
1592LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1593 DWORD dwParam1, DWORD dwParam2)
1594{
1595 TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1596 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1597
1598 switch (wMsg) {
1599 case DRV_LOAD: return 1;
1600 case DRV_FREE: return 1;
1601 case DRV_OPEN: return WAVE_drvOpen((LPSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSA)dwParam2);
1602 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1603 case DRV_ENABLE: return 1;
1604 case DRV_DISABLE: return 1;
1605 case DRV_QUERYCONFIGURE: return 1;
1606 case DRV_CONFIGURE: MessageBoxA(0, "Sample MultiMedia Driver !", "OSS Driver", MB_OK); return 1;
1607 case DRV_INSTALL: return DRVCNF_RESTART;
1608 case DRV_REMOVE: return DRVCNF_RESTART;
1609 }
1610
1611 if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1612
1613 switch (wMsg) {
1614 case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSA) dwParam2);
1615 case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1616 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1617 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1618 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, (LPMCI_RECORD_PARMS) dwParam2);
1619 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1620 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_SET_PARMS) dwParam2);
1621 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1622 case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1623 case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1624 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1625 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
1626 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1627 case MCI_SAVE: return WAVE_mciSave (dwDevID, dwParam1, (LPMCI_SAVE_PARMS) dwParam2);
1628 /* commands that should be supported */
1629 case MCI_LOAD:
1630 case MCI_FREEZE:
1631 case MCI_PUT:
1632 case MCI_REALIZE:
1633 case MCI_UNFREEZE:
1634 case MCI_UPDATE:
1635 case MCI_WHERE:
1636 case MCI_STEP:
1637 case MCI_SPIN:
1638 case MCI_ESCAPE:
1639 case MCI_COPY:
1640 case MCI_CUT:
1641 case MCI_DELETE:
1642 case MCI_PASTE:
1643 FIXME("Unsupported yet command [%lu]\n", wMsg);
1644 break;
1645 case MCI_WINDOW:
1646 TRACE("Unsupported command [%lu]\n", wMsg);
1647 break;
1648 /* option which can be silenced */
1649 case MCI_CONFIGURE:
1650 return 0;
1651 case MCI_OPEN:
1652 case MCI_CLOSE:
1653 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1654 break;
1655 default:
1656 FIXME("is probably wrong msg [%lu]\n", wMsg);
1657 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1658 }
1659 return MCIERR_UNRECOGNIZED_COMMAND;
1660}
Note: See TracBrowser for help on using the repository browser.