1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1998 Patrik Stridvall
11 * + asynchronous conversion is not implemented
12 * + callback/notification
14 * + properly close ACM streams
20 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(msacm
)
28 static PWINE_ACMSTREAM
ACM_GetStream(HACMSTREAM has
)
30 return (PWINE_ACMSTREAM
)has
;
33 /***********************************************************************
34 * acmStreamClose (MSACM32.37)
36 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
41 TRACE("(0x%08x, %ld)\n", has
, fdwClose
);
43 if ((was
= ACM_GetStream(has
)) == NULL
) {
44 return MMSYSERR_INVALHANDLE
;
46 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CLOSE
, (DWORD
)&was
->drvInst
, 0);
47 if (ret
== MMSYSERR_NOERROR
) {
49 acmDriverClose(was
->hAcmDriver
, 0L);
50 HeapFree(MSACM_hHeap
, 0, was
);
52 TRACE("=> (%d)\n", ret
);
56 /***********************************************************************
57 * acmStreamConvert (MSACM32.38)
59 MMRESULT WINAPI
acmStreamConvert(HACMSTREAM has
, PACMSTREAMHEADER pash
,
63 MMRESULT ret
= MMSYSERR_NOERROR
;
64 PACMDRVSTREAMHEADER padsh
;
66 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwConvert
);
68 if ((was
= ACM_GetStream(has
)) == NULL
)
69 return MMSYSERR_INVALHANDLE
;
70 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
71 return MMSYSERR_INVALPARAM
;
73 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
74 return ACMERR_UNPREPARED
;
76 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
77 * size. some fields are private to msacm internals, and are exposed
78 * in ACMSTREAMHEADER in the dwReservedDriver array
80 padsh
= (PACMDRVSTREAMHEADER
)pash
;
82 /* check that pointers have not been modified */
83 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
84 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
85 padsh
->pbPreparedDst
!= padsh
->pbDst
||
86 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
87 return MMSYSERR_INVALPARAM
;
90 padsh
->fdwConvert
= fdwConvert
;
92 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CONVERT
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
93 if (ret
== MMSYSERR_NOERROR
) {
94 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
96 TRACE("=> (%d)\n", ret
);
100 /***********************************************************************
101 * acmStreamMessage (MSACM32.39)
103 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
106 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
107 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
108 return MMSYSERR_ERROR
;
111 /***********************************************************************
112 * acmStreamOpen (MSACM32.40)
114 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
, PWAVEFORMATEX pwfxSrc
,
115 PWAVEFORMATEX pwfxDst
, PWAVEFILTER pwfltr
, DWORD dwCallback
,
116 DWORD dwInstance
, DWORD fdwOpen
)
124 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
125 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
127 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
128 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
129 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
131 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
132 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
133 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
135 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
136 wfxSrcSize
= SIZEOF_WFX(pwfxSrc
);
137 wfxDstSize
= SIZEOF_WFX(pwfxDst
);
140 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+ ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
142 return MMSYSERR_NOMEM
;
144 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
145 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
146 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
147 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
148 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
150 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
151 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
153 was
->drvInst
.pwfltr
= NULL
;
155 was
->drvInst
.dwCallback
= dwCallback
;
156 was
->drvInst
.dwInstance
= dwInstance
;
157 was
->drvInst
.fdwOpen
= fdwOpen
;
158 was
->drvInst
.fdwDriver
= 0L;
159 was
->drvInst
.dwDriver
= 0L;
160 was
->drvInst
.has
= (HACMSTREAM
)was
;
163 if (!(wad
= MSACM_GetDriver(had
))) {
164 ret
= MMSYSERR_INVALPARAM
;
168 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
170 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
172 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
173 if (ret
!= MMSYSERR_NOERROR
)
176 PWINE_ACMDRIVERID wadi
;
178 ret
= ACMERR_NOTPOSSIBLE
;
179 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
180 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
181 if (ret
== MMSYSERR_NOERROR
) {
182 if ((wad
= MSACM_GetDriver(had
)) != 0) {
183 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
185 was
->hAcmDriver
= had
;
187 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
188 if (ret
== MMSYSERR_NOERROR
) {
189 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
190 acmDriverClose(had
, 0L);
195 /* no match, close this acm driver and try next one */
196 acmDriverClose(had
, 0L);
199 if (ret
!= MMSYSERR_NOERROR
) {
200 ret
= ACMERR_NOTPOSSIBLE
;
204 ret
= MMSYSERR_NOERROR
;
205 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
207 *phas
= (HACMSTREAM
)was
;
208 TRACE("=> (%d)\n", ret
);
213 *phas
= (HACMSTREAM
)0;
214 HeapFree(MSACM_hHeap
, 0, was
);
215 TRACE("=> (%d)\n", ret
);
220 /***********************************************************************
221 * acmStreamPrepareHeader (MSACM32.41)
223 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
227 MMRESULT ret
= MMSYSERR_NOERROR
;
228 PACMDRVSTREAMHEADER padsh
;
230 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwPrepare
);
232 if ((was
= ACM_GetStream(has
)) == NULL
)
233 return MMSYSERR_INVALHANDLE
;
234 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
235 return MMSYSERR_INVALPARAM
;
237 ret
= MMSYSERR_INVALFLAG
;
239 if (pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_DONE
)
240 return MMSYSERR_NOERROR
;
242 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
243 * size. some fields are private to msacm internals, and are exposed
244 * in ACMSTREAMHEADER in the dwReservedDriver array
246 padsh
= (PACMDRVSTREAMHEADER
)pash
;
248 padsh
->fdwConvert
= fdwPrepare
;
249 padsh
->padshNext
= NULL
;
250 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
252 padsh
->fdwPrepared
= 0;
253 padsh
->dwPrepared
= 0;
254 padsh
->pbPreparedSrc
= 0;
255 padsh
->cbPreparedSrcLength
= 0;
256 padsh
->pbPreparedDst
= 0;
257 padsh
->cbPreparedDstLength
= 0;
259 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_PREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
260 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
261 ret
= MMSYSERR_NOERROR
;
262 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
);
263 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
264 padsh
->fdwPrepared
= padsh
->fdwStatus
;
265 padsh
->dwPrepared
= 0;
266 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
267 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
268 padsh
->pbPreparedDst
= padsh
->pbDst
;
269 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
271 padsh
->fdwPrepared
= 0;
272 padsh
->dwPrepared
= 0;
273 padsh
->pbPreparedSrc
= 0;
274 padsh
->cbPreparedSrcLength
= 0;
275 padsh
->pbPreparedDst
= 0;
276 padsh
->cbPreparedDstLength
= 0;
278 TRACE("=> (%d)\n", ret
);
282 /***********************************************************************
283 * acmStreamReset (MSACM32.42)
285 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
288 MMRESULT ret
= MMSYSERR_NOERROR
;
290 TRACE("(0x%08x, %ld)\n", has
, fdwReset
);
293 ret
= MMSYSERR_INVALFLAG
;
294 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
295 return MMSYSERR_INVALHANDLE
;
296 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
297 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_RESET
, (DWORD
)&was
->drvInst
, 0);
299 TRACE("=> (%d)\n", ret
);
303 /***********************************************************************
304 * acmStreamSize (MSACM32.43)
306 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
307 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
310 ACMDRVSTREAMSIZE adss
;
313 TRACE("(0x%08x, %ld, %p, %ld)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
315 if ((was
= ACM_GetStream(has
)) == NULL
) {
316 return MMSYSERR_INVALHANDLE
;
318 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
319 return MMSYSERR_INVALFLAG
;
322 *pdwOutputBytes
= 0L;
324 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
325 case ACM_STREAMSIZEF_DESTINATION
:
326 adss
.cbDstLength
= cbInput
;
327 adss
.cbSrcLength
= 0;
329 case ACM_STREAMSIZEF_SOURCE
:
330 adss
.cbSrcLength
= cbInput
;
331 adss
.cbDstLength
= 0;
334 return MMSYSERR_INVALFLAG
;
337 adss
.cbStruct
= sizeof(adss
);
338 adss
.fdwSize
= fdwSize
;
339 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_SIZE
,
340 (DWORD
)&was
->drvInst
, (DWORD
)&adss
);
341 if (ret
== MMSYSERR_NOERROR
) {
342 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
343 case ACM_STREAMSIZEF_DESTINATION
:
344 *pdwOutputBytes
= adss
.cbSrcLength
;
346 case ACM_STREAMSIZEF_SOURCE
:
347 *pdwOutputBytes
= adss
.cbDstLength
;
351 TRACE("=> (%d) [%lu]\n", ret
, *pdwOutputBytes
);
355 /***********************************************************************
356 * acmStreamUnprepareHeader (MSACM32.44)
358 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
362 MMRESULT ret
= MMSYSERR_NOERROR
;
363 PACMDRVSTREAMHEADER padsh
;
365 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwUnprepare
);
367 if ((was
= ACM_GetStream(has
)) == NULL
)
368 return MMSYSERR_INVALHANDLE
;
369 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
370 return MMSYSERR_INVALPARAM
;
372 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
373 return ACMERR_UNPREPARED
;
375 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
376 * size. some fields are private to msacm internals, and are exposed
377 * in ACMSTREAMHEADER in the dwReservedDriver array
379 padsh
= (PACMDRVSTREAMHEADER
)pash
;
381 /* check that pointers have not been modified */
382 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
383 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
384 padsh
->pbPreparedDst
!= padsh
->pbDst
||
385 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
386 return MMSYSERR_INVALPARAM
;
389 padsh
->fdwConvert
= fdwUnprepare
;
391 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_UNPREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
392 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
393 ret
= MMSYSERR_NOERROR
;
394 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
396 TRACE("=> (%d)\n", ret
);