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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * + asynchronous conversion is not implemented
26 * + callback/notification
28 * + properly close ACM streams
31 #define WIN32_NO_STATUS
36 //#include "winbase.h"
37 //#include "winerror.h"
38 #include <wine/debug.h>
39 //#include "mmsystem.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(msacm
);
48 static PWINE_ACMSTREAM
ACM_GetStream(HACMSTREAM has
)
52 return (PWINE_ACMSTREAM
)has
;
55 /***********************************************************************
56 * acmStreamClose (MSACM32.@)
58 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
63 TRACE("(%p, %d)\n", has
, fdwClose
);
65 if ((was
= ACM_GetStream(has
)) == NULL
) {
66 WARN("invalid handle\n");
67 return MMSYSERR_INVALHANDLE
;
69 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_CLOSE
, (LPARAM
)&was
->drvInst
, 0);
70 if (ret
== MMSYSERR_NOERROR
) {
72 acmDriverClose(was
->hAcmDriver
, 0L);
73 HeapFree(MSACM_hHeap
, 0, was
);
75 TRACE("=> (%d)\n", ret
);
79 /***********************************************************************
80 * acmStreamConvert (MSACM32.@)
82 MMRESULT WINAPI
acmStreamConvert(HACMSTREAM has
, PACMSTREAMHEADER pash
,
86 MMRESULT ret
= MMSYSERR_NOERROR
;
87 PACMDRVSTREAMHEADER padsh
;
89 TRACE("(%p, %p, %d)\n", has
, pash
, fdwConvert
);
91 if ((was
= ACM_GetStream(has
)) == NULL
) {
92 WARN("invalid handle\n");
93 return MMSYSERR_INVALHANDLE
;
95 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
96 WARN("invalid parameter\n");
97 return MMSYSERR_INVALPARAM
;
99 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
100 WARN("unprepared header\n");
101 return ACMERR_UNPREPARED
;
104 pash
->cbSrcLengthUsed
= 0;
105 pash
->cbDstLengthUsed
= 0;
107 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
108 * size. some fields are private to msacm internals, and are exposed
109 * in ACMSTREAMHEADER in the dwReservedDriver array
111 padsh
= (PACMDRVSTREAMHEADER
)pash
;
113 /* check that pointers have not been modified */
114 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
115 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
116 padsh
->pbPreparedDst
!= padsh
->pbDst
||
117 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
118 WARN("invalid parameter\n");
119 return MMSYSERR_INVALPARAM
;
122 padsh
->fdwConvert
= fdwConvert
;
124 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_CONVERT
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
125 if (ret
== MMSYSERR_NOERROR
) {
126 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
128 TRACE("=> (%d)\n", ret
);
132 /***********************************************************************
133 * acmStreamMessage (MSACM32.@)
135 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
138 FIXME("(%p, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
139 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
140 return MMSYSERR_ERROR
;
143 /***********************************************************************
144 * acmStreamOpen (MSACM32.@)
146 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
,
147 PWAVEFORMATEX pwfxSrc
, PWAVEFORMATEX pwfxDst
,
148 PWAVEFILTER pwfltr
, DWORD_PTR dwCallback
,
149 DWORD_PTR dwInstance
, DWORD fdwOpen
)
156 WAVEFORMATEX wfxSrc
, wfxDst
;
158 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %d)\n",
159 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
161 /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
162 * WAVEFORMATEX so don't use them directly when not sure */
163 if (pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
) {
164 memcpy(&wfxSrc
, pwfxSrc
, sizeof(PCMWAVEFORMAT
));
165 wfxSrc
.wBitsPerSample
= pwfxSrc
->wBitsPerSample
;
170 if (pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
) {
171 memcpy(&wfxDst
, pwfxDst
, sizeof(PCMWAVEFORMAT
));
172 wfxDst
.wBitsPerSample
= pwfxDst
->wBitsPerSample
;
177 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
178 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
179 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
181 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
182 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
183 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
185 /* (WS) In query mode, phas should be NULL. If it is not, then instead
186 * of returning an error we are making sure it is NULL, preventing some
187 * applications that pass garbage for phas from crashing.
189 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) phas
= NULL
;
191 if (pwfltr
&& (pwfxSrc
->wFormatTag
!= pwfxDst
->wFormatTag
)) {
192 WARN("invalid parameter\n");
193 return MMSYSERR_INVALPARAM
;
196 wfxSrcSize
= wfxDstSize
= sizeof(WAVEFORMATEX
);
197 if (pwfxSrc
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxSrcSize
+= pwfxSrc
->cbSize
;
198 if (pwfxDst
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxDstSize
+= pwfxDst
->cbSize
;
200 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+
201 ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
204 return MMSYSERR_NOMEM
;
207 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
208 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
209 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
210 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
211 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
213 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
214 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
216 was
->drvInst
.pwfltr
= NULL
;
218 was
->drvInst
.dwCallback
= dwCallback
;
219 was
->drvInst
.dwInstance
= dwInstance
;
220 was
->drvInst
.fdwOpen
= fdwOpen
;
221 was
->drvInst
.fdwDriver
= 0L;
222 was
->drvInst
.dwDriver
= 0L;
223 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
224 was
->drvInst
.has
= 0L;
227 if (!(wad
= MSACM_GetDriver(had
))) {
228 ret
= MMSYSERR_INVALPARAM
;
232 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
233 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
235 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
237 ret
= MSACM_Message((HACMDRIVER
)wad
, ACMDM_STREAM_OPEN
, (LPARAM
)&was
->drvInst
, 0L);
238 if (ret
!= MMSYSERR_NOERROR
)
241 PWINE_ACMDRIVERID wadi
;
243 ret
= ACMERR_NOTPOSSIBLE
;
244 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
245 if ((wadi
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ||
246 !MSACM_FindFormatTagInCache(wadi
, pwfxSrc
->wFormatTag
, NULL
) ||
247 !MSACM_FindFormatTagInCache(wadi
, pwfxDst
->wFormatTag
, NULL
))
249 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
250 if (ret
!= MMSYSERR_NOERROR
)
252 if ((wad
= MSACM_GetDriver(had
)) != 0) {
253 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
254 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
256 was
->hAcmDriver
= had
;
258 ret
= MSACM_Message((HACMDRIVER
)wad
, ACMDM_STREAM_OPEN
, (LPARAM
)&was
->drvInst
, 0L);
259 TRACE("%s => %08x\n", debugstr_w(wadi
->pszDriverAlias
), ret
);
260 if (ret
== MMSYSERR_NOERROR
) {
261 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
262 acmDriverClose(had
, 0L);
267 /* no match, close this acm driver and try next one */
268 acmDriverClose(had
, 0L);
270 if (ret
!= MMSYSERR_NOERROR
) {
271 ret
= ACMERR_NOTPOSSIBLE
;
275 ret
= MMSYSERR_NOERROR
;
276 was
->drvInst
.has
= (HACMSTREAM
)was
;
277 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
279 *phas
= (HACMSTREAM
)was
;
280 TRACE("=> (%d)\n", ret
);
286 HeapFree(MSACM_hHeap
, 0, was
);
287 TRACE("=> (%d)\n", ret
);
292 /***********************************************************************
293 * acmStreamPrepareHeader (MSACM32.@)
295 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
299 MMRESULT ret
= MMSYSERR_NOERROR
;
300 PACMDRVSTREAMHEADER padsh
;
302 TRACE("(%p, %p, %d)\n", has
, pash
, fdwPrepare
);
304 if ((was
= ACM_GetStream(has
)) == NULL
) {
305 WARN("invalid handle\n");
306 return MMSYSERR_INVALHANDLE
;
308 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
309 WARN("invalid parameter\n");
310 return MMSYSERR_INVALPARAM
;
313 ret
= MMSYSERR_INVALFLAG
;
315 if (pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_DONE
)
316 return MMSYSERR_NOERROR
;
318 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
319 * size. some fields are private to msacm internals, and are exposed
320 * in ACMSTREAMHEADER in the dwReservedDriver array
322 padsh
= (PACMDRVSTREAMHEADER
)pash
;
324 padsh
->fdwConvert
= fdwPrepare
;
325 padsh
->padshNext
= NULL
;
326 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
328 padsh
->fdwPrepared
= 0;
329 padsh
->dwPrepared
= 0;
330 padsh
->pbPreparedSrc
= 0;
331 padsh
->cbPreparedSrcLength
= 0;
332 padsh
->pbPreparedDst
= 0;
333 padsh
->cbPreparedDstLength
= 0;
335 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_PREPARE
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
336 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
337 ret
= MMSYSERR_NOERROR
;
338 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
);
339 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
340 padsh
->fdwPrepared
= padsh
->fdwStatus
;
341 padsh
->dwPrepared
= 0;
342 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
343 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
344 padsh
->pbPreparedDst
= padsh
->pbDst
;
345 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
347 padsh
->fdwPrepared
= 0;
348 padsh
->dwPrepared
= 0;
349 padsh
->pbPreparedSrc
= 0;
350 padsh
->cbPreparedSrcLength
= 0;
351 padsh
->pbPreparedDst
= 0;
352 padsh
->cbPreparedDstLength
= 0;
354 TRACE("=> (%d)\n", ret
);
358 /***********************************************************************
359 * acmStreamReset (MSACM32.@)
361 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
364 MMRESULT ret
= MMSYSERR_NOERROR
;
366 TRACE("(%p, %d)\n", has
, fdwReset
);
369 WARN("invalid flag\n");
370 ret
= MMSYSERR_INVALFLAG
;
371 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
372 WARN("invalid handle\n");
373 return MMSYSERR_INVALHANDLE
;
374 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
375 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_RESET
, (LPARAM
)&was
->drvInst
, 0);
377 TRACE("=> (%d)\n", ret
);
381 /***********************************************************************
382 * acmStreamSize (MSACM32.@)
384 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
385 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
388 ACMDRVSTREAMSIZE adss
;
391 TRACE("(%p, %d, %p, %d)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
393 if ((was
= ACM_GetStream(has
)) == NULL
) {
394 WARN("invalid handle\n");
395 return MMSYSERR_INVALHANDLE
;
397 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
398 WARN("invalid flag\n");
399 return MMSYSERR_INVALFLAG
;
402 *pdwOutputBytes
= 0L;
404 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
405 case ACM_STREAMSIZEF_DESTINATION
:
406 adss
.cbDstLength
= cbInput
;
407 adss
.cbSrcLength
= 0;
409 case ACM_STREAMSIZEF_SOURCE
:
410 adss
.cbSrcLength
= cbInput
;
411 adss
.cbDstLength
= 0;
414 WARN("invalid flag\n");
415 return MMSYSERR_INVALFLAG
;
418 adss
.cbStruct
= sizeof(adss
);
419 adss
.fdwSize
= fdwSize
;
420 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_SIZE
,
421 (LPARAM
)&was
->drvInst
, (LPARAM
)&adss
);
422 if (ret
== MMSYSERR_NOERROR
) {
423 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
424 case ACM_STREAMSIZEF_DESTINATION
:
425 *pdwOutputBytes
= adss
.cbSrcLength
;
427 case ACM_STREAMSIZEF_SOURCE
:
428 *pdwOutputBytes
= adss
.cbDstLength
;
432 TRACE("=> (%d) [%u]\n", ret
, *pdwOutputBytes
);
436 /***********************************************************************
437 * acmStreamUnprepareHeader (MSACM32.@)
439 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
443 MMRESULT ret
= MMSYSERR_NOERROR
;
444 PACMDRVSTREAMHEADER padsh
;
446 TRACE("(%p, %p, %d)\n", has
, pash
, fdwUnprepare
);
448 if ((was
= ACM_GetStream(has
)) == NULL
) {
449 WARN("invalid handle\n");
450 return MMSYSERR_INVALHANDLE
;
452 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
453 WARN("invalid parameter\n");
454 return MMSYSERR_INVALPARAM
;
456 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
457 WARN("unprepared header\n");
458 return ACMERR_UNPREPARED
;
461 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
462 * size. some fields are private to msacm internals, and are exposed
463 * in ACMSTREAMHEADER in the dwReservedDriver array
465 padsh
= (PACMDRVSTREAMHEADER
)pash
;
467 /* check that pointers have not been modified */
468 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
469 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
470 padsh
->pbPreparedDst
!= padsh
->pbDst
||
471 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
472 WARN("invalid parameter\n");
473 return MMSYSERR_INVALPARAM
;
476 padsh
->fdwConvert
= fdwUnprepare
;
478 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_UNPREPARE
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
479 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
480 ret
= MMSYSERR_NOERROR
;
481 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
483 TRACE("=> (%d)\n", ret
);