1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1998 Patrik Stridvall
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * + asynchronous conversion is not implemented
26 * + callback/notification
28 * + properly close ACM streams
36 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msacm
);
45 static PWINE_ACMSTREAM
ACM_GetStream(HACMSTREAM has
)
47 return (PWINE_ACMSTREAM
)has
;
50 /***********************************************************************
51 * acmStreamClose (MSACM32.@)
53 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
58 TRACE("(%p, %ld)\n", has
, fdwClose
);
60 if ((was
= ACM_GetStream(has
)) == NULL
) {
61 return MMSYSERR_INVALHANDLE
;
63 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CLOSE
, (DWORD
)&was
->drvInst
, 0);
64 if (ret
== MMSYSERR_NOERROR
) {
66 acmDriverClose(was
->hAcmDriver
, 0L);
67 HeapFree(MSACM_hHeap
, 0, was
);
69 TRACE("=> (%d)\n", ret
);
73 /***********************************************************************
74 * acmStreamConvert (MSACM32.@)
76 MMRESULT WINAPI
acmStreamConvert(HACMSTREAM has
, PACMSTREAMHEADER pash
,
80 MMRESULT ret
= MMSYSERR_NOERROR
;
81 PACMDRVSTREAMHEADER padsh
;
83 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwConvert
);
85 if ((was
= ACM_GetStream(has
)) == NULL
)
86 return MMSYSERR_INVALHANDLE
;
87 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
88 return MMSYSERR_INVALPARAM
;
90 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
91 return ACMERR_UNPREPARED
;
93 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
94 * size. some fields are private to msacm internals, and are exposed
95 * in ACMSTREAMHEADER in the dwReservedDriver array
97 padsh
= (PACMDRVSTREAMHEADER
)pash
;
99 /* check that pointers have not been modified */
100 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
101 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
102 padsh
->pbPreparedDst
!= padsh
->pbDst
||
103 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
104 return MMSYSERR_INVALPARAM
;
107 padsh
->fdwConvert
= fdwConvert
;
109 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CONVERT
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
110 if (ret
== MMSYSERR_NOERROR
) {
111 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
113 TRACE("=> (%d)\n", ret
);
117 /***********************************************************************
118 * acmStreamMessage (MSACM32.@)
120 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
123 FIXME("(%p, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
124 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
125 return MMSYSERR_ERROR
;
128 /***********************************************************************
129 * acmStreamOpen (MSACM32.@)
131 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
, PWAVEFORMATEX pwfxSrc
,
132 PWAVEFORMATEX pwfxDst
, PWAVEFILTER pwfltr
, DWORD dwCallback
,
133 DWORD dwInstance
, DWORD fdwOpen
)
141 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n",
142 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
144 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
145 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
146 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
148 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
149 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
150 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
152 /* (WS) In query mode, phas should be NULL. If it is not, then instead
153 * of returning an error we are making sure it is NULL, preventing some
154 * applications that pass garbage for phas from crashing.
156 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) phas
= NULL
;
158 if (pwfltr
&& (pwfxSrc
->wFormatTag
!= pwfxDst
->wFormatTag
)) return MMSYSERR_INVALPARAM
;
160 wfxSrcSize
= wfxDstSize
= sizeof(WAVEFORMATEX
);
161 if (pwfxSrc
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxSrcSize
+= pwfxSrc
->cbSize
;
162 if (pwfxDst
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxDstSize
+= pwfxDst
->cbSize
;
164 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+
165 ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
167 return MMSYSERR_NOMEM
;
169 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
170 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
171 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
172 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
173 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
175 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
176 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
178 was
->drvInst
.pwfltr
= NULL
;
180 was
->drvInst
.dwCallback
= dwCallback
;
181 was
->drvInst
.dwInstance
= dwInstance
;
182 was
->drvInst
.fdwOpen
= fdwOpen
;
183 was
->drvInst
.fdwDriver
= 0L;
184 was
->drvInst
.dwDriver
= 0L;
185 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
186 was
->drvInst
.has
= 0L;
189 if (!(wad
= MSACM_GetDriver(had
))) {
190 ret
= MMSYSERR_INVALPARAM
;
194 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
195 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
197 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
199 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
200 if (ret
!= MMSYSERR_NOERROR
)
203 PWINE_ACMDRIVERID wadi
;
205 ret
= ACMERR_NOTPOSSIBLE
;
206 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
207 if ((wadi
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ||
208 !MSACM_FindFormatTagInCache(wadi
, pwfxSrc
->wFormatTag
, NULL
) ||
209 !MSACM_FindFormatTagInCache(wadi
, pwfxDst
->wFormatTag
, NULL
))
211 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
212 if (ret
!= MMSYSERR_NOERROR
)
214 if ((wad
= MSACM_GetDriver(had
)) != 0) {
215 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
216 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
218 was
->hAcmDriver
= had
;
220 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
221 TRACE("%s => %08x\n", debugstr_w(wadi
->pszDriverAlias
), ret
);
222 if (ret
== MMSYSERR_NOERROR
) {
223 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
224 acmDriverClose(had
, 0L);
229 /* no match, close this acm driver and try next one */
230 acmDriverClose(had
, 0L);
232 if (ret
!= MMSYSERR_NOERROR
) {
233 ret
= ACMERR_NOTPOSSIBLE
;
237 ret
= MMSYSERR_NOERROR
;
238 was
->drvInst
.has
= (HACMSTREAM
)was
;
239 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
241 *phas
= (HACMSTREAM
)was
;
242 TRACE("=> (%d)\n", ret
);
248 HeapFree(MSACM_hHeap
, 0, was
);
249 TRACE("=> (%d)\n", ret
);
254 /***********************************************************************
255 * acmStreamPrepareHeader (MSACM32.@)
257 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
261 MMRESULT ret
= MMSYSERR_NOERROR
;
262 PACMDRVSTREAMHEADER padsh
;
264 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwPrepare
);
266 if ((was
= ACM_GetStream(has
)) == NULL
)
267 return MMSYSERR_INVALHANDLE
;
268 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
269 return MMSYSERR_INVALPARAM
;
271 ret
= MMSYSERR_INVALFLAG
;
273 if (pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_DONE
)
274 return MMSYSERR_NOERROR
;
276 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
277 * size. some fields are private to msacm internals, and are exposed
278 * in ACMSTREAMHEADER in the dwReservedDriver array
280 padsh
= (PACMDRVSTREAMHEADER
)pash
;
282 padsh
->fdwConvert
= fdwPrepare
;
283 padsh
->padshNext
= NULL
;
284 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
286 padsh
->fdwPrepared
= 0;
287 padsh
->dwPrepared
= 0;
288 padsh
->pbPreparedSrc
= 0;
289 padsh
->cbPreparedSrcLength
= 0;
290 padsh
->pbPreparedDst
= 0;
291 padsh
->cbPreparedDstLength
= 0;
293 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_PREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
294 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
295 ret
= MMSYSERR_NOERROR
;
296 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
);
297 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
298 padsh
->fdwPrepared
= padsh
->fdwStatus
;
299 padsh
->dwPrepared
= 0;
300 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
301 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
302 padsh
->pbPreparedDst
= padsh
->pbDst
;
303 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
305 padsh
->fdwPrepared
= 0;
306 padsh
->dwPrepared
= 0;
307 padsh
->pbPreparedSrc
= 0;
308 padsh
->cbPreparedSrcLength
= 0;
309 padsh
->pbPreparedDst
= 0;
310 padsh
->cbPreparedDstLength
= 0;
312 TRACE("=> (%d)\n", ret
);
316 /***********************************************************************
317 * acmStreamReset (MSACM32.@)
319 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
322 MMRESULT ret
= MMSYSERR_NOERROR
;
324 TRACE("(%p, %ld)\n", has
, fdwReset
);
327 ret
= MMSYSERR_INVALFLAG
;
328 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
329 return MMSYSERR_INVALHANDLE
;
330 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
331 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_RESET
, (DWORD
)&was
->drvInst
, 0);
333 TRACE("=> (%d)\n", ret
);
337 /***********************************************************************
338 * acmStreamSize (MSACM32.@)
340 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
341 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
344 ACMDRVSTREAMSIZE adss
;
347 TRACE("(%p, %ld, %p, %ld)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
349 if ((was
= ACM_GetStream(has
)) == NULL
) {
350 return MMSYSERR_INVALHANDLE
;
352 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
353 return MMSYSERR_INVALFLAG
;
356 *pdwOutputBytes
= 0L;
358 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
359 case ACM_STREAMSIZEF_DESTINATION
:
360 adss
.cbDstLength
= cbInput
;
361 adss
.cbSrcLength
= 0;
363 case ACM_STREAMSIZEF_SOURCE
:
364 adss
.cbSrcLength
= cbInput
;
365 adss
.cbDstLength
= 0;
368 return MMSYSERR_INVALFLAG
;
371 adss
.cbStruct
= sizeof(adss
);
372 adss
.fdwSize
= fdwSize
;
373 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_SIZE
,
374 (DWORD
)&was
->drvInst
, (DWORD
)&adss
);
375 if (ret
== MMSYSERR_NOERROR
) {
376 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
377 case ACM_STREAMSIZEF_DESTINATION
:
378 *pdwOutputBytes
= adss
.cbSrcLength
;
380 case ACM_STREAMSIZEF_SOURCE
:
381 *pdwOutputBytes
= adss
.cbDstLength
;
385 TRACE("=> (%d) [%lu]\n", ret
, *pdwOutputBytes
);
389 /***********************************************************************
390 * acmStreamUnprepareHeader (MSACM32.@)
392 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
396 MMRESULT ret
= MMSYSERR_NOERROR
;
397 PACMDRVSTREAMHEADER padsh
;
399 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwUnprepare
);
401 if ((was
= ACM_GetStream(has
)) == NULL
)
402 return MMSYSERR_INVALHANDLE
;
403 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
))
404 return MMSYSERR_INVALPARAM
;
406 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
))
407 return ACMERR_UNPREPARED
;
409 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
410 * size. some fields are private to msacm internals, and are exposed
411 * in ACMSTREAMHEADER in the dwReservedDriver array
413 padsh
= (PACMDRVSTREAMHEADER
)pash
;
415 /* check that pointers have not been modified */
416 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
417 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
418 padsh
->pbPreparedDst
!= padsh
->pbDst
||
419 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
420 return MMSYSERR_INVALPARAM
;
423 padsh
->fdwConvert
= fdwUnprepare
;
425 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_UNPREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
426 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
427 ret
= MMSYSERR_NOERROR
;
428 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
430 TRACE("=> (%d)\n", ret
);