1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1998 Patrik Stridvall
11 * + asynchronous conversion is not implemented
12 * + callback/notification
14 * + properly close ACM streams
20 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(msacm)
28 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
30 return (PWINE_ACMSTREAM)has;
33 /***********************************************************************
34 * acmStreamClose (MSACM32.37)
36 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
41 TRACE("(0x%08x, %ld)\n", has, fdwClose);
43 if ((was = ACM_GetStream(has)) == NULL) {
44 return MMSYSERR_INVALHANDLE;
46 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
47 if (ret == MMSYSERR_NOERROR) {
48 /* FIXME: shall the was->pDrv->hDrvr be also closed ? */
49 HeapFree(MSACM_hHeap, 0, was);
51 TRACE("=> (%d)\n", ret);
55 /***********************************************************************
56 * acmStreamConvert (MSACM32.38)
58 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
62 MMRESULT ret = MMSYSERR_NOERROR;
63 PACMDRVSTREAMHEADER padsh;
65 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
67 if ((was = ACM_GetStream(has)) == NULL)
68 return MMSYSERR_INVALHANDLE;
69 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
70 return MMSYSERR_INVALPARAM;
72 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
73 return ACMERR_UNPREPARED;
75 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
76 * size. some fields are private to msacm internals, and are exposed
77 * in ACMSTREAMHEADER in the dwReservedDriver array
79 padsh = (PACMDRVSTREAMHEADER)pash;
81 /* check that pointers have not been modified */
82 if (padsh->pbPreparedSrc != padsh->pbSrc ||
83 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
84 padsh->pbPreparedDst != padsh->pbDst ||
85 padsh->cbPreparedDstLength < padsh->cbDstLength) {
86 return MMSYSERR_INVALPARAM;
89 padsh->fdwConvert = fdwConvert;
91 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
92 if (ret == MMSYSERR_NOERROR) {
93 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
95 TRACE("=> (%d)\n", ret);
99 /***********************************************************************
100 * acmStreamMessage (MSACM32.39)
102 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
105 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
106 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
107 return MMSYSERR_ERROR;
110 /***********************************************************************
111 * acmStreamOpen (MSACM32.40)
113 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
114 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
115 DWORD dwInstance, DWORD fdwOpen)
123 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
124 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
126 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
127 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
128 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
130 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
131 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
132 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
134 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
135 wfxSrcSize = SIZEOF_WFX(pwfxSrc);
136 wfxDstSize = SIZEOF_WFX(pwfxDst);
139 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
141 return MMSYSERR_NOMEM;
143 was->drvInst.cbStruct = sizeof(was->drvInst);
144 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
145 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
146 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
147 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
149 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
150 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
152 was->drvInst.pwfltr = NULL;
154 was->drvInst.dwCallback = dwCallback;
155 was->drvInst.dwInstance = dwInstance;
156 was->drvInst.fdwOpen = fdwOpen;
157 was->drvInst.fdwDriver = 0L;
158 was->drvInst.dwDriver = 0L;
159 was->drvInst.has = (HACMSTREAM)was;
162 if (!(wad = MSACM_GetDriver(had))) {
163 ret = MMSYSERR_INVALPARAM;
167 was->obj.pACMDriverID = wad->obj.pACMDriverID;
170 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
171 if (ret != MMSYSERR_NOERROR)
174 PWINE_ACMDRIVERID wadi;
176 ret = ACMERR_NOTPOSSIBLE;
177 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
178 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
179 if (ret == MMSYSERR_NOERROR) {
180 if ((wad = MSACM_GetDriver(had)) != 0) {
181 was->obj.pACMDriverID = wad->obj.pACMDriverID;
184 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
185 /* FIXME: when shall the acmDriver be Close():d ? */
186 if (ret == MMSYSERR_NOERROR)
189 /* no match, close this acm driver and try next one */
190 acmDriverClose(had, 0L);
193 if (ret != MMSYSERR_NOERROR) {
194 ret = ACMERR_NOTPOSSIBLE;
199 *phas = (HACMSTREAM)was;
200 TRACE("=> (%d)\n", ret);
201 ret = MMSYSERR_NOERROR;
202 if (!(fdwOpen & ACM_STREAMOPENF_QUERY))
205 HeapFree(MSACM_hHeap, 0, was);
206 TRACE("=> (%d)\n", ret);
211 /***********************************************************************
212 * acmStreamPrepareHeader (MSACM32.41)
214 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
218 MMRESULT ret = MMSYSERR_NOERROR;
219 PACMDRVSTREAMHEADER padsh;
221 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
223 if ((was = ACM_GetStream(has)) == NULL)
224 return MMSYSERR_INVALHANDLE;
225 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
226 return MMSYSERR_INVALPARAM;
228 ret = MMSYSERR_INVALFLAG;
230 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
231 return MMSYSERR_NOERROR;
233 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
234 * size. some fields are private to msacm internals, and are exposed
235 * in ACMSTREAMHEADER in the dwReservedDriver array
237 padsh = (PACMDRVSTREAMHEADER)pash;
239 padsh->fdwConvert = fdwPrepare;
240 padsh->padshNext = NULL;
241 padsh->fdwDriver = padsh->dwDriver = 0L;
243 padsh->fdwPrepared = 0;
244 padsh->dwPrepared = 0;
245 padsh->pbPreparedSrc = 0;
246 padsh->cbPreparedSrcLength = 0;
247 padsh->pbPreparedDst = 0;
248 padsh->cbPreparedDstLength = 0;
250 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
251 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
252 ret = MMSYSERR_NOERROR;
253 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
254 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
255 padsh->fdwPrepared = padsh->fdwStatus;
256 padsh->dwPrepared = 0;
257 padsh->pbPreparedSrc = padsh->pbSrc;
258 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
259 padsh->pbPreparedDst = padsh->pbDst;
260 padsh->cbPreparedDstLength = padsh->cbDstLength;
262 padsh->fdwPrepared = 0;
263 padsh->dwPrepared = 0;
264 padsh->pbPreparedSrc = 0;
265 padsh->cbPreparedSrcLength = 0;
266 padsh->pbPreparedDst = 0;
267 padsh->cbPreparedDstLength = 0;
269 TRACE("=> (%d)\n", ret);
273 /***********************************************************************
274 * acmStreamReset (MSACM32.42)
276 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
279 MMRESULT ret = MMSYSERR_NOERROR;
281 TRACE("(0x%08x, %ld)\n", has, fdwReset);
284 ret = MMSYSERR_INVALFLAG;
285 } else if ((was = ACM_GetStream(has)) == NULL) {
286 return MMSYSERR_INVALHANDLE;
287 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
288 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
290 TRACE("=> (%d)\n", ret);
294 /***********************************************************************
295 * acmStreamSize (MSACM32.43)
297 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
298 LPDWORD pdwOutputBytes, DWORD fdwSize)
301 ACMDRVSTREAMSIZE adss;
304 TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
306 if ((was = ACM_GetStream(has)) == NULL) {
307 return MMSYSERR_INVALHANDLE;
309 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
310 return MMSYSERR_INVALFLAG;
313 *pdwOutputBytes = 0L;
315 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
316 case ACM_STREAMSIZEF_DESTINATION:
317 adss.cbDstLength = cbInput;
318 adss.cbSrcLength = 0;
320 case ACM_STREAMSIZEF_SOURCE:
321 adss.cbSrcLength = cbInput;
322 adss.cbDstLength = 0;
325 return MMSYSERR_INVALFLAG;
328 adss.cbStruct = sizeof(adss);
329 adss.fdwSize = fdwSize;
330 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
331 (DWORD)&was->drvInst, (DWORD)&adss);
332 if (ret == MMSYSERR_NOERROR) {
333 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
334 case ACM_STREAMSIZEF_DESTINATION:
335 *pdwOutputBytes = adss.cbSrcLength;
337 case ACM_STREAMSIZEF_SOURCE:
338 *pdwOutputBytes = adss.cbDstLength;
342 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
346 /***********************************************************************
347 * acmStreamUnprepareHeader (MSACM32.44)
349 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
353 MMRESULT ret = MMSYSERR_NOERROR;
354 PACMDRVSTREAMHEADER padsh;
356 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
358 if ((was = ACM_GetStream(has)) == NULL)
359 return MMSYSERR_INVALHANDLE;
360 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
361 return MMSYSERR_INVALPARAM;
363 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
364 return ACMERR_UNPREPARED;
366 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
367 * size. some fields are private to msacm internals, and are exposed
368 * in ACMSTREAMHEADER in the dwReservedDriver array
370 padsh = (PACMDRVSTREAMHEADER)pash;
372 /* check that pointers have not been modified */
373 if (padsh->pbPreparedSrc != padsh->pbSrc ||
374 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
375 padsh->pbPreparedDst != padsh->pbDst ||
376 padsh->cbPreparedDstLength < padsh->cbDstLength) {
377 return MMSYSERR_INVALPARAM;
380 padsh->fdwConvert = fdwUnprepare;
382 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
383 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
384 ret = MMSYSERR_NOERROR;
385 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
387 TRACE("=> (%d)\n", ret);