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);