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
35 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
43 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
45 return (PWINE_ACMSTREAM)has;
48 /***********************************************************************
49 * acmStreamClose (MSACM32.@)
51 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
56 TRACE("(%p, %ld)\n", has, fdwClose);
58 if ((was = ACM_GetStream(has)) == NULL) {
59 return MMSYSERR_INVALHANDLE;
61 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
62 if (ret == MMSYSERR_NOERROR) {
64 acmDriverClose(was->hAcmDriver, 0L);
65 HeapFree(MSACM_hHeap, 0, was);
67 TRACE("=> (%d)\n", ret);
71 /***********************************************************************
72 * acmStreamConvert (MSACM32.@)
74 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
78 MMRESULT ret = MMSYSERR_NOERROR;
79 PACMDRVSTREAMHEADER padsh;
81 TRACE("(%p, %p, %ld)\n", has, pash, fdwConvert);
83 if ((was = ACM_GetStream(has)) == NULL)
84 return MMSYSERR_INVALHANDLE;
85 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
86 return MMSYSERR_INVALPARAM;
88 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
89 return ACMERR_UNPREPARED;
91 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
92 * size. some fields are private to msacm internals, and are exposed
93 * in ACMSTREAMHEADER in the dwReservedDriver array
95 padsh = (PACMDRVSTREAMHEADER)pash;
97 /* check that pointers have not been modified */
98 if (padsh->pbPreparedSrc != padsh->pbSrc ||
99 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
100 padsh->pbPreparedDst != padsh->pbDst ||
101 padsh->cbPreparedDstLength < padsh->cbDstLength) {
102 return MMSYSERR_INVALPARAM;
105 padsh->fdwConvert = fdwConvert;
107 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
108 if (ret == MMSYSERR_NOERROR) {
109 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
111 TRACE("=> (%d)\n", ret);
115 /***********************************************************************
116 * acmStreamMessage (MSACM32.@)
118 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
121 FIXME("(%p, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
122 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
123 return MMSYSERR_ERROR;
126 /***********************************************************************
127 * acmStreamOpen (MSACM32.@)
129 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
130 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
131 DWORD dwInstance, DWORD fdwOpen)
139 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n",
140 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
142 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
143 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
144 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
146 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
147 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
148 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
150 /* (WS) In query mode, phas should be NULL. If it is not, then instead
151 * of returning an error we are making sure it is NULL, preventing some
152 * applications that pass garbage for phas from crashing.
154 if (fdwOpen & ACM_STREAMOPENF_QUERY) phas = NULL;
156 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) return MMSYSERR_INVALPARAM;
158 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
159 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
160 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
162 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize +
163 ((pwfltr) ? sizeof(WAVEFILTER) : 0));
165 return MMSYSERR_NOMEM;
167 was->drvInst.cbStruct = sizeof(was->drvInst);
168 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
169 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
170 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
171 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
173 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
174 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
176 was->drvInst.pwfltr = NULL;
178 was->drvInst.dwCallback = dwCallback;
179 was->drvInst.dwInstance = dwInstance;
180 was->drvInst.fdwOpen = fdwOpen;
181 was->drvInst.fdwDriver = 0L;
182 was->drvInst.dwDriver = 0L;
183 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
184 was->drvInst.has = 0L;
187 if (!(wad = MSACM_GetDriver(had))) {
188 ret = MMSYSERR_INVALPARAM;
192 was->obj.dwType = WINE_ACMOBJ_STREAM;
193 was->obj.pACMDriverID = wad->obj.pACMDriverID;
195 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
197 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
198 if (ret != MMSYSERR_NOERROR)
201 PWINE_ACMDRIVERID wadi;
203 ret = ACMERR_NOTPOSSIBLE;
204 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
205 if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
206 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
207 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
209 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
210 if (ret != MMSYSERR_NOERROR)
212 if ((wad = MSACM_GetDriver(had)) != 0) {
213 was->obj.dwType = WINE_ACMOBJ_STREAM;
214 was->obj.pACMDriverID = wad->obj.pACMDriverID;
216 was->hAcmDriver = had;
218 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
219 TRACE("%s => %08x\n", wadi->pszDriverAlias, ret);
220 if (ret == MMSYSERR_NOERROR) {
221 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
222 acmDriverClose(had, 0L);
227 /* no match, close this acm driver and try next one */
228 acmDriverClose(had, 0L);
230 if (ret != MMSYSERR_NOERROR) {
231 ret = ACMERR_NOTPOSSIBLE;
235 ret = MMSYSERR_NOERROR;
236 was->drvInst.has = (HACMSTREAM)was;
237 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
239 *phas = (HACMSTREAM)was;
240 TRACE("=> (%d)\n", ret);
246 HeapFree(MSACM_hHeap, 0, was);
247 TRACE("=> (%d)\n", ret);
252 /***********************************************************************
253 * acmStreamPrepareHeader (MSACM32.@)
255 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
259 MMRESULT ret = MMSYSERR_NOERROR;
260 PACMDRVSTREAMHEADER padsh;
262 TRACE("(%p, %p, %ld)\n", has, pash, fdwPrepare);
264 if ((was = ACM_GetStream(has)) == NULL)
265 return MMSYSERR_INVALHANDLE;
266 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
267 return MMSYSERR_INVALPARAM;
269 ret = MMSYSERR_INVALFLAG;
271 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
272 return MMSYSERR_NOERROR;
274 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
275 * size. some fields are private to msacm internals, and are exposed
276 * in ACMSTREAMHEADER in the dwReservedDriver array
278 padsh = (PACMDRVSTREAMHEADER)pash;
280 padsh->fdwConvert = fdwPrepare;
281 padsh->padshNext = NULL;
282 padsh->fdwDriver = padsh->dwDriver = 0L;
284 padsh->fdwPrepared = 0;
285 padsh->dwPrepared = 0;
286 padsh->pbPreparedSrc = 0;
287 padsh->cbPreparedSrcLength = 0;
288 padsh->pbPreparedDst = 0;
289 padsh->cbPreparedDstLength = 0;
291 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
292 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
293 ret = MMSYSERR_NOERROR;
294 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
295 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
296 padsh->fdwPrepared = padsh->fdwStatus;
297 padsh->dwPrepared = 0;
298 padsh->pbPreparedSrc = padsh->pbSrc;
299 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
300 padsh->pbPreparedDst = padsh->pbDst;
301 padsh->cbPreparedDstLength = padsh->cbDstLength;
303 padsh->fdwPrepared = 0;
304 padsh->dwPrepared = 0;
305 padsh->pbPreparedSrc = 0;
306 padsh->cbPreparedSrcLength = 0;
307 padsh->pbPreparedDst = 0;
308 padsh->cbPreparedDstLength = 0;
310 TRACE("=> (%d)\n", ret);
314 /***********************************************************************
315 * acmStreamReset (MSACM32.@)
317 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
320 MMRESULT ret = MMSYSERR_NOERROR;
322 TRACE("(%p, %ld)\n", has, fdwReset);
325 ret = MMSYSERR_INVALFLAG;
326 } else if ((was = ACM_GetStream(has)) == NULL) {
327 return MMSYSERR_INVALHANDLE;
328 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
329 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
331 TRACE("=> (%d)\n", ret);
335 /***********************************************************************
336 * acmStreamSize (MSACM32.@)
338 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
339 LPDWORD pdwOutputBytes, DWORD fdwSize)
342 ACMDRVSTREAMSIZE adss;
345 TRACE("(%p, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
347 if ((was = ACM_GetStream(has)) == NULL) {
348 return MMSYSERR_INVALHANDLE;
350 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
351 return MMSYSERR_INVALFLAG;
354 *pdwOutputBytes = 0L;
356 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
357 case ACM_STREAMSIZEF_DESTINATION:
358 adss.cbDstLength = cbInput;
359 adss.cbSrcLength = 0;
361 case ACM_STREAMSIZEF_SOURCE:
362 adss.cbSrcLength = cbInput;
363 adss.cbDstLength = 0;
366 return MMSYSERR_INVALFLAG;
369 adss.cbStruct = sizeof(adss);
370 adss.fdwSize = fdwSize;
371 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
372 (DWORD)&was->drvInst, (DWORD)&adss);
373 if (ret == MMSYSERR_NOERROR) {
374 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
375 case ACM_STREAMSIZEF_DESTINATION:
376 *pdwOutputBytes = adss.cbSrcLength;
378 case ACM_STREAMSIZEF_SOURCE:
379 *pdwOutputBytes = adss.cbDstLength;
383 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
387 /***********************************************************************
388 * acmStreamUnprepareHeader (MSACM32.@)
390 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
394 MMRESULT ret = MMSYSERR_NOERROR;
395 PACMDRVSTREAMHEADER padsh;
397 TRACE("(%p, %p, %ld)\n", has, pash, fdwUnprepare);
399 if ((was = ACM_GetStream(has)) == NULL)
400 return MMSYSERR_INVALHANDLE;
401 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
402 return MMSYSERR_INVALPARAM;
404 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
405 return ACMERR_UNPREPARED;
407 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
408 * size. some fields are private to msacm internals, and are exposed
409 * in ACMSTREAMHEADER in the dwReservedDriver array
411 padsh = (PACMDRVSTREAMHEADER)pash;
413 /* check that pointers have not been modified */
414 if (padsh->pbPreparedSrc != padsh->pbSrc ||
415 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
416 padsh->pbPreparedDst != padsh->pbDst ||
417 padsh->cbPreparedDstLength < padsh->cbDstLength) {
418 return MMSYSERR_INVALPARAM;
421 padsh->fdwConvert = fdwUnprepare;
423 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
424 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
425 ret = MMSYSERR_NOERROR;
426 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
428 TRACE("=> (%d)\n", ret);