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
21 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(msacm
);
29 static PWINE_ACMSTREAM
ACM_GetStream(HACMSTREAM has
)
31 return (PWINE_ACMSTREAM
)has
;
34 /***********************************************************************
35 * acmStreamClose (MSACM32.@)
37 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
42 TRACE("(0x%08x, %ld)\n", has
, fdwClose
);
44 if ((was
= ACM_GetStream(has
)) == NULL
) {
45 return MMSYSERR_INVALHANDLE
;
47 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CLOSE
, (DWORD
)&was
->drvInst
, 0);
48 if (ret
== MMSYSERR_NOERROR
) {
50 acmDriverClose(was
->hAcmDriver
, 0L);
51 HeapFree(MSACM_hHeap
, 0, was
);
53 TRACE("=> (%d)\n", ret
);
57 /***********************************************************************
58 * acmStreamConvert (MSACM32.@)
60 MMRESULT WINAPI
acmStreamConvert(HACMSTREAM has
, PACMSTREAMHEADER pash
,
64 MMRESULT ret
= MMSYSERR_NOERROR
;
65 PACMDRVSTREAMHEADER padsh
;
67 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwConvert
);
69 if ((was
= ACM_GetStream(has
)) == NULL
)
70 return MMSYSERR_INVALHANDLE
;
71 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
72 return MMSYSERR_INVALPARAM
;
74 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
75 return ACMERR_UNPREPARED
;
77 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
78 * size. some fields are private to msacm internals, and are exposed
79 * in ACMSTREAMHEADER in the dwReservedDriver array
81 padsh
= (PACMDRVSTREAMHEADER
)pash
;
83 /* check that pointers have not been modified */
84 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
85 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
86 padsh
->pbPreparedDst
!= padsh
->pbDst
||
87 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
88 return MMSYSERR_INVALPARAM
;
91 padsh
->fdwConvert
= fdwConvert
;
93 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CONVERT
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
94 if (ret
== MMSYSERR_NOERROR
) {
95 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
97 TRACE("=> (%d)\n", ret
);
101 /***********************************************************************
102 * acmStreamMessage (MSACM32.@)
104 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
107 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
108 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
109 return MMSYSERR_ERROR
;
112 /***********************************************************************
113 * acmStreamOpen (MSACM32.@)
115 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
, PWAVEFORMATEX pwfxSrc
,
116 PWAVEFORMATEX pwfxDst
, PWAVEFILTER pwfltr
, DWORD dwCallback
,
117 DWORD dwInstance
, DWORD fdwOpen
)
125 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
126 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
128 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
129 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
130 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
132 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
133 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
134 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
136 if ((fdwOpen
& ACM_STREAMOPENF_QUERY
) && phas
) return MMSYSERR_INVALPARAM
;
137 if (pwfltr
&& (pwfxSrc
->wFormatTag
!= pwfxDst
->wFormatTag
)) return MMSYSERR_INVALPARAM
;
139 wfxSrcSize
= wfxDstSize
= sizeof(WAVEFORMATEX
);
140 if (pwfxSrc
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxSrcSize
+= pwfxSrc
->cbSize
;
141 if (pwfxDst
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxDstSize
+= pwfxDst
->cbSize
;
143 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+
144 ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
146 return MMSYSERR_NOMEM
;
148 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
149 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
150 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
151 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
152 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
154 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
155 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
157 was
->drvInst
.pwfltr
= NULL
;
159 was
->drvInst
.dwCallback
= dwCallback
;
160 was
->drvInst
.dwInstance
= dwInstance
;
161 was
->drvInst
.fdwOpen
= fdwOpen
;
162 was
->drvInst
.fdwDriver
= 0L;
163 was
->drvInst
.dwDriver
= 0L;
164 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
165 was
->drvInst
.has
= 0L;
168 if (!(wad
= MSACM_GetDriver(had
))) {
169 ret
= MMSYSERR_INVALPARAM
;
173 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
174 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
176 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
178 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
179 if (ret
!= MMSYSERR_NOERROR
)
182 PWINE_ACMDRIVERID wadi
;
184 ret
= ACMERR_NOTPOSSIBLE
;
185 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
186 if ((wadi
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ||
187 !MSACM_FindFormatTagInCache(wadi
, pwfxSrc
->wFormatTag
, NULL
) ||
188 !MSACM_FindFormatTagInCache(wadi
, pwfxDst
->wFormatTag
, NULL
))
190 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
191 if (ret
!= MMSYSERR_NOERROR
)
193 if ((wad
= MSACM_GetDriver(had
)) != 0) {
194 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
195 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
197 was
->hAcmDriver
= had
;
199 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
200 TRACE("%s => %08x\n", wadi
->pszDriverAlias
, ret
);
201 if (ret
== MMSYSERR_NOERROR
) {
202 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
203 acmDriverClose(had
, 0L);
208 /* no match, close this acm driver and try next one */
209 acmDriverClose(had
, 0L);
211 if (ret
!= MMSYSERR_NOERROR
) {
212 ret
= ACMERR_NOTPOSSIBLE
;
216 ret
= MMSYSERR_NOERROR
;
217 was
->drvInst
.has
= (HACMSTREAM
)was
;
218 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
220 *phas
= (HACMSTREAM
)was
;
221 TRACE("=> (%d)\n", ret
);
226 *phas
= (HACMSTREAM
)0;
227 HeapFree(MSACM_hHeap
, 0, was
);
228 TRACE("=> (%d)\n", ret
);
233 /***********************************************************************
234 * acmStreamPrepareHeader (MSACM32.@)
236 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
240 MMRESULT ret
= MMSYSERR_NOERROR
;
241 PACMDRVSTREAMHEADER padsh
;
243 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwPrepare
);
245 if ((was
= ACM_GetStream(has
)) == NULL
)
246 return MMSYSERR_INVALHANDLE
;
247 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
248 return MMSYSERR_INVALPARAM
;
250 ret
= MMSYSERR_INVALFLAG
;
252 if (pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_DONE
)
253 return MMSYSERR_NOERROR
;
255 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
256 * size. some fields are private to msacm internals, and are exposed
257 * in ACMSTREAMHEADER in the dwReservedDriver array
259 padsh
= (PACMDRVSTREAMHEADER
)pash
;
261 padsh
->fdwConvert
= fdwPrepare
;
262 padsh
->padshNext
= NULL
;
263 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
265 padsh
->fdwPrepared
= 0;
266 padsh
->dwPrepared
= 0;
267 padsh
->pbPreparedSrc
= 0;
268 padsh
->cbPreparedSrcLength
= 0;
269 padsh
->pbPreparedDst
= 0;
270 padsh
->cbPreparedDstLength
= 0;
272 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_PREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
273 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
274 ret
= MMSYSERR_NOERROR
;
275 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
);
276 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
277 padsh
->fdwPrepared
= padsh
->fdwStatus
;
278 padsh
->dwPrepared
= 0;
279 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
280 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
281 padsh
->pbPreparedDst
= padsh
->pbDst
;
282 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
284 padsh
->fdwPrepared
= 0;
285 padsh
->dwPrepared
= 0;
286 padsh
->pbPreparedSrc
= 0;
287 padsh
->cbPreparedSrcLength
= 0;
288 padsh
->pbPreparedDst
= 0;
289 padsh
->cbPreparedDstLength
= 0;
291 TRACE("=> (%d)\n", ret
);
295 /***********************************************************************
296 * acmStreamReset (MSACM32.@)
298 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
301 MMRESULT ret
= MMSYSERR_NOERROR
;
303 TRACE("(0x%08x, %ld)\n", has
, fdwReset
);
306 ret
= MMSYSERR_INVALFLAG
;
307 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
308 return MMSYSERR_INVALHANDLE
;
309 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
310 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_RESET
, (DWORD
)&was
->drvInst
, 0);
312 TRACE("=> (%d)\n", ret
);
316 /***********************************************************************
317 * acmStreamSize (MSACM32.@)
319 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
320 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
323 ACMDRVSTREAMSIZE adss
;
326 TRACE("(0x%08x, %ld, %p, %ld)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
328 if ((was
= ACM_GetStream(has
)) == NULL
) {
329 return MMSYSERR_INVALHANDLE
;
331 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
332 return MMSYSERR_INVALFLAG
;
335 *pdwOutputBytes
= 0L;
337 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
338 case ACM_STREAMSIZEF_DESTINATION
:
339 adss
.cbDstLength
= cbInput
;
340 adss
.cbSrcLength
= 0;
342 case ACM_STREAMSIZEF_SOURCE
:
343 adss
.cbSrcLength
= cbInput
;
344 adss
.cbDstLength
= 0;
347 return MMSYSERR_INVALFLAG
;
350 adss
.cbStruct
= sizeof(adss
);
351 adss
.fdwSize
= fdwSize
;
352 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_SIZE
,
353 (DWORD
)&was
->drvInst
, (DWORD
)&adss
);
354 if (ret
== MMSYSERR_NOERROR
) {
355 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
356 case ACM_STREAMSIZEF_DESTINATION
:
357 *pdwOutputBytes
= adss
.cbSrcLength
;
359 case ACM_STREAMSIZEF_SOURCE
:
360 *pdwOutputBytes
= adss
.cbDstLength
;
364 TRACE("=> (%d) [%lu]\n", ret
, *pdwOutputBytes
);
368 /***********************************************************************
369 * acmStreamUnprepareHeader (MSACM32.@)
371 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
375 MMRESULT ret
= MMSYSERR_NOERROR
;
376 PACMDRVSTREAMHEADER padsh
;
378 TRACE("(0x%08x, %p, %ld)\n", has
, pash
, fdwUnprepare
);
380 if ((was
= ACM_GetStream(has
)) == NULL
)
381 return MMSYSERR_INVALHANDLE
;
382 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
383 return MMSYSERR_INVALPARAM
;
385 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
386 return ACMERR_UNPREPARED
;
388 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
389 * size. some fields are private to msacm internals, and are exposed
390 * in ACMSTREAMHEADER in the dwReservedDriver array
392 padsh
= (PACMDRVSTREAMHEADER
)pash
;
394 /* check that pointers have not been modified */
395 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
396 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
397 padsh
->pbPreparedDst
!= padsh
->pbDst
||
398 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
399 return MMSYSERR_INVALPARAM
;
402 padsh
->fdwConvert
= fdwUnprepare
;
404 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_UNPREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
405 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
406 ret
= MMSYSERR_NOERROR
;
407 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
409 TRACE("=> (%d)\n", ret
);