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 && lpDesc
->lpFormat
->wFormatTag
== WAVE_FORMAT_PCM
) {
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
);