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

Last change on this file since 22014 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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