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
)
49 return (PWINE_ACMSTREAM
)has
;
52 /***********************************************************************
53 * acmStreamClose (MSACM32.@)
55 MMRESULT WINAPI
acmStreamClose(HACMSTREAM has
, DWORD fdwClose
)
60 TRACE("(%p, %ld)\n", has
, fdwClose
);
62 if ((was
= ACM_GetStream(has
)) == NULL
) {
63 WARN("invalid handle\n");
64 return MMSYSERR_INVALHANDLE
;
66 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CLOSE
, (DWORD
)&was
->drvInst
, 0);
67 if (ret
== MMSYSERR_NOERROR
) {
69 acmDriverClose(was
->hAcmDriver
, 0L);
70 HeapFree(MSACM_hHeap
, 0, was
);
72 TRACE("=> (%d)\n", ret
);
76 /***********************************************************************
77 * acmStreamConvert (MSACM32.@)
79 MMRESULT WINAPI
acmStreamConvert(HACMSTREAM has
, PACMSTREAMHEADER pash
,
83 MMRESULT ret
= MMSYSERR_NOERROR
;
84 PACMDRVSTREAMHEADER padsh
;
86 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwConvert
);
88 if ((was
= ACM_GetStream(has
)) == NULL
) {
89 WARN("invalid handle\n");
90 return MMSYSERR_INVALHANDLE
;
92 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
93 WARN("invalid parameter\n");
94 return MMSYSERR_INVALPARAM
;
96 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
97 WARN("unprepared header\n");
98 return ACMERR_UNPREPARED
;
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 /* check that pointers have not been modified */
108 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
109 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
110 padsh
->pbPreparedDst
!= padsh
->pbDst
||
111 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
112 WARN("invalid parameter\n");
113 return MMSYSERR_INVALPARAM
;
116 padsh
->fdwConvert
= fdwConvert
;
118 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_CONVERT
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
119 if (ret
== MMSYSERR_NOERROR
) {
120 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_DONE
;
122 TRACE("=> (%d)\n", ret
);
126 /***********************************************************************
127 * acmStreamMessage (MSACM32.@)
129 MMRESULT WINAPI
acmStreamMessage(HACMSTREAM has
, UINT uMsg
, LPARAM lParam1
,
132 FIXME("(%p, %u, %ld, %ld): stub\n", has
, uMsg
, lParam1
, lParam2
);
133 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
134 return MMSYSERR_ERROR
;
137 /***********************************************************************
138 * acmStreamOpen (MSACM32.@)
140 MMRESULT WINAPI
acmStreamOpen(PHACMSTREAM phas
, HACMDRIVER had
, PWAVEFORMATEX pwfxSrc
,
141 PWAVEFORMATEX pwfxDst
, PWAVEFILTER pwfltr
, DWORD dwCallback
,
142 DWORD dwInstance
, DWORD fdwOpen
)
149 WAVEFORMATEX wfxSrc
, wfxDst
;
151 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n",
152 phas
, had
, pwfxSrc
, pwfxDst
, pwfltr
, dwCallback
, dwInstance
, fdwOpen
);
154 /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
155 * WAVEFORMATEX so don't use them directly when not sure */
156 if (pwfxSrc
->wFormatTag
== WAVE_FORMAT_PCM
) {
157 memcpy(&wfxSrc
, pwfxSrc
, sizeof(PCMWAVEFORMAT
));
158 wfxSrc
.wBitsPerSample
= pwfxSrc
->wBitsPerSample
;
163 if (pwfxDst
->wFormatTag
== WAVE_FORMAT_PCM
) {
164 memcpy(&wfxDst
, pwfxDst
, sizeof(PCMWAVEFORMAT
));
165 wfxDst
.wBitsPerSample
= pwfxDst
->wBitsPerSample
;
170 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
171 pwfxSrc
->wFormatTag
, pwfxSrc
->nChannels
, pwfxSrc
->nSamplesPerSec
, pwfxSrc
->nAvgBytesPerSec
,
172 pwfxSrc
->nBlockAlign
, pwfxSrc
->wBitsPerSample
, pwfxSrc
->cbSize
);
174 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
175 pwfxDst
->wFormatTag
, pwfxDst
->nChannels
, pwfxDst
->nSamplesPerSec
, pwfxDst
->nAvgBytesPerSec
,
176 pwfxDst
->nBlockAlign
, pwfxDst
->wBitsPerSample
, pwfxDst
->cbSize
);
178 /* (WS) In query mode, phas should be NULL. If it is not, then instead
179 * of returning an error we are making sure it is NULL, preventing some
180 * applications that pass garbage for phas from crashing.
182 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) phas
= NULL
;
184 if (pwfltr
&& (pwfxSrc
->wFormatTag
!= pwfxDst
->wFormatTag
)) {
185 WARN("invalid parameter\n");
186 return MMSYSERR_INVALPARAM
;
189 wfxSrcSize
= wfxDstSize
= sizeof(WAVEFORMATEX
);
190 if (pwfxSrc
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxSrcSize
+= pwfxSrc
->cbSize
;
191 if (pwfxDst
->wFormatTag
!= WAVE_FORMAT_PCM
) wfxDstSize
+= pwfxDst
->cbSize
;
193 was
= HeapAlloc(MSACM_hHeap
, 0, sizeof(*was
) + wfxSrcSize
+ wfxDstSize
+
194 ((pwfltr
) ? sizeof(WAVEFILTER
) : 0));
197 return MMSYSERR_NOMEM
;
200 was
->drvInst
.cbStruct
= sizeof(was
->drvInst
);
201 was
->drvInst
.pwfxSrc
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
));
202 memcpy(was
->drvInst
.pwfxSrc
, pwfxSrc
, wfxSrcSize
);
203 was
->drvInst
.pwfxDst
= (PWAVEFORMATEX
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
);
204 memcpy(was
->drvInst
.pwfxDst
, pwfxDst
, wfxDstSize
);
206 was
->drvInst
.pwfltr
= (PWAVEFILTER
)((LPSTR
)was
+ sizeof(*was
) + wfxSrcSize
+ wfxDstSize
);
207 memcpy(was
->drvInst
.pwfltr
, pwfltr
, sizeof(WAVEFILTER
));
209 was
->drvInst
.pwfltr
= NULL
;
211 was
->drvInst
.dwCallback
= dwCallback
;
212 was
->drvInst
.dwInstance
= dwInstance
;
213 was
->drvInst
.fdwOpen
= fdwOpen
;
214 was
->drvInst
.fdwDriver
= 0L;
215 was
->drvInst
.dwDriver
= 0L;
216 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
217 was
->drvInst
.has
= 0L;
220 if (!(wad
= MSACM_GetDriver(had
))) {
221 ret
= MMSYSERR_INVALPARAM
;
225 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
226 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
228 was
->hAcmDriver
= 0; /* not to close it in acmStreamClose */
230 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
231 if (ret
!= MMSYSERR_NOERROR
)
234 PWINE_ACMDRIVERID wadi
;
236 ret
= ACMERR_NOTPOSSIBLE
;
237 for (wadi
= MSACM_pFirstACMDriverID
; wadi
; wadi
= wadi
->pNextACMDriverID
) {
238 if ((wadi
->fdwSupport
& ACMDRIVERDETAILS_SUPPORTF_DISABLED
) ||
239 !MSACM_FindFormatTagInCache(wadi
, pwfxSrc
->wFormatTag
, NULL
) ||
240 !MSACM_FindFormatTagInCache(wadi
, pwfxDst
->wFormatTag
, NULL
))
242 ret
= acmDriverOpen(&had
, (HACMDRIVERID
)wadi
, 0L);
243 if (ret
!= MMSYSERR_NOERROR
)
245 if ((wad
= MSACM_GetDriver(had
)) != 0) {
246 was
->obj
.dwType
= WINE_ACMOBJ_STREAM
;
247 was
->obj
.pACMDriverID
= wad
->obj
.pACMDriverID
;
249 was
->hAcmDriver
= had
;
251 ret
= SendDriverMessage(wad
->hDrvr
, ACMDM_STREAM_OPEN
, (DWORD
)&was
->drvInst
, 0L);
252 TRACE("%s => %08x\n", debugstr_w(wadi
->pszDriverAlias
), ret
);
253 if (ret
== MMSYSERR_NOERROR
) {
254 if (fdwOpen
& ACM_STREAMOPENF_QUERY
) {
255 acmDriverClose(had
, 0L);
260 /* no match, close this acm driver and try next one */
261 acmDriverClose(had
, 0L);
263 if (ret
!= MMSYSERR_NOERROR
) {
264 ret
= ACMERR_NOTPOSSIBLE
;
268 ret
= MMSYSERR_NOERROR
;
269 was
->drvInst
.has
= (HACMSTREAM
)was
;
270 if (!(fdwOpen
& ACM_STREAMOPENF_QUERY
)) {
272 *phas
= (HACMSTREAM
)was
;
273 TRACE("=> (%d)\n", ret
);
279 HeapFree(MSACM_hHeap
, 0, was
);
280 TRACE("=> (%d)\n", ret
);
285 /***********************************************************************
286 * acmStreamPrepareHeader (MSACM32.@)
288 MMRESULT WINAPI
acmStreamPrepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
292 MMRESULT ret
= MMSYSERR_NOERROR
;
293 PACMDRVSTREAMHEADER padsh
;
295 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwPrepare
);
297 if ((was
= ACM_GetStream(has
)) == NULL
) {
298 WARN("invalid handle\n");
299 return MMSYSERR_INVALHANDLE
;
301 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
302 WARN("invalid parameter\n");
303 return MMSYSERR_INVALPARAM
;
306 ret
= MMSYSERR_INVALFLAG
;
308 if (pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_DONE
)
309 return MMSYSERR_NOERROR
;
311 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
312 * size. some fields are private to msacm internals, and are exposed
313 * in ACMSTREAMHEADER in the dwReservedDriver array
315 padsh
= (PACMDRVSTREAMHEADER
)pash
;
317 padsh
->fdwConvert
= fdwPrepare
;
318 padsh
->padshNext
= NULL
;
319 padsh
->fdwDriver
= padsh
->dwDriver
= 0L;
321 padsh
->fdwPrepared
= 0;
322 padsh
->dwPrepared
= 0;
323 padsh
->pbPreparedSrc
= 0;
324 padsh
->cbPreparedSrcLength
= 0;
325 padsh
->pbPreparedDst
= 0;
326 padsh
->cbPreparedDstLength
= 0;
328 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_PREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
329 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
330 ret
= MMSYSERR_NOERROR
;
331 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
);
332 padsh
->fdwStatus
|= ACMSTREAMHEADER_STATUSF_PREPARED
;
333 padsh
->fdwPrepared
= padsh
->fdwStatus
;
334 padsh
->dwPrepared
= 0;
335 padsh
->pbPreparedSrc
= padsh
->pbSrc
;
336 padsh
->cbPreparedSrcLength
= padsh
->cbSrcLength
;
337 padsh
->pbPreparedDst
= padsh
->pbDst
;
338 padsh
->cbPreparedDstLength
= padsh
->cbDstLength
;
340 padsh
->fdwPrepared
= 0;
341 padsh
->dwPrepared
= 0;
342 padsh
->pbPreparedSrc
= 0;
343 padsh
->cbPreparedSrcLength
= 0;
344 padsh
->pbPreparedDst
= 0;
345 padsh
->cbPreparedDstLength
= 0;
347 TRACE("=> (%d)\n", ret
);
351 /***********************************************************************
352 * acmStreamReset (MSACM32.@)
354 MMRESULT WINAPI
acmStreamReset(HACMSTREAM has
, DWORD fdwReset
)
357 MMRESULT ret
= MMSYSERR_NOERROR
;
359 TRACE("(%p, %ld)\n", has
, fdwReset
);
362 WARN("invalid flag\n");
363 ret
= MMSYSERR_INVALFLAG
;
364 } else if ((was
= ACM_GetStream(has
)) == NULL
) {
365 WARN("invalid handle\n");
366 return MMSYSERR_INVALHANDLE
;
367 } else if (was
->drvInst
.fdwOpen
& ACM_STREAMOPENF_ASYNC
) {
368 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_RESET
, (DWORD
)&was
->drvInst
, 0);
370 TRACE("=> (%d)\n", ret
);
374 /***********************************************************************
375 * acmStreamSize (MSACM32.@)
377 MMRESULT WINAPI
acmStreamSize(HACMSTREAM has
, DWORD cbInput
,
378 LPDWORD pdwOutputBytes
, DWORD fdwSize
)
381 ACMDRVSTREAMSIZE adss
;
384 TRACE("(%p, %ld, %p, %ld)\n", has
, cbInput
, pdwOutputBytes
, fdwSize
);
386 if ((was
= ACM_GetStream(has
)) == NULL
) {
387 WARN("invalid handle\n");
388 return MMSYSERR_INVALHANDLE
;
390 if ((fdwSize
& ~ACM_STREAMSIZEF_QUERYMASK
) != 0) {
391 WARN("invalid flag\n");
392 return MMSYSERR_INVALFLAG
;
395 *pdwOutputBytes
= 0L;
397 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
398 case ACM_STREAMSIZEF_DESTINATION
:
399 adss
.cbDstLength
= cbInput
;
400 adss
.cbSrcLength
= 0;
402 case ACM_STREAMSIZEF_SOURCE
:
403 adss
.cbSrcLength
= cbInput
;
404 adss
.cbDstLength
= 0;
407 WARN("invalid flag\n");
408 return MMSYSERR_INVALFLAG
;
411 adss
.cbStruct
= sizeof(adss
);
412 adss
.fdwSize
= fdwSize
;
413 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_SIZE
,
414 (DWORD
)&was
->drvInst
, (DWORD
)&adss
);
415 if (ret
== MMSYSERR_NOERROR
) {
416 switch (fdwSize
& ACM_STREAMSIZEF_QUERYMASK
) {
417 case ACM_STREAMSIZEF_DESTINATION
:
418 *pdwOutputBytes
= adss
.cbSrcLength
;
420 case ACM_STREAMSIZEF_SOURCE
:
421 *pdwOutputBytes
= adss
.cbDstLength
;
425 TRACE("=> (%d) [%lu]\n", ret
, *pdwOutputBytes
);
429 /***********************************************************************
430 * acmStreamUnprepareHeader (MSACM32.@)
432 MMRESULT WINAPI
acmStreamUnprepareHeader(HACMSTREAM has
, PACMSTREAMHEADER pash
,
436 MMRESULT ret
= MMSYSERR_NOERROR
;
437 PACMDRVSTREAMHEADER padsh
;
439 TRACE("(%p, %p, %ld)\n", has
, pash
, fdwUnprepare
);
441 if ((was
= ACM_GetStream(has
)) == NULL
) {
442 WARN("invalid handle\n");
443 return MMSYSERR_INVALHANDLE
;
445 if (!pash
|| pash
->cbStruct
< sizeof(ACMSTREAMHEADER
)) {
446 WARN("invalid parameter\n");
447 return MMSYSERR_INVALPARAM
;
449 if (!(pash
->fdwStatus
& ACMSTREAMHEADER_STATUSF_PREPARED
)) {
450 WARN("unprepared header\n");
451 return ACMERR_UNPREPARED
;
454 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
455 * size. some fields are private to msacm internals, and are exposed
456 * in ACMSTREAMHEADER in the dwReservedDriver array
458 padsh
= (PACMDRVSTREAMHEADER
)pash
;
460 /* check that pointers have not been modified */
461 if (padsh
->pbPreparedSrc
!= padsh
->pbSrc
||
462 padsh
->cbPreparedSrcLength
< padsh
->cbSrcLength
||
463 padsh
->pbPreparedDst
!= padsh
->pbDst
||
464 padsh
->cbPreparedDstLength
< padsh
->cbDstLength
) {
465 WARN("invalid parameter\n");
466 return MMSYSERR_INVALPARAM
;
469 padsh
->fdwConvert
= fdwUnprepare
;
471 ret
= SendDriverMessage(was
->pDrv
->hDrvr
, ACMDM_STREAM_UNPREPARE
, (DWORD
)&was
->drvInst
, (DWORD
)padsh
);
472 if (ret
== MMSYSERR_NOERROR
|| ret
== MMSYSERR_NOTSUPPORTED
) {
473 ret
= MMSYSERR_NOERROR
;
474 padsh
->fdwStatus
&= ~(ACMSTREAMHEADER_STATUSF_DONE
|ACMSTREAMHEADER_STATUSF_INQUEUE
|ACMSTREAMHEADER_STATUSF_PREPARED
);
476 TRACE("=> (%d)\n", ret
);