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
33 static PWINE_ACMSTREAM
ACM_GetStream(HACMSTREAM has
)
37 return (PWINE_ACMSTREAM
)has
;
40 static BOOL
ACM_ValidatePointers(PACMDRVSTREAMHEADER padsh
)
42 /* check that pointers have not been modified */
43 return !(padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
44 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
45 padsh
->pbPreparedDst
!= padsh
->pbDst
||
46 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
);
49 /***********************************************************************
50 * acmStreamClose (MSACM32.@)
52 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
57 TRACE("(%p, %d)\n", has
, fdwClose
);
59 if ((was
= ACM_GetStream(has
)) == NULL
) {
60 WARN("invalid handle\n");
61 return MMSYSERR_INVALHANDLE
;
63 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_CLOSE
, (LPARAM
)&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, %d)\n", has
, pash
, fdwConvert
);
85 if ((was
= ACM_GetStream(has
)) == NULL
) {
86 WARN("invalid handle\n");
87 return MMSYSERR_INVALHANDLE
;
89 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
90 WARN("invalid parameter\n");
91 return MMSYSERR_INVALPARAM
;
93 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
94 WARN("unprepared header\n");
95 return ACMERR_UNPREPARED
;
98 pash
->cbSrcLengthUsed
= 0;
99 pash
->cbDstLengthUsed
= 0;
101 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
102 * size. some fields are private to msacm internals, and are exposed
103 * in ACMSTREAMHEADER in the dwReservedDriver array
105 padsh
= (PACMDRVSTREAMHEADER
)pash
;
107 if (!ACM_ValidatePointers(padsh
)) {
108 WARN("invalid parameter\n");
109 return MMSYSERR_INVALPARAM
;
112 padsh
->fdwConvert
= fdwConvert
;
114 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_CONVERT
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
115 if (ret
== MMSYSERR_NOERROR
) {
116 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
118 TRACE("=> (%d)\n", ret
);
122 /***********************************************************************
123 * acmStreamMessage (MSACM32.@)
125 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
128 FIXME("(%p, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
129 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
130 return MMSYSERR_ERROR
;
133 /***********************************************************************
134 * acmStreamOpen (MSACM32.@)
136 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
,
137 PWAVEFORMATEX pwfxSrc
, PWAVEFORMATEX pwfxDst
,
138 PWAVEFILTER pwfltr
, DWORD_PTR dwCallback
,
139 DWORD_PTR dwInstance
, DWORD fdwOpen
)
146 WAVEFORMATEX wfxSrc
, wfxDst
;
148 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %d)\n",
149 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
151 /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
152 * WAVEFORMATEX so don't use them directly when not sure */
153 if (pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
) {
154 memcpy(&wfxSrc
, pwfxSrc
, sizeof(PCMWAVEFORMAT
));
155 wfxSrc
.wBitsPerSample
= pwfxSrc
->wBitsPerSample
;
160 if (pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
) {
161 memcpy(&wfxDst
, pwfxDst
, sizeof(PCMWAVEFORMAT
));
162 wfxDst
.wBitsPerSample
= pwfxDst
->wBitsPerSample
;
167 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
168 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
169 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
171 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
172 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
173 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
175 /* (WS) In query mode, phas should be NULL. If it is not, then instead
176 * of returning an error we are making sure it is NULL, preventing some
177 * applications that pass garbage for phas from crashing.
179 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) phas
= NULL
;
181 if (pwfltr
&& (pwfxSrc
->wFormatTag
!= pwfxDst
->wFormatTag
)) {
182 WARN("invalid parameter\n");
183 return MMSYSERR_INVALPARAM
;
186 wfxSrcSize
= wfxDstSize
= sizeof(WAVEFORMATEX
);
187 if (pwfxSrc
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxSrcSize
+= pwfxSrc
->cbSize
;
188 if (pwfxDst
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxDstSize
+= pwfxDst
->cbSize
;
190 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+
191 ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
194 return MMSYSERR_NOMEM
;
197 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
198 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
199 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
200 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
201 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
203 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
204 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
206 was
->drvInst
.pwfltr
= NULL
;
208 was
->drvInst
.dwCallback
= dwCallback
;
209 was
->drvInst
.dwInstance
= dwInstance
;
210 was
->drvInst
.fdwOpen
= fdwOpen
;
211 was
->drvInst
.fdwDriver
= 0L;
212 was
->drvInst
.dwDriver
= 0L;
213 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
214 was
->drvInst
.has
= 0L;
217 if (!(wad
= MSACM_GetDriver(had
))) {
218 ret
= MMSYSERR_INVALPARAM
;
222 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
223 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
225 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
227 ret
= MSACM_Message((HACMDRIVER
)wad
, ACMDM_STREAM_OPEN
, (LPARAM
)&was
->drvInst
, 0L);
228 if (ret
!= MMSYSERR_NOERROR
)
231 PWINE_ACMDRIVERID wadi
;
233 ret
= ACMERR_NOTPOSSIBLE
;
234 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
235 if ((wadi
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ||
236 !MSACM_FindFormatTagInCache(wadi
, pwfxSrc
->wFormatTag
, NULL
) ||
237 !MSACM_FindFormatTagInCache(wadi
, pwfxDst
->wFormatTag
, NULL
))
239 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
240 if (ret
!= MMSYSERR_NOERROR
)
242 if ((wad
= MSACM_GetDriver(had
)) != 0) {
243 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
244 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
246 was
->hAcmDriver
= had
;
248 ret
= MSACM_Message((HACMDRIVER
)wad
, ACMDM_STREAM_OPEN
, (LPARAM
)&was
->drvInst
, 0L);
249 TRACE("%s => %08x\n", debugstr_w(wadi
->pszDriverAlias
), ret
);
250 if (ret
== MMSYSERR_NOERROR
) {
251 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
252 MSACM_Message((HACMDRIVER
)wad
, ACMDM_STREAM_CLOSE
, (LPARAM
)&was
->drvInst
, 0);
253 acmDriverClose(had
, 0L);
258 /* no match, close this acm driver and try next one */
259 acmDriverClose(had
, 0L);
261 if (ret
!= MMSYSERR_NOERROR
) {
262 ret
= ACMERR_NOTPOSSIBLE
;
266 ret
= MMSYSERR_NOERROR
;
267 was
->drvInst
.has
= (HACMSTREAM
)was
;
268 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
270 *phas
= (HACMSTREAM
)was
;
271 TRACE("=> (%d)\n", ret
);
277 HeapFree(MSACM_hHeap
, 0, was
);
278 TRACE("=> (%d)\n", ret
);
283 /***********************************************************************
284 * acmStreamPrepareHeader (MSACM32.@)
286 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
290 MMRESULT ret
= MMSYSERR_NOERROR
;
291 PACMDRVSTREAMHEADER padsh
;
293 TRACE("(%p, %p, %d)\n", has
, pash
, fdwPrepare
);
295 if ((was
= ACM_GetStream(has
)) == NULL
) {
296 WARN("invalid handle\n");
297 return MMSYSERR_INVALHANDLE
;
299 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
300 WARN("invalid parameter\n");
301 return MMSYSERR_INVALPARAM
;
304 WARN("invalid use of reserved parameter\n");
305 return MMSYSERR_INVALFLAG
;
307 if ((was
->drvInst
.pwfxSrc
->wFormatTag
== WAVE_FORMAT_ADPCM
||
308 was
->drvInst
.pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
) &&
309 pash
->cbSrcLength
< was
->drvInst
.pwfxSrc
->nBlockAlign
) {
310 WARN("source smaller than block align (%d < %d)\n",
311 pash
->cbSrcLength
, was
->drvInst
.pwfxSrc
->nBlockAlign
);
312 return pash
->cbSrcLength
? ACMERR_NOTPOSSIBLE
: MMSYSERR_INVALPARAM
;
315 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
316 * size. some fields are private to msacm internals, and are exposed
317 * in ACMSTREAMHEADER in the dwReservedDriver array
319 padsh
= (PACMDRVSTREAMHEADER
)pash
;
321 padsh
->fdwConvert
= fdwPrepare
;
322 padsh
->padshNext
= NULL
;
323 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
325 padsh
->fdwPrepared
= 0;
326 padsh
->dwPrepared
= 0;
327 padsh
->pbPreparedSrc
= 0;
328 padsh
->cbPreparedSrcLength
= 0;
329 padsh
->pbPreparedDst
= 0;
330 padsh
->cbPreparedDstLength
= 0;
332 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_PREPARE
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
333 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
334 ret
= MMSYSERR_NOERROR
;
335 padsh
->fdwStatus
&= ~ACMSTREAMHEADER_STATUSF_INQUEUE
;
336 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
337 padsh
->fdwPrepared
= padsh
->fdwStatus
;
338 padsh
->dwPrepared
= 0;
339 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
340 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
341 padsh
->pbPreparedDst
= padsh
->pbDst
;
342 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
344 padsh
->fdwPrepared
= 0;
345 padsh
->dwPrepared
= 0;
346 padsh
->pbPreparedSrc
= 0;
347 padsh
->cbPreparedSrcLength
= 0;
348 padsh
->pbPreparedDst
= 0;
349 padsh
->cbPreparedDstLength
= 0;
351 TRACE("=> (%d)\n", ret
);
355 /***********************************************************************
356 * acmStreamReset (MSACM32.@)
358 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
361 MMRESULT ret
= MMSYSERR_NOERROR
;
363 TRACE("(%p, %d)\n", has
, fdwReset
);
366 WARN("invalid flag\n");
367 ret
= MMSYSERR_INVALFLAG
;
368 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
369 WARN("invalid handle\n");
370 return MMSYSERR_INVALHANDLE
;
371 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
372 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_RESET
, (LPARAM
)&was
->drvInst
, 0);
374 TRACE("=> (%d)\n", ret
);
378 /***********************************************************************
379 * acmStreamSize (MSACM32.@)
381 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
382 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
385 ACMDRVSTREAMSIZE adss
;
388 TRACE("(%p, %d, %p, %d)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
390 if ((was
= ACM_GetStream(has
)) == NULL
) {
391 WARN("invalid handle\n");
392 return MMSYSERR_INVALHANDLE
;
394 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
395 WARN("invalid flag\n");
396 return MMSYSERR_INVALFLAG
;
399 *pdwOutputBytes
= 0L;
401 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
402 case ACM_STREAMSIZEF_DESTINATION
:
403 adss
.cbDstLength
= cbInput
;
404 adss
.cbSrcLength
= 0;
406 case ACM_STREAMSIZEF_SOURCE
:
407 adss
.cbSrcLength
= cbInput
;
408 adss
.cbDstLength
= 0;
411 WARN("invalid flag\n");
412 return MMSYSERR_INVALFLAG
;
415 adss
.cbStruct
= sizeof(adss
);
416 adss
.fdwSize
= fdwSize
;
417 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_SIZE
,
418 (LPARAM
)&was
->drvInst
, (LPARAM
)&adss
);
419 if (ret
== MMSYSERR_NOERROR
) {
420 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
421 case ACM_STREAMSIZEF_DESTINATION
:
422 *pdwOutputBytes
= adss
.cbSrcLength
;
424 case ACM_STREAMSIZEF_SOURCE
:
425 *pdwOutputBytes
= adss
.cbDstLength
;
429 TRACE("=> (%d) [%u]\n", ret
, *pdwOutputBytes
);
433 /***********************************************************************
434 * acmStreamUnprepareHeader (MSACM32.@)
436 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
440 MMRESULT ret
= MMSYSERR_NOERROR
;
441 PACMDRVSTREAMHEADER padsh
;
443 TRACE("(%p, %p, %d)\n", has
, pash
, fdwUnprepare
);
445 if ((was
= ACM_GetStream(has
)) == NULL
) {
446 WARN("invalid handle\n");
447 return MMSYSERR_INVALHANDLE
;
449 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
450 WARN("invalid parameter\n");
451 return MMSYSERR_INVALPARAM
;
453 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
454 WARN("unprepared header\n");
455 return ACMERR_UNPREPARED
;
458 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
459 * size. some fields are private to msacm internals, and are exposed
460 * in ACMSTREAMHEADER in the dwReservedDriver array
462 padsh
= (PACMDRVSTREAMHEADER
)pash
;
464 if (!ACM_ValidatePointers(padsh
)) {
465 WARN("invalid parameter\n");
466 return MMSYSERR_INVALPARAM
;
469 padsh
->fdwConvert
= fdwUnprepare
;
471 ret
= MSACM_Message((HACMDRIVER
)was
->pDrv
, ACMDM_STREAM_UNPREPARE
, (LPARAM
)&was
->drvInst
, (LPARAM
)padsh
);
472 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
473 ret
= MMSYSERR_NOERROR
;
474 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
476 TRACE("=> (%d)\n", ret
);