1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Wine Wave mapper driver
5 * Copyright 1999,2001 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * + better protection against evilish dwUser parameters
24 * + use asynchronous ACM conversion
25 * + don't use callback functions when none is required in open
26 * + the buffer sizes may not be accurate, so there may be some
27 * remaining bytes in src and dst buffers after ACM conversions...
28 * those should be taken care of...
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
44 typedef struct tagWAVEMAPDATA {
45 struct tagWAVEMAPDATA* self;
56 HACMSTREAM hAcmStream;
57 /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
59 DWORD dwClientInstance;
61 /* ratio to compute position from a PCM playback to any format */
66 static BOOL WAVEMAP_IsData(WAVEMAPDATA* wm)
68 return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
71 /*======================================================================*
73 *======================================================================*/
75 static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance,
76 DWORD dwParam1, DWORD dwParam2)
78 WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance;
80 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
82 if (!WAVEMAP_IsData(wom)) {
87 if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)
88 ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
93 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
96 if (wom->hAcmStream) {
97 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1;
98 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
99 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
101 lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
102 lpWaveHdrSrc->dwFlags |= WHDR_DONE;
103 dwParam1 = (DWORD)lpWaveHdrSrc;
107 ERR("Unknown msg %u\n", uMsg);
110 DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
111 uMsg, wom->dwClientInstance, dwParam1, dwParam2);
114 /******************************************************************
119 static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
120 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
125 TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags);
127 /* destination is always PCM, so the formulas below apply */
128 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
129 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
130 if (dwFlags & WAVE_FORMAT_QUERY) {
131 ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
133 ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
135 if (ret == MMSYSERR_NOERROR) {
136 ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,
137 (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
138 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
139 acmStreamClose(wom->hAcmStream, 0);
143 TRACE("ret = %08lx\n", ret);
147 static DWORD wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
151 WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
154 TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
158 return MMSYSERR_NOMEM;
161 ndhi = waveOutGetNumDevs();
162 if (dwFlags & WAVE_MAPPED) {
163 if (lpDesc->uMappedDeviceID >= ndhi) {
164 WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
165 return MMSYSERR_INVALPARAM;
167 ndlo = lpDesc->uMappedDeviceID;
169 dwFlags &= ~WAVE_MAPPED;
174 wom->dwCallback = lpDesc->dwCallback;
175 wom->dwFlags = dwFlags;
176 wom->dwClientInstance = lpDesc->dwInstance;
177 wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
178 wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
180 for (i = ndlo; i < ndhi; i++) {
181 /* if no ACM stuff is involved, no need to handle callbacks at this
182 * level, this will be done transparently
184 if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback,
185 (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
191 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) {
194 wfx.wFormatTag = WAVE_FORMAT_PCM;
195 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
196 /* try some ACM stuff */
198 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
199 switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
200 case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
201 case WAVERR_BADFORMAT: break; \
202 default: goto error; \
205 /* Our resampling algorithm is quite primitive so first try
206 * to just change the bit depth and number of channels
208 for (i = ndlo; i < ndhi; i++) {
209 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
210 wfx.nChannels = lpDesc->lpFormat->nChannels;
211 TRY(wfx.nSamplesPerSec, 16);
212 TRY(wfx.nSamplesPerSec, 8);
214 TRY(wfx.nSamplesPerSec, 16);
215 TRY(wfx.nSamplesPerSec, 8);
218 for (i = ndlo; i < ndhi; i++) {
219 /* first try with same stereo/mono option as source */
220 wfx.nChannels = lpDesc->lpFormat->nChannels;
227 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
235 /* first try with same stereo/mono option as source */
236 wfx.nChannels = lpDesc->lpFormat->nChannels;
243 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
254 HeapFree(GetProcessHeap(), 0, wom);
255 WARN("ret = WAVERR_BADFORMAT\n");
256 return WAVERR_BADFORMAT;
259 if (dwFlags & WAVE_FORMAT_QUERY) {
261 HeapFree(GetProcessHeap(), 0, wom);
263 *lpdwUser = (DWORD)wom;
265 return MMSYSERR_NOERROR;
267 HeapFree(GetProcessHeap(), 0, wom);
268 if (res==ACMERR_NOTPOSSIBLE) {
269 WARN("ret = WAVERR_BADFORMAT\n");
270 return WAVERR_BADFORMAT;
272 WARN("ret = MMSYSERR_ERROR\n");
273 return MMSYSERR_ERROR;
276 static DWORD wodClose(WAVEMAPDATA* wom)
280 TRACE("(%p)\n", wom);
282 ret = waveOutClose(wom->u.out.hInnerWave);
283 if (ret == MMSYSERR_NOERROR) {
284 if (wom->hAcmStream) {
285 ret = acmStreamClose(wom->hAcmStream, 0);
287 if (ret == MMSYSERR_NOERROR) {
288 HeapFree(GetProcessHeap(), 0, wom);
294 static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
296 PACMSTREAMHEADER ash;
297 LPWAVEHDR lpWaveHdrDst;
299 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
301 if (!wom->hAcmStream) {
302 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
305 lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
306 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
307 /* acmStreamConvert will actually check that the new size is less than initial size */
308 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
309 if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
310 WARN("acmStreamConvert failed\n");
311 return MMSYSERR_ERROR;
314 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
315 if (ash->cbSrcLength > ash->cbSrcLengthUsed)
316 FIXME("Not all src buffer has been written, expect bogus sound\n");
317 else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
318 ERR("CoDec has read more data than it is allowed to\n");
320 if (ash->cbDstLengthUsed == 0) {
321 /* something went wrong in decoding */
322 FIXME("Got 0 length\n");
323 return MMSYSERR_ERROR;
325 lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
326 return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
329 static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
331 PACMSTREAMHEADER ash;
334 LPWAVEHDR lpWaveHdrDst;
336 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
338 if (!wom->hAcmStream)
339 return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
341 if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
342 WARN("acmStreamSize failed\n");
343 return MMSYSERR_ERROR;
346 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
349 return MMSYSERR_NOMEM;
352 ash->cbStruct = sizeof(*ash);
354 ash->dwUser = (DWORD)lpWaveHdrSrc;
355 ash->pbSrc = lpWaveHdrSrc->lpData;
356 ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
357 /* ash->cbSrcLengthUsed */
358 ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
359 ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
360 ash->cbDstLength = size;
361 /* ash->cbDstLengthUsed */
362 ash->dwDstUser = 0; /* FIXME ? */
363 dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
364 if (dwRet != MMSYSERR_NOERROR) {
365 WARN("acmStreamPrepareHeader failed\n");
369 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
370 lpWaveHdrDst->lpData = ash->pbDst;
371 lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
372 lpWaveHdrDst->dwFlags = 0;
373 lpWaveHdrDst->dwLoops = 0;
374 dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
375 if (dwRet != MMSYSERR_NOERROR) {
376 WARN("waveOutPrepareHeader failed\n");
380 lpWaveHdrSrc->reserved = (DWORD)ash;
381 lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
383 return MMSYSERR_NOERROR;
385 TRACE("=> (%ld)\n", dwRet);
386 HeapFree(GetProcessHeap(), 0, ash);
390 static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
392 PACMSTREAMHEADER ash;
393 LPWAVEHDR lpWaveHdrDst;
394 DWORD dwRet1, dwRet2;
396 TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
398 if (!wom->hAcmStream) {
399 return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
401 ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
402 dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
404 lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
405 dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
407 HeapFree(GetProcessHeap(), 0, ash);
409 lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
410 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
413 static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
416 TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2);
418 val = waveOutGetPosition(wom->u.out.hInnerWave, lpTime, dwParam2);
419 if (lpTime->wType == TIME_BYTES)
420 lpTime->u.cb = MulDiv(lpTime->u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
421 /* other time types don't require conversion */
425 static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
427 TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2);
429 /* if opened low driver, forward message */
430 if (WAVEMAP_IsData(wom))
431 return waveOutGetDevCapsA((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
432 /* else if no drivers, nothing to map so return bad device */
433 if (waveOutGetNumDevs() == 0) {
434 WARN("bad device id\n");
435 return MMSYSERR_BADDEVICEID;
437 /* otherwise, return caps of mapper itself */
438 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
442 woc.vDriverVersion = 0x0100;
443 strcpy(woc.szPname, "Wine wave out mapper");
445 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
446 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
447 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
448 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
449 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
451 woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
452 memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
454 return MMSYSERR_NOERROR;
456 ERR("This shouldn't happen\n");
457 return MMSYSERR_ERROR;
460 static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
462 TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
464 if (WAVEMAP_IsData(wom))
465 return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
466 return MMSYSERR_NOERROR;
469 static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
471 TRACE("(%04x %p %08lx)\n",wDevID, wom, vol);
473 if (WAVEMAP_IsData(wom))
474 return waveOutSetVolume(wom->u.out.hInnerWave, vol);
475 return MMSYSERR_NOERROR;
478 static DWORD wodPause(WAVEMAPDATA* wom)
482 return waveOutPause(wom->u.out.hInnerWave);
485 static DWORD wodRestart(WAVEMAPDATA* wom)
489 return waveOutRestart(wom->u.out.hInnerWave);
492 static DWORD wodReset(WAVEMAPDATA* wom)
496 return waveOutReset(wom->u.out.hInnerWave);
499 static DWORD wodBreakLoop(WAVEMAPDATA* wom)
503 return waveOutBreakLoop(wom->u.out.hInnerWave);
506 static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
509 DWORD ret = MMSYSERR_NOTSUPPORTED;
511 TRACE("(%p %08lx %p)\n",wom, flags, ptr);
514 case WAVEOUT_MAPPER_STATUS_DEVICE:
515 ret = waveOutGetID(wom->u.out.hInnerWave, &id);
518 case WAVEOUT_MAPPER_STATUS_MAPPED:
519 FIXME("Unsupported flag=%ld\n", flags);
520 *(LPDWORD)ptr = 0; /* FIXME ?? */
522 case WAVEOUT_MAPPER_STATUS_FORMAT:
523 FIXME("Unsupported flag=%ld\n", flags);
524 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
528 FIXME("Unsupported flag=%ld\n", flags);
535 /**************************************************************************
536 * wodMessage (MSACM.@)
538 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
539 DWORD dwParam1, DWORD dwParam2)
541 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
542 wDevID, wMsg, dwUser, dwParam1, dwParam2);
549 /* FIXME: Pretend this is supported */
551 case WODM_OPEN: return wodOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2);
552 case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser);
553 case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
554 case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser);
555 case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
556 case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser);
557 case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
558 case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
559 case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
560 case WODM_GETNUMDEVS: return 1;
561 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
562 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
563 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
564 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
565 case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
566 case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
567 case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser);
568 case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser);
569 case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
570 /* known but not supported */
571 case DRV_QUERYDEVICEINTERFACESIZE:
572 case DRV_QUERYDEVICEINTERFACE:
573 return MMSYSERR_NOTSUPPORTED;
575 FIXME("unknown message %d!\n", wMsg);
577 return MMSYSERR_NOTSUPPORTED;
580 /*======================================================================*
582 *======================================================================*/
584 static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance,
585 DWORD dwParam1, DWORD dwParam2)
587 WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance;
589 TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
591 if (!WAVEMAP_IsData(wim)) {
596 if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN)
597 ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
602 /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
605 if (wim->hAcmStream) {
606 LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
607 PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
608 LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
610 /* convert data just gotten from waveIn into requested format */
611 if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
612 ERR("ACM conversion failed\n");
615 TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
617 /* and setup the wavehdr to return accordingly */
618 lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
619 lpWaveHdrDst->dwFlags |= WHDR_DONE;
620 lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
621 dwParam1 = (DWORD)lpWaveHdrDst;
625 ERR("Unknown msg %u\n", uMsg);
628 DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
629 uMsg, wim->dwClientInstance, dwParam1, dwParam2);
632 static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx,
633 LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
638 TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags);
640 /* source is always PCM, so the formulas below apply */
641 lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
642 lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
643 if (dwFlags & WAVE_FORMAT_QUERY) {
644 ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
646 ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
648 if (ret == MMSYSERR_NOERROR) {
649 ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback,
650 (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
651 if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
652 acmStreamClose(wim->hAcmStream, 0);
656 TRACE("ret = %08lx\n", ret);
660 static DWORD widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
664 WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
667 TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
671 return MMSYSERR_NOMEM;
675 wim->dwCallback = lpDesc->dwCallback;
676 wim->dwFlags = dwFlags;
677 wim->dwClientInstance = lpDesc->dwInstance;
678 wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
680 ndhi = waveInGetNumDevs();
681 if (dwFlags & WAVE_MAPPED) {
682 if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
683 ndlo = lpDesc->uMappedDeviceID;
685 dwFlags &= ~WAVE_MAPPED;
690 wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
692 for (i = ndlo; i < ndhi; i++) {
693 if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback,
694 (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
700 if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
704 wfx.wFormatTag = WAVE_FORMAT_PCM;
705 wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
706 /* try some ACM stuff */
708 #define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
709 switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
710 case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; goto found; \
711 case WAVERR_BADFORMAT: break; \
712 default: goto error; \
715 for (i = ndlo; i < ndhi; i++) {
716 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
717 /* first try with same stereo/mono option as source */
718 wfx.nChannels = lpDesc->lpFormat->nChannels;
719 TRY(wfx.nSamplesPerSec, 16);
720 TRY(wfx.nSamplesPerSec, 8);
722 TRY(wfx.nSamplesPerSec, 16);
723 TRY(wfx.nSamplesPerSec, 8);
726 for (i = ndlo; i < ndhi; i++) {
727 wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
728 /* first try with same stereo/mono option as source */
729 wfx.nChannels = lpDesc->lpFormat->nChannels;
736 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
744 /* first try with same stereo/mono option as source */
745 wfx.nChannels = lpDesc->lpFormat->nChannels;
752 /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
763 HeapFree(GetProcessHeap(), 0, wim);
764 WARN("ret = WAVERR_BADFORMAT\n");
765 return WAVERR_BADFORMAT;
767 if (dwFlags & WAVE_FORMAT_QUERY) {
769 HeapFree(GetProcessHeap(), 0, wim);
771 *lpdwUser = (DWORD)wim;
773 TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream);
774 return MMSYSERR_NOERROR;
776 HeapFree(GetProcessHeap(), 0, wim);
777 if (res==ACMERR_NOTPOSSIBLE) {
778 WARN("ret = WAVERR_BADFORMAT\n");
779 return WAVERR_BADFORMAT;
781 WARN("ret = MMSYSERR_ERROR\n");
782 return MMSYSERR_ERROR;
785 static DWORD widClose(WAVEMAPDATA* wim)
789 TRACE("(%p)\n", wim);
791 ret = waveInClose(wim->u.in.hInnerWave);
792 if (ret == MMSYSERR_NOERROR) {
793 if (wim->hAcmStream) {
794 ret = acmStreamClose(wim->hAcmStream, 0);
796 if (ret == MMSYSERR_NOERROR) {
797 HeapFree(GetProcessHeap(), 0, wim);
803 static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
805 PACMSTREAMHEADER ash;
806 LPWAVEHDR lpWaveHdrSrc;
808 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
810 if (!wim->hAcmStream) {
811 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
814 lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
815 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
817 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
818 return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
821 static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
823 PACMSTREAMHEADER ash;
826 LPWAVEHDR lpWaveHdrSrc;
828 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
830 if (!wim->hAcmStream) {
831 return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
833 if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
834 ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
835 WARN("acmStreamSize failed\n");
836 return MMSYSERR_ERROR;
839 ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
842 return MMSYSERR_NOMEM;
845 ash->cbStruct = sizeof(*ash);
847 ash->dwUser = (DWORD)lpWaveHdrDst;
848 ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
849 ash->cbSrcLength = size;
850 /* ash->cbSrcLengthUsed */
851 ash->dwSrcUser = 0L; /* FIXME ? */
852 ash->pbDst = lpWaveHdrDst->lpData;
853 ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
854 /* ash->cbDstLengthUsed */
855 ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
856 dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
857 if (dwRet != MMSYSERR_NOERROR) {
858 WARN("acmStreamPrepareHeader failed\n");
862 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
863 lpWaveHdrSrc->lpData = ash->pbSrc;
864 lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
865 lpWaveHdrSrc->dwFlags = 0;
866 lpWaveHdrSrc->dwLoops = 0;
867 dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
868 if (dwRet != MMSYSERR_NOERROR) {
869 WARN("waveInPrepareHeader failed\n");
873 lpWaveHdrDst->reserved = (DWORD)ash;
874 lpWaveHdrDst->dwFlags = WHDR_PREPARED;
876 return MMSYSERR_NOERROR;
878 TRACE("=> (%ld)\n", dwRet);
879 HeapFree(GetProcessHeap(), 0, ash);
883 static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
885 PACMSTREAMHEADER ash;
886 LPWAVEHDR lpWaveHdrSrc;
887 DWORD dwRet1, dwRet2;
889 TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
891 if (!wim->hAcmStream) {
892 return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
894 ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
895 dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
897 lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
898 dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
900 HeapFree(GetProcessHeap(), 0, ash);
902 lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
903 return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
906 static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
910 TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2);
912 val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);
913 if (lpTime->wType == TIME_BYTES)
914 lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
915 /* other time types don't require conversion */
919 static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
921 TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2);
923 /* if opened low driver, forward message */
924 if (WAVEMAP_IsData(wim))
925 return waveInGetDevCapsA((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
926 /* else if no drivers, nothing to map so return bad device */
927 if (waveInGetNumDevs() == 0) {
928 WARN("bad device id\n");
929 return MMSYSERR_BADDEVICEID;
931 /* otherwise, return caps of mapper itself */
932 if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
936 wic.vDriverVersion = 0x0001;
937 strcpy(wic.szPname, "Wine wave in mapper");
939 WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
940 WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
941 WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
942 WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
943 WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
945 memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
947 return MMSYSERR_NOERROR;
949 ERR("This shouldn't happen\n");
950 return MMSYSERR_ERROR;
953 static DWORD widStop(WAVEMAPDATA* wim)
955 TRACE("(%p)\n", wim);
957 return waveInStop(wim->u.in.hInnerWave);
960 static DWORD widStart(WAVEMAPDATA* wim)
962 TRACE("(%p)\n", wim);
964 return waveInStart(wim->u.in.hInnerWave);
967 static DWORD widReset(WAVEMAPDATA* wim)
969 TRACE("(%p)\n", wim);
971 return waveInReset(wim->u.in.hInnerWave);
974 static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
977 DWORD ret = MMSYSERR_NOTSUPPORTED;
979 TRACE("(%p %08lx %p)\n", wim, flags, ptr);
982 case WAVEIN_MAPPER_STATUS_DEVICE:
983 ret = waveInGetID(wim->u.in.hInnerWave, &id);
986 case WAVEIN_MAPPER_STATUS_MAPPED:
987 FIXME("Unsupported yet flag=%ld\n", flags);
988 *(LPDWORD)ptr = 0; /* FIXME ?? */
990 case WAVEIN_MAPPER_STATUS_FORMAT:
991 FIXME("Unsupported flag=%ld\n", flags);
992 /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
993 *(LPDWORD)ptr = 0; /* FIXME ?? */
996 FIXME("Unsupported flag=%ld\n", flags);
1003 /**************************************************************************
1004 * widMessage (MSACM.@)
1006 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1007 DWORD dwParam1, DWORD dwParam2)
1009 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1010 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1017 /* FIXME: Pretend this is supported */
1020 case WIDM_OPEN: return widOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2);
1021 case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser);
1023 case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1024 case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1025 case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2);
1026 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
1027 case WIDM_GETNUMDEVS: return 1;
1028 case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2);
1029 case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser);
1030 case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser);
1031 case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser);
1032 case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1033 /* known but not supported */
1034 case DRV_QUERYDEVICEINTERFACESIZE:
1035 case DRV_QUERYDEVICEINTERFACE:
1036 return MMSYSERR_NOTSUPPORTED;
1038 FIXME("unknown message %u!\n", wMsg);
1040 return MMSYSERR_NOTSUPPORTED;
1043 /*======================================================================*
1045 *======================================================================*/
1047 static struct WINE_WAVEMAP* oss = NULL;
1049 /**************************************************************************
1050 * WAVEMAP_drvOpen [internal]
1052 static DWORD WAVEMAP_drvOpen(LPSTR str)
1054 TRACE("(%p)\n", str);
1059 /* I know, this is ugly, but who cares... */
1060 oss = (struct WINE_WAVEMAP*)1;
1064 /**************************************************************************
1065 * WAVEMAP_drvClose [internal]
1067 static DWORD WAVEMAP_drvClose(DWORD dwDevID)
1069 TRACE("(%08lx)\n", dwDevID);
1078 /**************************************************************************
1079 * DriverProc (MSACM.@)
1081 LONG CALLBACK WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1082 DWORD dwParam1, DWORD dwParam2)
1084 TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1085 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1088 case DRV_LOAD: return 1;
1089 case DRV_FREE: return 1;
1090 case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1);
1091 case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID);
1092 case DRV_ENABLE: return 1;
1093 case DRV_DISABLE: return 1;
1094 case DRV_QUERYCONFIGURE: return 1;
1095 case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1;
1096 case DRV_INSTALL: return DRVCNF_RESTART;
1097 case DRV_REMOVE: return DRVCNF_RESTART;
1099 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);