ReactOS 0.4.17-dev-966-gf06eace
mciwave.c
Go to the documentation of this file.
1/*
2 * Wine Driver for MCI wave forms
3 *
4 * Copyright 1994 Martin Ayotte
5 * 1999,2000,2005 Eric Pouech
6 * 2000 Francois Jacques
7 * 2009 Jörg Höhle
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <assert.h>
25#include <stdarg.h>
26
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
37
38typedef struct {
41 int nUseCount; /* Incremented for each shared open */
42 HMMIO hFile; /* mmio file handle open as Element */
43 MCIDEVICEID wNotifyDeviceID; /* MCI device ID with a pending notification */
44 HANDLE hCallback; /* Callback handle for pending notification */
45 LPWSTR lpFileName; /* Name of file (if any) */
47 LPWAVEFORMATEX lpWaveFormat; /* Points to wfxRef until set by OPEN or RECORD */
48 BOOL fInput; /* FALSE = Output, TRUE = Input */
49 WORD wInput; /* wave input device */
50 WORD wOutput; /* wave output device */
51 volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
52 DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
53 DWORD dwPosition; /* position in bytes in chunk */
54 HANDLE hEvent; /* for synchronization */
55 LONG dwEventCount; /* for synchronization */
56 MMCKINFO ckMainRIFF; /* main RIFF chunk */
57 MMCKINFO ckWaveData; /* data chunk */
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
70
71struct SCA {
77};
78
79/**************************************************************************
80 * MCI_SCAStarter [internal]
81 */
83{
84 struct SCA* sca = (struct SCA*)arg;
85 DWORD ret;
86
87 TRACE("In thread before async command (%08x,%08Ix,%08Ix)\n",
88 sca->wDevID, sca->dwParam1, sca->dwParam2);
89 ret = sca->cmd(sca->wDevID, sca->dwParam1 | MCI_WAIT, sca->dwParam2, sca->evt);
90 TRACE("In thread after async command (%08x,%08Ix,%08Ix)\n",
91 sca->wDevID, sca->dwParam1, sca->dwParam2);
92 free(sca);
93 return ret;
94}
95
96/**************************************************************************
97 * MCI_SendCommandAsync [internal]
98 */
101{
102 HANDLE handles[2];
103 struct SCA* sca = malloc(sizeof(struct SCA) + size);
104
105 if (sca == 0)
107
108 sca->wDevID = wDevID;
109 sca->cmd = cmd;
110 sca->dwParam1 = dwParam1;
111
112 if (size && dwParam2) {
113 sca->dwParam2 = (DWORD_PTR)sca + sizeof(struct SCA);
114 /* copy structure passed by program in dwParam2 to be sure
115 * we can still use it whatever the program does
116 */
118 } else {
119 sca->dwParam2 = dwParam2;
120 }
121
122 if ((sca->evt = handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL)) == NULL ||
123 (handles[0] = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
124 WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
125 if (handles[1]) CloseHandle(handles[1]);
126 sca->evt = NULL;
127 return MCI_SCAStarter(sca);
128 }
129
131 /* wait until either:
132 * - the thread has finished (handles[0], likely an error)
133 * - init phase of async command is done (handles[1])
134 */
138 return 0;
139}
140
141/*======================================================================*
142 * MCI WAVE implementation *
143 *======================================================================*/
144
146
147/**************************************************************************
148 * MCIWAVE_drvOpen [internal]
149 */
151{
152 WINE_MCIWAVE* wmw;
153
154 if (modp == NULL) return 0xFFFFFFFF;
155
157
158 if (!wmw)
159 return 0;
160
161 wmw->wDevID = modp->wDeviceID;
165
167 wmw->wfxRef.nChannels = 1; /* MONO */
168 wmw->wfxRef.nSamplesPerSec = 11025;
169 wmw->wfxRef.nAvgBytesPerSec = 11025;
170 wmw->wfxRef.nBlockAlign = 1;
171 wmw->wfxRef.wBitsPerSample = 8;
172 wmw->wfxRef.cbSize = 0; /* don't care */
173
174 return modp->wDeviceID;
175}
176
177/**************************************************************************
178 * MCIWAVE_drvClose [internal]
179 */
181{
183
184 if (wmw) {
185 free(wmw);
186 mciSetDriverData(dwDevID, 0);
187 return 1;
188 }
189 return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
190}
191
192/**************************************************************************
193 * WAVE_mciGetOpenDev [internal]
194 */
196{
198
199 if (wmw == NULL || wmw->nUseCount == 0) {
200 WARN("Invalid wDevID=%u\n", wDevID);
201 return 0;
202 }
203 return wmw;
204}
205
206/**************************************************************************
207 * WAVE_mciNotify [internal]
208 *
209 * Notifications in MCI work like a 1-element queue.
210 * Each new notification request supersedes the previous one.
211 * This affects Play and Record; other commands are immediate.
212 */
213static void WAVE_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIWAVE* wmw, UINT wStatus)
214{
215 /* We simply save one parameter by not passing the wDevID local
216 * to the command. They are the same (via mciGetDriverData).
217 */
221 mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
222}
223
224/**************************************************************************
225 * WAVE_ConvertByteToTimeFormat [internal]
226 */
228{
229 DWORD ret = 0;
230
231 switch (wmw->dwMciTimeFormat) {
234 break;
235 case MCI_FORMAT_BYTES:
236 ret = val;
237 break;
240 break;
241 default:
242 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
243 }
244 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
245 return ret;
246}
247
248/**************************************************************************
249 * WAVE_ConvertTimeFormatToByte [internal]
250 */
252{
253 DWORD ret = 0;
254
255 switch (wmw->dwMciTimeFormat) {
258 if (ret > wmw->ckWaveData.cksize &&
260 ret = wmw->ckWaveData.cksize;
261 break;
262 case MCI_FORMAT_BYTES:
263 ret = val;
264 break;
267 break;
268 default:
269 WARN("Bad time format %lu!\n", wmw->dwMciTimeFormat);
270 }
271 TRACE("val=%lu=0x%08lx [tf=%lu] => ret=%lu\n", val, val, wmw->dwMciTimeFormat, ret);
272 return ret;
273}
274
275/**************************************************************************
276 * WAVE_mciReadFmt [internal]
277 */
278static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, const MMCKINFO* pckMainRIFF)
279{
280 MMCKINFO mmckInfo;
281 LONG r;
282 LPWAVEFORMATEX pwfx;
283
284 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
285 if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
286 return MCIERR_INVALID_FILE;
287 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
288 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
289
290 pwfx = malloc(mmckInfo.cksize);
291 if (!pwfx) return MCIERR_OUT_OF_MEMORY;
292
293 r = mmioRead(wmw->hFile, (HPSTR)pwfx, mmckInfo.cksize);
294 if (r < 0 || r < sizeof(PCMWAVEFORMAT)) {
295 free(pwfx);
296 return MCIERR_INVALID_FILE;
297 }
298 TRACE("wFormatTag=%04X !\n", pwfx->wFormatTag);
299 TRACE("nChannels=%d\n", pwfx->nChannels);
300 TRACE("nSamplesPerSec=%ld\n", pwfx->nSamplesPerSec);
301 TRACE("nAvgBytesPerSec=%ld\n", pwfx->nAvgBytesPerSec);
302 TRACE("nBlockAlign=%d\n", pwfx->nBlockAlign);
303 TRACE("wBitsPerSample=%u !\n", pwfx->wBitsPerSample);
304 if (r >= sizeof(WAVEFORMATEX))
305 TRACE("cbSize=%u !\n", pwfx->cbSize);
306 if ((pwfx->wFormatTag != WAVE_FORMAT_PCM)
307 && (r < sizeof(WAVEFORMATEX) || (r < sizeof(WAVEFORMATEX) + pwfx->cbSize))) {
308 free(pwfx);
309 return MCIERR_INVALID_FILE;
310 }
311 wmw->lpWaveFormat = pwfx;
312
313 mmioAscend(wmw->hFile, &mmckInfo, 0);
314 wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
315 if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
316 TRACE("can't find data chunk\n");
317 return MCIERR_INVALID_FILE;
318 }
319 TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n",
321 return 0;
322}
323
324/**************************************************************************
325 * WAVE_mciDefaultFmt [internal]
326 *
327 * wmw->lpWaveFormat points to the default wave format at wmw->wfxRef
328 * until either Open File or Record. It becomes immutable afterwards,
329 * i.e. Set wave format or channels etc. is subsequently refused.
330 */
332{
333 wmw->lpWaveFormat = &wmw->wfxRef;
335 wmw->lpWaveFormat->nChannels = 1;
336 wmw->lpWaveFormat->nSamplesPerSec = 11025;
337 wmw->lpWaveFormat->nAvgBytesPerSec = 11025;
338 wmw->lpWaveFormat->nBlockAlign = 1;
340 wmw->lpWaveFormat->cbSize = 0;
341}
342
343/**************************************************************************
344 * WAVE_mciCreateRIFFSkeleton [internal]
345 */
347{
348 MMCKINFO ckWaveFormat;
349 LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF);
350 LPMMCKINFO lpckWaveData = &(wmw->ckWaveData);
351
352 lpckRIFF->ckid = FOURCC_RIFF;
353 lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
354 lpckRIFF->cksize = 0;
355
357 goto err;
358
359 ckWaveFormat.fccType = 0;
360 ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' ');
361 ckWaveFormat.cksize = sizeof(PCMWAVEFORMAT);
362
363 /* Set wave format accepts PCM only, however open an
364 * existing ADPCM file, record into it and the MCI will
365 * happily save back in that format. */
367 if (wmw->lpWaveFormat->nBlockAlign !=
371 WARN("Incorrect nBlockAlign (%d), setting it to %d\n",
374 }
375 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
377 DWORD speed = wmw->lpWaveFormat->nSamplesPerSec *
379 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
380 wmw->lpWaveFormat->nAvgBytesPerSec, speed);
381 wmw->lpWaveFormat->nAvgBytesPerSec = speed;
382 }
383 }
384 if (wmw->lpWaveFormat == &wmw->wfxRef) {
386 if (!pwfx) return MCIERR_OUT_OF_MEMORY;
387 /* Set wave format accepts PCM only so the size is known. */
389 *pwfx = wmw->wfxRef;
390 wmw->lpWaveFormat = pwfx;
391 }
392
393 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
394 goto err;
395
396 if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, (WAVE_FORMAT_PCM==wmw->lpWaveFormat->wFormatTag)
397 ? sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX)+wmw->lpWaveFormat->cbSize))
398 goto err;
399
400 if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
401 goto err;
402
403 lpckWaveData->cksize = 0;
404 lpckWaveData->fccType = 0;
405 lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a');
406
407 /* create data chunk */
408 if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
409 goto err;
410
411 return 0;
412
413err:
414 /* mciClose takes care of wmw->lpWaveFormat. */
415 return MCIERR_INVALID_FILE;
416}
417
418static DWORD create_tmp_file(HMMIO* hFile, LPWSTR* pszTmpFileName)
419{
420 WCHAR szTmpPath[MAX_PATH];
421 WCHAR szPrefix[4];
422 DWORD dwRet = MMSYSERR_NOERROR;
423
424 szPrefix[0] = 'M';
425 szPrefix[1] = 'C';
426 szPrefix[2] = 'I';
427 szPrefix[3] = '\0';
428
429 if (!GetTempPathW(ARRAY_SIZE(szTmpPath), szTmpPath)) {
430 WARN("can't retrieve temp path!\n");
431 *pszTmpFileName = NULL;
433 }
434
435 *pszTmpFileName = calloc(1, MAX_PATH * sizeof(WCHAR));
436 if (!GetTempFileNameW(szTmpPath, szPrefix, 0, *pszTmpFileName)) {
437 WARN("can't retrieve temp file name!\n");
438 free(*pszTmpFileName);
440 }
441
442 TRACE("%s!\n", debugstr_w(*pszTmpFileName));
443
444 if (*pszTmpFileName && (*pszTmpFileName)[0]) {
445
446 *hFile = mmioOpenW(*pszTmpFileName, NULL,
448
449 if (*hFile == 0) {
450 WARN("can't create file=%s!\n", debugstr_w(*pszTmpFileName));
451 /* temporary file could not be created. clean filename. */
452 free(*pszTmpFileName);
453 dwRet = MCIERR_FILE_NOT_FOUND;
454 }
455 }
456 return dwRet;
457}
458
460{
462 LPWSTR fn;
463
464 fn = wcsdup(filename);
465 if (!fn) return MCIERR_OUT_OF_MEMORY;
466 free(wmw->lpFileName);
467 wmw->lpFileName = fn;
468
469 if (filename[0]) {
470 /* FIXME : what should be done if wmw->hFile is already != 0, or the driver is playin' */
471 TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(filename));
472
475
476 if (wmw->hFile == 0) {
477 WARN("can't find file=%s!\n", debugstr_w(filename));
478 dwRet = MCIERR_FILE_NOT_FOUND;
479 }
480 else
481 {
482 LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF;
483
484 /* make sure we're at the beginning of the file */
485 mmioSeek(wmw->hFile, 0, SEEK_SET);
486
487 /* first reading of this file. read the waveformat chunk */
488 if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
489 dwRet = MCIERR_INVALID_FILE;
490 } else {
491 TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX\n",
492 (LPSTR)&(lpckMainRIFF->ckid),
493 (LPSTR) &(lpckMainRIFF->fccType),
494 (lpckMainRIFF->cksize));
495
496 if ((lpckMainRIFF->ckid != FOURCC_RIFF) ||
497 lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
498 dwRet = MCIERR_INVALID_FILE;
499 } else {
500 dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
501 }
502 }
503 }
504 }
505 return dwRet;
506}
507
508/**************************************************************************
509 * WAVE_mciOpen [internal]
510 */
512{
513 DWORD dwRet = 0;
515
516 TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
517 if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
518 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
519
522
523 if (wmw->nUseCount > 0) {
524 /* The driver is already opened on this channel
525 * Wave driver cannot be shared
526 */
527 return MCIERR_DEVICE_OPEN;
528 }
529
530 wmw->nUseCount++;
531
532 wmw->wInput = wmw->wOutput = WAVE_MAPPER;
533 wmw->fInput = FALSE;
534 wmw->hWave = 0;
536 wmw->hFile = 0;
537 wmw->lpFileName = NULL; /* will be set by WAVE_mciOpenFile */
538 wmw->hCallback = NULL;
540
541 TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
542 /* Logs show the native winmm calls us with 0 still in lpOpenParms.wDeviceID */
543 wmw->wNotifyDeviceID = wDevID;
544
547 /* could it be that (DWORD)lpOpenParms->lpstrElementName
548 * contains the hFile value ?
549 */
551 } else {
552 dwRet = WAVE_mciOpenFile(wmw, lpOpenParms->lpstrElementName);
553 }
554 }
555 TRACE("hFile=%p\n", wmw->hFile);
556
557 if (dwRet == 0) {
558 wmw->dwPosition = 0;
559
560 wmw->dwStatus = MCI_MODE_STOP;
561
562 if (dwFlags & MCI_NOTIFY)
564 } else {
565 wmw->nUseCount--;
566 if (wmw->hFile != 0)
567 mmioClose(wmw->hFile, 0);
568 wmw->hFile = 0;
569 free(wmw->lpFileName);
570 wmw->lpFileName = NULL;
571 }
572 return dwRet;
573}
574
575/**************************************************************************
576 * WAVE_mciCue [internal]
577 */
579{
581
582 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
583
584 /* Tests on systems without sound drivers show that Cue, like
585 * Record and Play, opens winmm, returning MCIERR_WAVE_xyPUTSUNSUITABLE.
586 * The first Cue Notify does not immediately return the
587 * notification, as if a player or recorder thread is started.
588 * PAUSE mode is reported when successful, but this mode is
589 * different from the normal Pause, because a) Pause then returns
590 * NONAPPLICABLE_FUNCTION instead of 0 and b) Set Channels etc. is
591 * still accepted, returning the original notification as ABORTED.
592 * I.e. Cue allows subsequent format changes, unlike Record or
593 * Open file, closes winmm if the format changes and stops this
594 * thread.
595 * Wine creates one player or recorder thread per async. Play or
596 * Record command. Notification behaviour suggests that MS-W*
597 * reuses a single thread to improve response times. Having Cue
598 * start this thread early helps to improve Play/Record's initial
599 * response time. In effect, Cue is a performance hint, which
600 * justifies our almost no-op implementation.
601 */
602
603 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
605
606 if ((dwFlags & MCI_NOTIFY) && lpParms)
608
609 return MMSYSERR_NOERROR;
610}
611
612/**************************************************************************
613 * WAVE_mciStop [internal]
614 */
616{
617 DWORD dwRet = 0;
619
620 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
621
622 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
623
624 if (wmw->dwStatus != MCI_MODE_STOP) {
627 }
628
629 /* wait for playback thread (if any) to exit before processing further */
630 switch (wmw->dwStatus) {
631 case MCI_MODE_PAUSE:
632 case MCI_MODE_PLAY:
633 case MCI_MODE_RECORD:
635 dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
636 while (wmw->dwStatus != MCI_MODE_STOP)
637 Sleep(10);
638 break;
639 }
640
641 /* sanity resets */
642 wmw->dwStatus = MCI_MODE_STOP;
643
644 if ((dwFlags & MCI_NOTIFY) && lpParms && MMSYSERR_NOERROR==dwRet)
646
647 return dwRet;
648}
649
650/**************************************************************************
651 * WAVE_mciClose [internal]
652 */
654{
655 DWORD dwRet = 0;
657
658 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
659
660 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
661
662 if (wmw->dwStatus != MCI_MODE_STOP) {
663 /* mciStop handles MCI_NOTIFY_ABORTED */
664 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
665 }
666
667 wmw->nUseCount--;
668
669 if (wmw->nUseCount == 0) {
670 if (wmw->hFile != 0) {
671 mmioClose(wmw->hFile, 0);
672 wmw->hFile = 0;
673 }
674 }
675
676 if (wmw->lpWaveFormat != &wmw->wfxRef)
677 free(wmw->lpWaveFormat);
678 wmw->lpWaveFormat = &wmw->wfxRef;
679 free(wmw->lpFileName);
680 wmw->lpFileName = NULL;
681
682 if ((dwFlags & MCI_NOTIFY) && lpParms) {
683 WAVE_mciNotify(lpParms->dwCallback, wmw,
685 }
686
687 return 0;
688}
689
690/**************************************************************************
691 * WAVE_mciPlayCallback [internal]
692 */
693static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
694 DWORD_PTR dwInstance,
696{
697 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
698
699 switch (uMsg) {
700 case WOM_OPEN:
701 case WOM_CLOSE:
702 break;
703 case WOM_DONE:
705 TRACE("Returning waveHdr=%Ix\n", dwParam1);
706 SetEvent(wmw->hEvent);
707 break;
708 default:
709 ERR("Unknown uMsg=%d\n", uMsg);
710 }
711}
712
713/******************************************************************
714 * WAVE_mciPlayWaitDone [internal]
715 */
717{
718 for (;;) {
719 ResetEvent(wmw->hEvent);
720 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
721 break;
722 }
724
726 }
727}
728
729/**************************************************************************
730 * WAVE_mciPlay [internal]
731 */
733{
734 LPMCI_PLAY_PARMS lpParms = (void*)pmt;
735 DWORD end;
737 DWORD dwRet;
738 LPWAVEHDR waveHdr = NULL;
740 HANDLE oldcb;
741 int whidx;
742
743 TRACE("(%u, %08IX, %p);\n", wDevID, dwFlags, lpParms);
744
745 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
746 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
747
748 if (wmw->hFile == 0) {
749 WARN("Can't play: no file=%s!\n", debugstr_w(wmw->lpFileName));
751 }
752
753 if (wmw->dwStatus == MCI_MODE_PAUSE && !wmw->fInput && !(dwFlags & (MCI_FROM | MCI_TO))) {
754 /* FIXME: notification is different with Resume than Play */
756 }
757
762 if ( !(wmw->dwStatus == MCI_MODE_STOP) &&
763 !((wmw->dwStatus == MCI_MODE_PLAY) && (dwFlags & MCI_WAIT) && !wmw->hWave)) {
764 /* FIXME: Check FROM/TO parameters first. */
765 /* FIXME: Play; Play [notify|wait] must hook into the running player. */
766 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, NULL);
767 if (dwRet) return dwRet;
768 }
769
771 if (wmw->lpWaveFormat->nBlockAlign !=
773 WARN("Incorrect nBlockAlign (%d), setting it to %d\n",
775 wmw->lpWaveFormat->nChannels *
778 wmw->lpWaveFormat->nChannels *
780 }
781 if (wmw->lpWaveFormat->nAvgBytesPerSec !=
783 WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
790 }
791 }
792
793 end = wmw->ckWaveData.cksize;
794 if (dwFlags & MCI_TO) {
795 DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
796 if (position > end) return MCIERR_OUTOFRANGE;
797 end = position;
798 }
799 if (dwFlags & MCI_FROM) {
800 DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
801 if (position > end) return MCIERR_OUTOFRANGE;
802 /* Seek rounds down, so do we. */
803 position /= wmw->lpWaveFormat->nBlockAlign;
804 position *= wmw->lpWaveFormat->nBlockAlign;
805 wmw->dwPosition = position;
806 }
807 if (end < wmw->dwPosition) return MCIERR_OUTOFRANGE;
808 left = end - wmw->dwPosition;
809 if (0==left) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
810
811 wmw->fInput = FALSE; /* FIXME: waveInOpen may have been called. */
812 wmw->dwStatus = MCI_MODE_PLAY;
813
814 if (!(dwFlags & MCI_WAIT)) {
816 (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS));
817 }
818
819 TRACE("Playing from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
820
822 (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
823 if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
824 oldcb = NULL;
825
826#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
827((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
828
829 /* go back to beginning of chunk plus the requested position */
830 /* FIXME: I'm not sure this is correct, notably because some data linked to
831 * the decompression state machine will not be correctly initialized.
832 * try it this way (other way would be to decompress from 0 up to dwPosition
833 * and to start sending to hWave when dwPosition is reached)
834 */
835 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
836
837 dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, wmw->wOutput, wmw->lpWaveFormat,
839
840 if (dwRet != 0) {
841 TRACE("Can't open low level audio device %ld\n", dwRet);
842 dwRet = MCIERR_DEVICE_OPEN;
843 wmw->hWave = 0;
844 goto cleanUp;
845 }
846
847 /* make it so that 3 buffers per second are needed */
849
850 waveHdr = malloc(2 * sizeof(WAVEHDR) + 2 * bufsize);
851 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
852 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
853 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
854 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
855 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
856 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
857 if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
858 waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
859 dwRet = MCIERR_INTERNAL;
860 goto cleanUp;
861 }
862
863 whidx = 0;
865 if (!wmw->hEvent) {
866 dwRet = MCIERR_OUT_OF_MEMORY;
867 goto cleanUp;
868 }
869 wmw->dwEventCount = 1L; /* for first buffer */
870
871 TRACE("Playing (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, left);
872 if (hEvent) SetEvent(hEvent);
873
874 /* FIXME: this doesn't work if wmw->dwPosition != 0 */
875 while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
876 count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
877 TRACE("mmioRead bufsize=%ld count=%ld\n", bufsize, count);
878 if (count < 1)
879 break;
880 /* count is always <= bufsize, so this is correct regarding the
881 * waveOutPrepareHeader function
882 */
883 waveHdr[whidx].dwBufferLength = count;
884 waveHdr[whidx].dwFlags &= ~WHDR_DONE;
885 TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu\n",
886 &waveHdr[whidx], waveHdr[whidx].dwBufferLength);
887 dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
888 if (dwRet) {
889 ERR("Aborting play loop, WODM_WRITE error %ld\n", dwRet);
890 dwRet = MCIERR_HARDWARE;
891 break;
892 }
893 left -= count;
894 wmw->dwPosition += count;
895 TRACE("after WODM_WRITE dwPosition=%lu\n", wmw->dwPosition);
896 /* InterlockedDecrement if and only if waveOutWrite is successful */
898 whidx ^= 1;
899 }
900
901 WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
902
903 /* just to get rid of some race conditions between play, stop and pause */
904 waveOutReset(wmw->hWave);
905
906 waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
907 waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
908
909cleanUp:
910 if (dwFlags & MCI_NOTIFY)
912
913 free(waveHdr);
914
915 if (wmw->hWave) {
916 waveOutClose(wmw->hWave);
917 wmw->hWave = 0;
918 }
919 CloseHandle(wmw->hEvent);
920 wmw->hEvent = NULL;
921
922 wmw->dwStatus = MCI_MODE_STOP;
923
924 /* Let the potentially asynchronous commands support FAILURE notification. */
925 if (oldcb) mciDriverNotify(oldcb, wDevID,
927
928 return dwRet;
929}
930
931/**************************************************************************
932 * WAVE_mciRecordCallback [internal]
933 */
934static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
935 DWORD_PTR dwInstance,
937{
938 WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
939 LPWAVEHDR lpWaveHdr;
940 LONG count = 0;
941
942 switch (uMsg) {
943 case WIM_OPEN:
944 case WIM_CLOSE:
945 break;
946 case WIM_DATA:
947 lpWaveHdr = (LPWAVEHDR) dwParam1;
948
950
951 count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
952
953 lpWaveHdr->dwFlags &= ~WHDR_DONE;
954 if (count > 0)
955 wmw->dwPosition += count;
956 /* else error reporting ?? */
957 if (wmw->dwStatus == MCI_MODE_RECORD)
958 {
959 /* Only queue up another buffer if we are recording. We could receive this
960 message also when waveInReset() is called, since it notifies on all wave
961 buffers that are outstanding. Queueing up more sometimes causes waveInClose
962 to fail. */
963 waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
964 TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
965 }
966
967 SetEvent(wmw->hEvent);
968 break;
969 default:
970 ERR("Unknown uMsg=%d\n", uMsg);
971 }
972}
973
974/******************************************************************
975 * WAVE_mciRecordWaitDone [internal]
976 */
978{
979 for (;;) {
980 ResetEvent(wmw->hEvent);
981 if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
982 break;
983 }
985
987 }
988}
989
990/**************************************************************************
991 * WAVE_mciRecord [internal]
992 */
994{
995 LPMCI_RECORD_PARMS lpParms = (void*)pmt;
996 DWORD end;
997 DWORD dwRet = MMSYSERR_NOERROR;
999 LPWAVEHDR waveHdr = NULL;
1001 HANDLE oldcb;
1002
1003 TRACE("(%u, %08IX, %p);\n", wDevID, dwFlags, lpParms);
1004
1005 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1006 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1007
1008 if (wmw->dwStatus == MCI_MODE_PAUSE && wmw->fInput) {
1009 /* FIXME: parameters (start/end) in lpParams may not be used */
1011 }
1012
1017 if ( !(wmw->dwStatus == MCI_MODE_STOP) &&
1018 !((wmw->dwStatus == MCI_MODE_RECORD) && (dwFlags & MCI_WAIT) && !wmw->hWave)) {
1019 return MCIERR_INTERNAL;
1020 }
1021
1022 wmw->fInput = TRUE; /* FIXME: waveOutOpen may have been called. */
1024
1025 if (!(dwFlags & MCI_WAIT)) {
1027 (DWORD_PTR)lpParms, sizeof(MCI_RECORD_PARMS));
1028 }
1029
1030 /* FIXME: we only re-create the RIFF structure from an existing file (if any)
1031 * we don't modify the wave part of an existing file (ie. we always erase an
1032 * existing content, we don't overwrite)
1033 */
1034 free(wmw->lpFileName);
1035 dwRet = create_tmp_file(&wmw->hFile, (WCHAR**)&wmw->lpFileName);
1036 if (dwRet != 0) return dwRet;
1037
1038 /* new RIFF file, lpWaveFormat now valid */
1039 dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
1040 if (dwRet != 0) return dwRet;
1041
1042 if (dwFlags & MCI_TO) {
1043 end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1044 } else end = 0xFFFFFFFF;
1045 if (dwFlags & MCI_FROM) {
1046 DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
1047 if (wmw->ckWaveData.cksize < position) return MCIERR_OUTOFRANGE;
1048 /* Seek rounds down, so do we. */
1049 position /= wmw->lpWaveFormat->nBlockAlign;
1050 position *= wmw->lpWaveFormat->nBlockAlign;
1051 wmw->dwPosition = position;
1052 }
1053 if (end==wmw->dwPosition) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
1054
1055 TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
1056
1058 (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
1059 if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
1060 oldcb = NULL;
1061
1062#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1063((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1064
1066
1067 /* Go back to the beginning of the chunk plus the requested position */
1068 /* FIXME: I'm not sure this is correct, notably because some data linked to
1069 * the decompression state machine will not be correctly initialized.
1070 * Try it this way (other way would be to decompress from 0 up to dwPosition
1071 * and to start sending to hWave when dwPosition is reached).
1072 */
1073 mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1074
1075 dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, wmw->wInput, wmw->lpWaveFormat,
1077
1078 if (dwRet != MMSYSERR_NOERROR) {
1079 TRACE("Can't open low level audio device %ld\n", dwRet);
1080 dwRet = MCIERR_DEVICE_OPEN;
1081 wmw->hWave = 0;
1082 goto cleanUp;
1083 }
1084
1085 /* make it so that 3 buffers per second are needed */
1087
1088 waveHdr = malloc(2 * sizeof(WAVEHDR) + 2 * bufsize);
1089 waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1090 waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1091 waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
1092 waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
1093 waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
1094 waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1095
1096 if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1097 waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1098 dwRet = MCIERR_INTERNAL;
1099 goto cleanUp;
1100 }
1101
1102 if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1103 waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1104 dwRet = MCIERR_INTERNAL;
1105 goto cleanUp;
1106 }
1107
1109 wmw->dwEventCount = 1L; /* for first buffer */
1110
1111 TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1112
1113 waveInStart(wmw->hWave);
1114
1115 if (hEvent) SetEvent(hEvent);
1116
1117 while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1119 }
1120 /* Grab callback before another thread kicks in after we change dwStatus. */
1121 if (dwFlags & MCI_NOTIFY) {
1123 dwFlags &= ~MCI_NOTIFY;
1124 }
1125 /* needed so that the callback above won't add again the buffers returned by the reset */
1126 wmw->dwStatus = MCI_MODE_STOP;
1127
1128 waveInReset(wmw->hWave);
1129
1130 waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1131 waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1132
1133 dwRet = 0;
1134
1135cleanUp:
1136 if (dwFlags & MCI_NOTIFY)
1138
1139 free(waveHdr);
1140
1141 if (wmw->hWave) {
1142 waveInClose(wmw->hWave);
1143 wmw->hWave = 0;
1144 }
1145 CloseHandle(wmw->hEvent);
1146
1147 wmw->dwStatus = MCI_MODE_STOP;
1148
1149 if (oldcb) mciDriverNotify(oldcb, wDevID,
1151
1152 return dwRet;
1153
1154}
1155
1156/**************************************************************************
1157 * WAVE_mciPause [internal]
1158 */
1160{
1161 DWORD dwRet;
1163
1164 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1165
1166 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1167
1168 switch (wmw->dwStatus) {
1169 case MCI_MODE_PLAY:
1170 dwRet = waveOutPause(wmw->hWave);
1171 if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1172 else { /* When playthread was not started yet, winmm not opened, error 5 MMSYSERR_INVALHANDLE */
1173 ERR("waveOutPause error %ld\n",dwRet);
1174 dwRet = MCIERR_INTERNAL;
1175 }
1176 break;
1177 case MCI_MODE_RECORD:
1178 dwRet = waveInStop(wmw->hWave);
1179 if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1180 else {
1181 ERR("waveInStop error %ld\n",dwRet);
1182 dwRet = MCIERR_INTERNAL;
1183 }
1184 break;
1185 case MCI_MODE_PAUSE:
1186 dwRet = MMSYSERR_NOERROR;
1187 break;
1188 default:
1190 }
1191 if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1193 return dwRet;
1194}
1195
1196/**************************************************************************
1197 * WAVE_mciResume [internal]
1198 */
1200{
1202 DWORD dwRet;
1203
1204 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1205
1206 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1207
1208 switch (wmw->dwStatus) {
1209 case MCI_MODE_PAUSE:
1210 /* Only update dwStatus if wave* succeeds and will exchange buffers buffers. */
1211 if (wmw->fInput) {
1212 dwRet = waveInStart(wmw->hWave);
1213 if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_RECORD;
1214 else {
1215 ERR("waveInStart error %ld\n",dwRet);
1216 dwRet = MCIERR_INTERNAL;
1217 }
1218 } else {
1219 dwRet = waveOutRestart(wmw->hWave);
1220 if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PLAY;
1221 else {
1222 ERR("waveOutRestart error %ld\n",dwRet);
1223 dwRet = MCIERR_INTERNAL;
1224 }
1225 }
1226 break;
1227 case MCI_MODE_PLAY:
1228 case MCI_MODE_RECORD:
1229 dwRet = MMSYSERR_NOERROR;
1230 break;
1231 default:
1233 }
1234 if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1236 return dwRet;
1237}
1238
1239/**************************************************************************
1240 * WAVE_mciSeek [internal]
1241 */
1243{
1245 DWORD position, dwRet;
1246
1247 TRACE("(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1248
1249 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1250 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1251
1253 if (!position) return MCIERR_MISSING_PARAMETER;
1254 if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
1255
1256 /* Stop sends MCI_NOTIFY_ABORTED when needed */
1257 dwRet = WAVE_mciStop(wDevID, MCI_WAIT, 0);
1258 if (dwRet != MMSYSERR_NOERROR) return dwRet;
1259
1260 if (dwFlags & MCI_TO) {
1261 position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1262 if (position > wmw->ckWaveData.cksize)
1263 return MCIERR_OUTOFRANGE;
1264 } else if (dwFlags & MCI_SEEK_TO_START) {
1265 position = 0;
1266 } else {
1267 position = wmw->ckWaveData.cksize;
1268 }
1269 /* Seek rounds down, unless at end */
1270 if (position != wmw->ckWaveData.cksize) {
1271 position /= wmw->lpWaveFormat->nBlockAlign;
1272 position *= wmw->lpWaveFormat->nBlockAlign;
1273 }
1274 wmw->dwPosition = position;
1275 TRACE("Seeking to position=%lu bytes\n", position);
1276
1277 if (dwFlags & MCI_NOTIFY)
1279
1280 return MMSYSERR_NOERROR;
1281}
1282
1283/**************************************************************************
1284 * WAVE_mciSet [internal]
1285 */
1287{
1289
1290 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1291
1292 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1293 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1294
1296 switch (lpParms->dwTimeFormat) {
1298 TRACE("MCI_FORMAT_MILLISECONDS !\n");
1300 break;
1301 case MCI_FORMAT_BYTES:
1302 TRACE("MCI_FORMAT_BYTES !\n");
1304 break;
1305 case MCI_FORMAT_SAMPLES:
1306 TRACE("MCI_FORMAT_SAMPLES !\n");
1308 break;
1309 default:
1310 WARN("Bad time format %lu!\n", lpParms->dwTimeFormat);
1312 }
1313 }
1314 if (dwFlags & MCI_SET_VIDEO) {
1315 TRACE("No support for video !\n");
1317 }
1318 if (dwFlags & MCI_SET_DOOR_OPEN) {
1319 TRACE("No support for door open !\n");
1321 }
1323 TRACE("No support for door close !\n");
1325 }
1326 if (dwFlags & MCI_SET_AUDIO) {
1327 if (dwFlags & MCI_SET_ON) {
1328 TRACE("MCI_SET_ON audio !\n");
1329 } else if (dwFlags & MCI_SET_OFF) {
1330 TRACE("MCI_SET_OFF audio !\n");
1331 } else {
1332 WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1333 return MCIERR_BAD_INTEGER;
1334 }
1335
1336 switch (lpParms->dwAudio)
1337 {
1338 case MCI_SET_AUDIO_ALL: TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1339 case MCI_SET_AUDIO_LEFT: TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1340 case MCI_SET_AUDIO_RIGHT: TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1341 default: WARN("Unknown audio channel %lu\n", lpParms->dwAudio); break;
1342 }
1343 }
1344 if (dwFlags & MCI_WAVE_INPUT) {
1345 TRACE("MCI_WAVE_INPUT = %d\n", lpParms->wInput);
1346 if (lpParms->wInput >= waveInGetNumDevs())
1347 return MCIERR_OUTOFRANGE;
1348 if (wmw->wInput != (WORD)lpParms->wInput)
1350 wmw->wInput = lpParms->wInput;
1351 }
1352 if (dwFlags & MCI_WAVE_OUTPUT) {
1353 TRACE("MCI_WAVE_OUTPUT = %d\n", lpParms->wOutput);
1354 if (lpParms->wOutput >= waveOutGetNumDevs())
1355 return MCIERR_OUTOFRANGE;
1356 if (wmw->wOutput != (WORD)lpParms->wOutput)
1358 wmw->wOutput = lpParms->wOutput;
1359 }
1361 TRACE("MCI_WAVE_SET_ANYINPUT\n");
1362 if (wmw->wInput != (WORD)lpParms->wInput)
1364 wmw->wInput = WAVE_MAPPER;
1365 }
1367 TRACE("MCI_WAVE_SET_ANYOUTPUT\n");
1368 if (wmw->wOutput != (WORD)lpParms->wOutput)
1370 wmw->wOutput = WAVE_MAPPER;
1371 }
1372 /* Set wave format parameters is refused after Open or Record.*/
1374 TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", lpParms->wFormatTag);
1375 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1376 if (lpParms->wFormatTag != WAVE_FORMAT_PCM)
1377 return MCIERR_OUTOFRANGE;
1378 }
1380 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1381 wmw->wfxRef.nAvgBytesPerSec = lpParms->nAvgBytesPerSec;
1382 TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %ld\n", wmw->wfxRef.nAvgBytesPerSec);
1383 }
1385 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1386 wmw->wfxRef.wBitsPerSample = lpParms->wBitsPerSample;
1387 TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1388 }
1390 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1391 wmw->wfxRef.nBlockAlign = lpParms->nBlockAlign;
1392 TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1393 }
1395 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1396 wmw->wfxRef.nChannels = lpParms->nChannels;
1397 TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1398 }
1400 if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1401 wmw->wfxRef.nSamplesPerSec = lpParms->nSamplesPerSec;
1402 TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %ld\n", wmw->wfxRef.nSamplesPerSec);
1403 }
1404 if (dwFlags & MCI_NOTIFY)
1406 return 0;
1407}
1408
1409/**************************************************************************
1410 * WAVE_mciSave [internal]
1411 */
1413{
1416
1417 TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1418 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1419 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1420
1421 if (dwFlags & MCI_WAIT)
1422 {
1423 FIXME("MCI_WAIT not implemented\n");
1424 }
1426
1427 ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1428 ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1429
1430 ret = mmioClose(wmw->hFile, 0);
1431 wmw->hFile = 0;
1432
1433 /*
1434 If the destination file already exists, it has to be overwritten. (Behaviour
1435 verified in Windows (2000)). If it doesn't overwrite, it is breaking one of
1436 my applications. We are making use of mmioRename, which WILL NOT overwrite
1437 the destination file (which is what Windows does, also verified in Win2K)
1438 So, lets delete the destination file before calling mmioRename. If the
1439 destination file DOESN'T exist, the delete will fail silently. Let's also be
1440 careful not to lose our previous error code.
1441 */
1442 tmpRet = GetLastError();
1443 DeleteFileW (lpParms->lpfilename);
1444 SetLastError(tmpRet);
1445
1446 /* FIXME: Open file.wav; Save; must not rename the original file.
1447 * Nor must Save a.wav; Save b.wav rename a. */
1448 if (0 == mmioRenameW(wmw->lpFileName, lpParms->lpfilename, 0, 0 )) {
1450 }
1451
1454
1455 if (ret == MMSYSERR_NOERROR)
1456 ret = WAVE_mciOpenFile(wmw, lpParms->lpfilename);
1457
1458 return ret;
1459}
1460
1461/**************************************************************************
1462 * WAVE_mciStatus [internal]
1463 */
1465{
1467 DWORD ret = 0;
1468
1469 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1470 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1471 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1473
1474 if (dwFlags & MCI_STATUS_ITEM) {
1475 switch (lpParms->dwItem) {
1477 lpParms->dwReturn = 1;
1478 TRACE("MCI_STATUS_CURRENT_TRACK => %Iu\n", lpParms->dwReturn);
1479 break;
1480 case MCI_STATUS_LENGTH:
1481 if (!wmw->hFile) {
1482 lpParms->dwReturn = 0;
1484 }
1485 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1487 TRACE("MCI_STATUS_LENGTH => %Iu\n", lpParms->dwReturn);
1488 break;
1489 case MCI_STATUS_MODE:
1490 TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1491 lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1493 break;
1495 TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1498 break;
1500 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1501 lpParms->dwReturn = 1;
1502 TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %Iu\n", lpParms->dwReturn);
1503 break;
1505 if (!wmw->hFile) {
1506 lpParms->dwReturn = 0;
1508 }
1509 /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1511 (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
1512 TRACE("MCI_STATUS_POSITION %s => %Iu\n",
1513 (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1514 break;
1515 case MCI_STATUS_READY:
1516 lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1518 TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1520 break;
1523 TRACE("MCI_STATUS_TIME_FORMAT => %Iu\n", lpParms->dwReturn);
1525 break;
1526 case MCI_WAVE_INPUT:
1527 if (wmw->wInput != (WORD)WAVE_MAPPER)
1528 lpParms->dwReturn = wmw->wInput;
1529 else {
1532 }
1533 TRACE("MCI_WAVE_INPUT => %d\n", (signed)wmw->wInput);
1534 break;
1535 case MCI_WAVE_OUTPUT:
1536 if (wmw->wOutput != (WORD)WAVE_MAPPER)
1537 lpParms->dwReturn = wmw->wOutput;
1538 else {
1541 }
1542 TRACE("MCI_WAVE_OUTPUT => %d\n", (signed)wmw->wOutput);
1543 break;
1544 /* It is always ok to query wave format parameters,
1545 * except on auto-open yield MCIERR_UNSUPPORTED_FUNCTION. */
1548 lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1549 else {
1552 }
1553 TRACE("MCI_WAVE_FORMATTAG => %Iu\n", lpParms->dwReturn);
1554 break;
1556 lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1557 TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %Iu\n", lpParms->dwReturn);
1558 break;
1560 lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1561 TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %Iu\n", lpParms->dwReturn);
1562 break;
1564 lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1565 TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %Iu\n", lpParms->dwReturn);
1566 break;
1568 lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1569 TRACE("MCI_WAVE_STATUS_CHANNELS => %Iu\n", lpParms->dwReturn);
1570 break;
1572 lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1573 TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %Iu\n", lpParms->dwReturn);
1574 break;
1576 TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1577 lpParms->dwReturn = 0xAAAA5555;
1578 break;
1579 default:
1580 WARN("unknown command %08lX !\n", lpParms->dwItem);
1582 }
1583 }
1584 if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1586 return ret;
1587}
1588
1589/**************************************************************************
1590 * WAVE_mciGetDevCaps [internal]
1591 */
1593 LPMCI_GETDEVCAPS_PARMS lpParms)
1594{
1596 DWORD ret = 0;
1597
1598 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1599
1600 if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1601 if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1602
1604 switch(lpParms->dwItem) {
1608 break;
1612 break;
1616 break;
1620 break;
1624 break;
1628 break;
1632 break;
1636 break;
1640 break;
1642 lpParms->dwReturn = waveInGetNumDevs();
1643 break;
1645 lpParms->dwReturn = waveOutGetNumDevs();
1646 break;
1647 default:
1648 FIXME("Unknown capability (%08lx) !\n", lpParms->dwItem);
1650 }
1651 } else {
1652 WARN("No GetDevCaps-Item !\n");
1654 }
1655 if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1657 return ret;
1658}
1659
1660/**************************************************************************
1661 * WAVE_mciInfo [internal]
1662 */
1664{
1665 DWORD ret = 0;
1666 LPCWSTR str = 0;
1668
1669 TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1670
1671 if (!lpParms || !lpParms->lpstrReturn)
1673
1674 TRACE("buf=%p, len=%lu\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1675
1676 if (wmw == NULL) {
1678 } else {
1679 switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1680 case MCI_INFO_PRODUCT: str = L"Wine's audio player"; break;
1681 case MCI_INFO_FILE: str = wmw->lpFileName; break;
1682 case MCI_WAVE_INPUT: str = L"Wine Wave In"; break;
1683 case MCI_WAVE_OUTPUT: str = L"Wine Wave Out"; break;
1684 default:
1685 WARN("Don't know this info command (%lu)\n", dwFlags);
1687 }
1688 }
1689 if (!ret) {
1690 if (lpParms->dwRetSize) {
1691 /* FIXME? Since NT, mciwave, mciseq and mcicda set dwRetSize
1692 * to the number of characters written, excluding \0. */
1693 lstrcpynW(lpParms->lpstrReturn, str ? str : L"", lpParms->dwRetSize);
1694 } else ret = MCIERR_PARAM_OVERFLOW;
1695 }
1698 return ret;
1699}
1700
1701/**************************************************************************
1702 * DriverProc (MCIWAVE.@)
1703 */
1706{
1707 TRACE("(%08IX, %p, %08X, %08IX, %08IX)\n",
1708 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1709
1710 switch (wMsg) {
1711 case DRV_LOAD: return 1;
1712 case DRV_FREE: return 1;
1714 case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1715 case DRV_ENABLE: return 1;
1716 case DRV_DISABLE: return 1;
1717 case DRV_QUERYCONFIGURE: return 1;
1718 case DRV_CONFIGURE: MessageBoxA(0, "MCI waveaudio Driver !", "Wine Driver", MB_OK); return 1;
1719 case DRV_INSTALL: return DRVCNF_RESTART;
1720 case DRV_REMOVE: return DRVCNF_RESTART;
1721 }
1722
1723 if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1724
1725 switch (wMsg) {
1728 case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1729 case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, dwParam2, NULL);
1730 case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, dwParam2, NULL);
1731 case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1732 case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_WAVE_SET_PARMS) dwParam2);
1733 case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1737 case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSW) dwParam2);
1738 case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1739 case MCI_SAVE: return WAVE_mciSave (dwDevID, dwParam1, (LPMCI_SAVE_PARMSW) dwParam2);
1740 /* commands that should be supported */
1741 case MCI_LOAD:
1742 case MCI_FREEZE:
1743 case MCI_PUT:
1744 case MCI_REALIZE:
1745 case MCI_UNFREEZE:
1746 case MCI_UPDATE:
1747 case MCI_WHERE:
1748 case MCI_STEP:
1749 case MCI_SPIN:
1750 case MCI_ESCAPE:
1751 case MCI_COPY:
1752 case MCI_CUT:
1753 case MCI_DELETE:
1754 case MCI_PASTE:
1755 FIXME("Unsupported command [%u]\n", wMsg);
1756 break;
1757 case MCI_WINDOW:
1758 TRACE("Unsupported command [%u]\n", wMsg);
1759 break;
1760 /* option which can be silenced */
1761 case MCI_CONFIGURE:
1762 return 0;
1763 case MCI_OPEN:
1764 case MCI_CLOSE:
1765 ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1766 break;
1767 default:
1768 FIXME("is probably wrong msg [%u]\n", wMsg);
1769 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1770 }
1772}
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define WAVE_FORMAT_PCM
Definition: constants.h:425
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define MCI_CONFIGURE
Definition: digitalv.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define lstrcpynW
Definition: compat.h:738
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:2098
BOOL WINAPI SetThreadPriority(IN HANDLE hThread, IN int nPriority)
Definition: thread.c:758
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
#define MCI_NO_COMMAND_TABLE
Definition: mmddk.h:375
#define MCI_FORMAT_RETURN_BASE
Definition: mmddk.h:343
#define MAKEMCIRESOURCE(wRet, wRes)
Definition: mmddk.h:388
#define MCI_FALSE
Definition: mmddk.h:340
#define MCI_TRUE
Definition: mmddk.h:341
#define WAVE_MAPPER_S
Definition: mmddk.h:359
BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, UINT uStatus)
Definition: mci.c:2223
#define MCI_RESOURCE_RETURNED
Definition: mmddk.h:369
#define WAVE_FORMAT_PCM_S
Definition: mmddk.h:358
BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData)
DWORD WINAPI mciGetDriverData(UINT uDeviceID)
Definition: mci.c:2233
#define assert(_expr)
Definition: assert.h:32
static wchar_t * wcsdup(const wchar_t *str)
Definition: string.h:94
LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv, UINT Msg, LPARAM lParam1, LPARAM lParam2)
Definition: driver.c:554
MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags)
Definition: mmio.c:1205
LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
Definition: mmio.c:836
MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
Definition: mmio.c:702
LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch)
Definition: mmio.c:782
MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, const MMCKINFO *lpckParent, UINT uFlags)
Definition: mmio.c:1107
LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
Definition: mmio.c:733
MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO *lpck, UINT uFlags)
Definition: mmio.c:1239
HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO *lpmmioinfo, DWORD dwOpenFlags)
Definition: mmio.c:670
MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName, const MMIOINFO *lpmmioinfo, DWORD dwFlags)
Definition: mmio.c:1320
return ret
Definition: mutex.c:147
#define L(x)
Definition: resources.c:13
#define INFINITE
Definition: serial.h:102
void cleanUp()
Definition: main.cpp:469
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
UINT WINAPI GetTempFileNameW(IN LPCWSTR lpPathName, IN LPCWSTR lpPrefixString, IN UINT uUnique, OUT LPWSTR lpTempFileName)
Definition: filename.c:84
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLint left
Definition: glext.h:7726
GLuint GLfloat * val
Definition: glext.h:7180
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
unsigned int UINT
Definition: sysinfo.c:13
#define DRV_LOAD(x)
const char * filename
Definition: ioapi.h:137
#define SEEK_SET
Definition: jmemansi.c:26
#define debugstr_w
Definition: kernel32.h:32
static LRESULT WAVE_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
Definition: mciwave.c:150
static DWORD create_tmp_file(HMMIO *hFile, LPWSTR *pszTmpFileName)
Definition: mciwave.c:418
#define WAVE_ALIGN_ON_BLOCK(wmw, v)
static DWORD WAVE_mciStatus(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
Definition: mciwave.c:1464
static DWORD WAVE_mciReadFmt(WINE_MCIWAVE *wmw, const MMCKINFO *pckMainRIFF)
Definition: mciwave.c:278
static DWORD WAVE_mciGetDevCaps(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms)
Definition: mciwave.c:1592
static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
Definition: mciwave.c:732
static void WAVE_mciPlayWaitDone(WINE_MCIWAVE *wmw)
Definition: mciwave.c:716
static void WAVE_mciDefaultFmt(WINE_MCIWAVE *wmw)
Definition: mciwave.c:331
static DWORD WAVE_mciPause(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mciwave.c:1159
static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE *wmw)
Definition: mciwave.c:346
static WINE_MCIWAVE * WAVE_mciGetOpenDev(MCIDEVICEID wDevID)
Definition: mciwave.c:195
static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, LPARAM dwParam1, LPARAM dwParam2)
Definition: mciwave.c:693
static DWORD WAVE_mciSet(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_SET_PARMS lpParms)
Definition: mciwave.c:1286
static void WAVE_mciRecordWaitDone(WINE_MCIWAVE *wmw)
Definition: mciwave.c:977
static DWORD MCI_SendCommandAsync(UINT wDevID, async_cmd cmd, DWORD_PTR dwParam1, DWORD_PTR dwParam2, UINT size)
Definition: mciwave.c:99
static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE *wmw, DWORD val)
Definition: mciwave.c:227
LRESULT CALLBACK MCIWAVE_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, LPARAM dwParam1, LPARAM dwParam2)
Definition: mciwave.c:1704
static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, LPARAM dwParam1, LPARAM dwParam2)
Definition: mciwave.c:934
static DWORD WAVE_mciClose(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mciwave.c:653
static void WAVE_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIWAVE *wmw, UINT wStatus)
Definition: mciwave.c:213
static DWORD WAVE_mciCue(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mciwave.c:578
static LRESULT WAVE_drvClose(MCIDEVICEID dwDevID)
Definition: mciwave.c:180
static LRESULT WAVE_mciOpen(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSW lpOpenParms)
Definition: mciwave.c:511
static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE *wmw, DWORD val)
Definition: mciwave.c:251
DWORD(* async_cmd)(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE evt)
Definition: mciwave.c:69
static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mciwave.c:1199
static LRESULT WAVE_mciOpenFile(WINE_MCIWAVE *wmw, LPCWSTR filename)
Definition: mciwave.c:459
static DWORD WAVE_mciSeek(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
Definition: mciwave.c:1242
static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
Definition: mciwave.c:993
static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
Definition: mciwave.c:82
static DWORD WAVE_mciSave(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SAVE_PARMSW lpParms)
Definition: mciwave.c:1412
static DWORD WAVE_mciInfo(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
Definition: mciwave.c:1663
static DWORD WAVE_mciStop(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mciwave.c:615
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define MCI_CUT
Definition: mmsystem.h:671
#define MCI_SAVE
Definition: mmsystem.h:661
#define DRV_CLOSE
Definition: mmsystem.h:122
#define WOM_DONE
Definition: mmsystem.h:183
#define MCI_SET_AUDIO
Definition: mmsystem.h:775
#define MCIERR_FLAGS_NOT_COMPATIBLE
Definition: mmsystem.h:593
#define MCI_OPEN_SHAREABLE
Definition: mmsystem.h:734
#define MCI_INFO_PRODUCT
Definition: mmsystem.h:752
#define MCI_NOTIFY_SUPERSEDED
Definition: mmsystem.h:726
struct wavehdr_tag * LPWAVEHDR
#define MCI_GETDEVCAPS_CAN_SAVE
Definition: mmsystem.h:767
#define MCI_SEEK_TO_END
Definition: mmsystem.h:741
#define MCI_NOTIFY
Definition: mmsystem.h:729
#define MCI_TO
Definition: mmsystem.h:732
#define MMIO_ALLOCBUF
Definition: mmsystem.h:532
#define FOURCC_RIFF
Definition: mmsystem.h:564
#define MCI_WAVE_SET_SAMPLESPERSEC
Definition: mmsystem.h:824
#define MCI_WAVE_STATUS_BITSPERSAMPLE
Definition: mmsystem.h:835
#define MCI_GETDEVCAPS_HAS_VIDEO
Definition: mmsystem.h:761
#define MCI_STATUS_POSITION
Definition: mmsystem.h:745
#define WOM_OPEN
Definition: mmsystem.h:181
#define DRV_QUERYCONFIGURE
Definition: mmsystem.h:126
#define MCI_WAVE_STATUS_LEVEL
Definition: mmsystem.h:836
#define MCI_GETDEVCAPS
Definition: mmsystem.h:654
#define MCI_OPEN_ELEMENT_ID
Definition: mmsystem.h:737
#define MCI_RESUME
Definition: mmsystem.h:675
#define MCI_GETDEVCAPS_CAN_RECORD
Definition: mmsystem.h:759
#define MCI_OPEN_ELEMENT
Definition: mmsystem.h:735
#define MCI_DELETE
Definition: mmsystem.h:676
#define WIM_DATA
Definition: mmsystem.h:186
#define MMIO_READWRITE
Definition: mmsystem.h:537
#define MCIERR_HARDWARE
Definition: mmsystem.h:572
#define WOM_CLOSE
Definition: mmsystem.h:182
#define MCI_FORMAT_SAMPLES
Definition: mmsystem.h:710
#define MCI_FORMAT_MILLISECONDS
Definition: mmsystem.h:701
#define MCI_MODE_PLAY
Definition: mmsystem.h:696
#define MCI_WAVE_OUTPUT
Definition: mmsystem.h:829
#define MCI_FREEZE
Definition: mmsystem.h:668
#define MMIO_FINDCHUNK
Definition: mmsystem.h:551
#define MCI_WAVE_INPUT
Definition: mmsystem.h:828
#define MCIERR_FILE_NOT_FOUND
Definition: mmsystem.h:585
#define MMIO_CREATE
Definition: mmsystem.h:528
#define MCI_FORMAT_BYTES
Definition: mmsystem.h:709
#define MCI_GETDEVCAPS_DEVICE_TYPE
Definition: mmsystem.h:762
#define DRVCNF_RESTART
Definition: mmsystem.h:135
#define MCI_WINDOW
Definition: mmsystem.h:665
#define MCI_STATUS
Definition: mmsystem.h:662
#define WAVE_MAPPER
Definition: mmsystem.h:187
#define MCI_COPY
Definition: mmsystem.h:672
#define MCI_WAVE_GETDEVCAPS_OUTPUTS
Definition: mmsystem.h:840
#define MCI_ESCAPE
Definition: mmsystem.h:648
#define MCIERR_UNRECOGNIZED_COMMAND
Definition: mmsystem.h:571
#define MCI_WAVE_STATUS_BLOCKALIGN
Definition: mmsystem.h:834
#define MCI_WAVE_SET_AVGBYTESPERSEC
Definition: mmsystem.h:825
#define MCI_SET
Definition: mmsystem.h:656
#define MCI_GETDEVCAPS_COMPOUND_DEVICE
Definition: mmsystem.h:764
#define MCI_WAVE_SET_ANYINPUT
Definition: mmsystem.h:837
#define MCIERR_BAD_INTEGER
Definition: mmsystem.h:580
#define MCI_SET_DOOR_OPEN
Definition: mmsystem.h:772
#define MCI_GETDEVCAPS_USES_FILES
Definition: mmsystem.h:763
#define MCI_GETDEVCAPS_CAN_PLAY
Definition: mmsystem.h:766
#define MCI_LOAD
Definition: mmsystem.h:670
#define MCI_WAVE_STATUS_SAMPLESPERSEC
Definition: mmsystem.h:832
#define MCI_UPDATE
Definition: mmsystem.h:674
#define MCI_WAVE_GETDEVCAPS_INPUTS
Definition: mmsystem.h:839
#define DRV_REMOVE
Definition: mmsystem.h:128
#define DRV_ENABLE
Definition: mmsystem.h:120
#define MCI_STOP
Definition: mmsystem.h:651
#define WIM_CLOSE
Definition: mmsystem.h:185
#define MMIO_DENYWRITE
Definition: mmsystem.h:540
#define MCIERR_PARAM_OVERFLOW
Definition: mmsystem.h:578
#define MCI_CLOSE
Definition: mmsystem.h:647
#define MCIERR_INVALID_DEVICE_ID
Definition: mmsystem.h:569
#define MCI_SET_TIME_FORMAT
Definition: mmsystem.h:774
#define MCI_SEEK
Definition: mmsystem.h:650
#define DRV_CONFIGURE
Definition: mmsystem.h:125
#define MCIERR_INVALID_FILE
Definition: mmsystem.h:604
#define MCI_GETDEVCAPS_CAN_EJECT
Definition: mmsystem.h:765
#define MCI_SET_VIDEO
Definition: mmsystem.h:776
#define DRV_OPEN
Definition: mmsystem.h:121
#define MCIERR_DEVICE_OPEN
Definition: mmsystem.h:575
#define MCIERR_MISSING_PARAMETER
Definition: mmsystem.h:583
struct pcmwaveformat_tag PCMWAVEFORMAT
#define MCIERR_INTERNAL
Definition: mmsystem.h:587
#define MCI_WHERE
Definition: mmsystem.h:667
#define MCI_SET_AUDIO_RIGHT
Definition: mmsystem.h:781
#define MCIERR_NULL_PARAMETER_BLOCK
Definition: mmsystem.h:605
#define MCI_NOTIFY_ABORTED
Definition: mmsystem.h:727
#define MCI_INFO_FILE
Definition: mmsystem.h:753
#define MCI_STATUS_START
Definition: mmsystem.h:743
#define MCI_SET_AUDIO_ALL
Definition: mmsystem.h:779
#define MCIERR_FILE_NOT_SAVED
Definition: mmsystem.h:594
#define MCIERR_OUTOFRANGE
Definition: mmsystem.h:592
#define DRV_INSTALL
Definition: mmsystem.h:127
#define MCI_WAVE_SET_FORMATTAG
Definition: mmsystem.h:822
#define MCI_OPEN
Definition: mmsystem.h:646
#define MCI_WAVE_STATUS_FORMATTAG
Definition: mmsystem.h:830
#define MCI_STATUS_CURRENT_TRACK
Definition: mmsystem.h:751
#define MCI_UNFREEZE
Definition: mmsystem.h:669
#define MCI_STATUS_NUMBER_OF_TRACKS
Definition: mmsystem.h:746
UINT MCIDEVICEID
Definition: mmsystem.h:961
#define MCIERR_OUT_OF_MEMORY
Definition: mmsystem.h:574
#define MCI_SET_DOOR_CLOSED
Definition: mmsystem.h:773
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define MCI_WAVE_SET_CHANNELS
Definition: mmsystem.h:823
#define MCI_MODE_RECORD
Definition: mmsystem.h:697
#define MCI_GETDEVCAPS_ITEM
Definition: mmsystem.h:758
#define MCI_WAVE_STATUS_AVGBYTESPERSEC
Definition: mmsystem.h:833
#define MCI_STATUS_LENGTH
Definition: mmsystem.h:744
#define MCI_SET_AUDIO_LEFT
Definition: mmsystem.h:780
#define MCI_STATUS_MODE
Definition: mmsystem.h:747
#define MCIERR_UNRECOGNIZED_KEYWORD
Definition: mmsystem.h:570
#define mmioFOURCC(c0, c1, c2, c3)
Definition: mmsystem.h:38
#define MCI_SET_OFF
Definition: mmsystem.h:778
#define MCI_WAVE_SET_BITSPERSAMPLE
Definition: mmsystem.h:827
#define MCI_DEVTYPE_WAVEFORM_AUDIO
Definition: mmsystem.h:689
#define MCI_PUT
Definition: mmsystem.h:666
#define MCI_WAVE_SET_BLOCKALIGN
Definition: mmsystem.h:826
#define MCI_SPIN
Definition: mmsystem.h:655
#define MCI_MODE_STOP
Definition: mmsystem.h:695
#define MMIO_READ
Definition: mmsystem.h:535
#define MCI_SEEK_TO_START
Definition: mmsystem.h:740
#define MCI_WAIT
Definition: mmsystem.h:730
#define MCI_NOTIFY_SUCCESSFUL
Definition: mmsystem.h:725
#define CALLBACK_FUNCTION
Definition: mmsystem.h:150
#define MCI_CUE
Definition: mmsystem.h:663
#define MCI_NOTIFY_FAILURE
Definition: mmsystem.h:728
#define MMIO_CREATERIFF
Definition: mmsystem.h:554
#define MCI_PAUSE
Definition: mmsystem.h:652
#define MCI_WAVE_SET_ANYOUTPUT
Definition: mmsystem.h:838
#define MCI_FROM
Definition: mmsystem.h:731
#define WIM_OPEN
Definition: mmsystem.h:184
#define MCI_INFO
Definition: mmsystem.h:653
#define MCI_MODE_NOT_READY
Definition: mmsystem.h:694
#define MCI_STATUS_MEDIA_PRESENT
Definition: mmsystem.h:748
#define MCIERR_BAD_TIME_FORMAT
Definition: mmsystem.h:601
#define MCI_MODE_PAUSE
Definition: mmsystem.h:699
#define MCI_PASTE
Definition: mmsystem.h:673
#define MCIERR_NONAPPLICABLE_FUNCTION
Definition: mmsystem.h:610
#define DRV_FREE
Definition: mmsystem.h:124
#define MCIERR_UNSUPPORTED_FUNCTION
Definition: mmsystem.h:584
#define MCI_PLAY
Definition: mmsystem.h:649
char * HPSTR
Definition: mmsystem.h:1479
#define MCI_STATUS_TIME_FORMAT
Definition: mmsystem.h:749
#define MCI_STEP
Definition: mmsystem.h:657
#define MCI_SET_ON
Definition: mmsystem.h:777
#define MCI_REALIZE
Definition: mmsystem.h:664
#define MCI_WAVE_STATUS_CHANNELS
Definition: mmsystem.h:831
#define MCI_RECORD
Definition: mmsystem.h:658
#define MCI_STATUS_ITEM
Definition: mmsystem.h:742
#define MCI_GETDEVCAPS_HAS_AUDIO
Definition: mmsystem.h:760
#define MCI_STATUS_READY
Definition: mmsystem.h:750
#define DRV_DISABLE
Definition: mmsystem.h:123
static HANDLE hEvent
Definition: comm.c:54
#define min(a, b)
Definition: monoChain.cc:55
_In_ HANDLE hFile
Definition: mswsock.h:90
INT WINAPI MulDiv(INT nNumber, INT nNumerator, INT nDenominator)
Definition: muldiv.c:25
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
#define DWORD
Definition: nt_native.h:44
#define LOWORD(l)
Definition: pedump.c:82
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
int WINAPI MessageBoxA(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
#define MB_OK
Definition: winuser.h:801
#define err(...)
#define calloc
Definition: rosglue.h:14
const WCHAR * str
#define MCI_OPEN_DRIVER
Definition: mmddk.h:338
#define MCI_CLOSE_DRIVER
Definition: mmddk.h:339
#define TRACE(s)
Definition: solgame.cpp:4
UINT wCustomCommandTable
Definition: mmddk.h:438
Definition: mciwave.c:71
UINT wDevID
Definition: mciwave.c:74
DWORD_PTR dwParam1
Definition: mciwave.c:75
HANDLE evt
Definition: mciwave.c:73
DWORD_PTR dwParam2
Definition: mciwave.c:76
async_cmd cmd
Definition: mciwave.c:72
DWORD nAvgBytesPerSec
Definition: audioclient.idl:43
WORD wBitsPerSample
Definition: audioclient.idl:45
DWORD nSamplesPerSec
Definition: audioclient.idl:42
BOOL fInput
Definition: mciwave.c:48
WORD wInput
Definition: mciwave.c:49
MMCKINFO ckWaveData
Definition: mciwave.c:57
MMCKINFO ckMainRIFF
Definition: mciwave.c:56
HANDLE hCallback
Definition: mciwave.c:44
WAVEFORMATEX wfxRef
Definition: mciwave.c:46
HANDLE hEvent
Definition: mciwave.c:54
HMMIO hFile
Definition: mciwave.c:42
MCIDEVICEID wNotifyDeviceID
Definition: mciwave.c:43
DWORD dwMciTimeFormat
Definition: mciwave.c:52
LPWAVEFORMATEX lpWaveFormat
Definition: mciwave.c:47
LONG dwEventCount
Definition: mciwave.c:55
LPWSTR lpFileName
Definition: mciwave.c:45
DWORD dwPosition
Definition: mciwave.c:53
int nUseCount
Definition: mciwave.c:41
volatile WORD dwStatus
Definition: mciwave.c:51
UINT wDevID
Definition: mciwave.c:39
HANDLE hWave
Definition: mciwave.c:40
WORD wOutput
Definition: mciwave.c:50
FOURCC ckid
Definition: mmsystem.h:1509
DWORD cksize
Definition: mmsystem.h:1510
DWORD dwDataOffset
Definition: mmsystem.h:1512
FOURCC fccType
Definition: mmsystem.h:1511
WORD nBlockAlign
Definition: mmreg.h:82
WORD cbSize
Definition: mmreg.h:84
DWORD nAvgBytesPerSec
Definition: mmreg.h:81
DWORD nSamplesPerSec
Definition: mmreg.h:80
WORD nChannels
Definition: mmreg.h:79
WORD wFormatTag
Definition: mmreg.h:78
WORD wBitsPerSample
Definition: mmreg.h:83
Definition: ftp_var.h:139
DWORD_PTR dwCallback
Definition: mmsystem.h:1519
DWORD_PTR dwCallback
Definition: mmsystem.h:1581
DWORD_PTR dwCallback
Definition: mmsystem.h:1539
DWORD_PTR dwCallback
Definition: mmsystem.h:1641
LPCWSTR lpfilename
Definition: mmsystem.h:1627
DWORD_PTR dwCallback
Definition: mmsystem.h:1626
DWORD_PTR dwCallback
Definition: mmsystem.h:1545
DWORD_PTR dwReturn
Definition: mmsystem.h:1569
DWORD_PTR dwCallback
Definition: mmsystem.h:1568
MCIDEVICEID wDeviceID
Definition: mmsystem.h:1679
DWORD_PTR dwCallback
Definition: mmsystem.h:1693
DWORD dwBufferLength
Definition: mmsystem.h:1017
DWORD dwLoops
Definition: mmsystem.h:1021
DWORD dwFlags
Definition: mmsystem.h:1020
DWORD dwBytesRecorded
Definition: mmsystem.h:1018
DWORD_PTR dwUser
Definition: mmsystem.h:1019
LPSTR lpData
Definition: mmsystem.h:1016
DWORD WINAPI WaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds)
Definition: synch.c:151
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:726
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:587
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:669
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:650
#define DWORD_PTR
Definition: treelist.c:76
const uint16_t * LPCWSTR
Definition: typedefs.h:57
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint16_t * LPWSTR
Definition: typedefs.h:56
char * LPSTR
Definition: typedefs.h:51
static EFI_HANDLE * handles
Definition: uefidisk.c:66
static GLenum _GLUfuncptr fn
Definition: wgl_font.c:159
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define THREAD_PRIORITY_TIME_CRITICAL
Definition: winbase.h:306
#define HRESULT_CODE(hr)
Definition: winerror.h:188
UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
Definition: winmm.c:2385
UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2717
UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2653
UINT WINAPI waveInStop(HWAVEIN hWaveIn)
Definition: winmm.c:2764
UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR *lpWaveInHdr, UINT uSize)
Definition: winmm.c:2684
UINT WINAPI waveOutGetNumDevs(void)
Definition: winmm.c:2137
UINT WINAPI waveInReset(HWAVEIN hWaveIn)
Definition: winmm.c:2734
UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2341
UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2307
MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:2246
UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
Definition: winmm.c:2399
MMRESULT WINAPI waveInOpen(HWAVEIN *lphWaveIn, UINT uDeviceID, LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:2623
UINT WINAPI waveInGetNumDevs(void)
Definition: winmm.c:2565
UINT WINAPI waveInClose(HWAVEIN hWaveIn)
Definition: winmm.c:2634
UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, WAVEHDR *lpWaveOutHdr, UINT uSize)
Definition: winmm.c:2277
UINT WINAPI waveInStart(HWAVEIN hWaveIn)
Definition: winmm.c:2749
UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
Definition: winmm.c:2371
UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
Definition: winmm.c:2257
#define HWND_32(h16)
Definition: wownt32.h:29