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) {
49 acmDriverClose(was->hAcmDriver, 0L);
50 HeapFree(MSACM_hHeap, 0, was);
52 TRACE("=> (%d)\n", ret);
56 /***********************************************************************
57 * acmStreamConvert (MSACM32.38)
59 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
63 MMRESULT ret = MMSYSERR_NOERROR;
64 PACMDRVSTREAMHEADER padsh;
66 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
68 if ((was = ACM_GetStream(has)) == NULL)
69 return MMSYSERR_INVALHANDLE;
70 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
71 return MMSYSERR_INVALPARAM;
73 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
74 return ACMERR_UNPREPARED;
76 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
77 * size. some fields are private to msacm internals, and are exposed
78 * in ACMSTREAMHEADER in the dwReservedDriver array
80 padsh = (PACMDRVSTREAMHEADER)pash;
82 /* check that pointers have not been modified */
83 if (padsh->pbPreparedSrc != padsh->pbSrc ||
84 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
85 padsh->pbPreparedDst != padsh->pbDst ||
86 padsh->cbPreparedDstLength < padsh->cbDstLength) {
87 return MMSYSERR_INVALPARAM;
90 padsh->fdwConvert = fdwConvert;
92 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
93 if (ret == MMSYSERR_NOERROR) {
94 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
96 TRACE("=> (%d)\n", ret);
100 /***********************************************************************
101 * acmStreamMessage (MSACM32.39)
103 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
106 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
107 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
108 return MMSYSERR_ERROR;
111 /***********************************************************************
112 * acmStreamOpen (MSACM32.40)
114 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
115 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
116 DWORD dwInstance, DWORD fdwOpen)
124 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
125 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
127 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
128 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
129 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
131 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
132 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
133 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
135 if ((fdwOpen & ACM_STREAMOPENF_QUERY) && phas) return MMSYSERR_INVALPARAM;
136 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) return MMSYSERR_INVALPARAM;
138 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
139 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
140 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
142 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
144 return MMSYSERR_NOMEM;
146 was->drvInst.cbStruct = sizeof(was->drvInst);
147 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
148 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
149 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
150 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
152 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
153 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
155 was->drvInst.pwfltr = NULL;
157 was->drvInst.dwCallback = dwCallback;
158 was->drvInst.dwInstance = dwInstance;
159 was->drvInst.fdwOpen = fdwOpen;
160 was->drvInst.fdwDriver = 0L;
161 was->drvInst.dwDriver = 0L;
162 was->drvInst.has = (HACMSTREAM)was;
165 if (!(wad = MSACM_GetDriver(had))) {
166 ret = MMSYSERR_INVALPARAM;
170 was->obj.dwType = WINE_ACMOBJ_STREAM;
171 was->obj.pACMDriverID = wad->obj.pACMDriverID;
173 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
175 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
176 if (ret != MMSYSERR_NOERROR)
179 PWINE_ACMDRIVERID wadi;
181 ret = ACMERR_NOTPOSSIBLE;
182 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
183 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
184 if (ret == MMSYSERR_NOERROR) {
185 if ((wad = MSACM_GetDriver(had)) != 0) {
186 was->obj.dwType = WINE_ACMOBJ_STREAM;
187 was->obj.pACMDriverID = wad->obj.pACMDriverID;
189 was->hAcmDriver = had;
191 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
192 if (ret == MMSYSERR_NOERROR) {
193 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
194 acmDriverClose(had, 0L);
199 /* no match, close this acm driver and try next one */
200 acmDriverClose(had, 0L);
203 if (ret != MMSYSERR_NOERROR) {
204 ret = ACMERR_NOTPOSSIBLE;
208 ret = MMSYSERR_NOERROR;
209 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
211 *phas = (HACMSTREAM)was;
212 TRACE("=> (%d)\n", ret);
217 *phas = (HACMSTREAM)0;
218 HeapFree(MSACM_hHeap, 0, was);
219 TRACE("=> (%d)\n", ret);
224 /***********************************************************************
225 * acmStreamPrepareHeader (MSACM32.41)
227 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
231 MMRESULT ret = MMSYSERR_NOERROR;
232 PACMDRVSTREAMHEADER padsh;
234 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
236 if ((was = ACM_GetStream(has)) == NULL)
237 return MMSYSERR_INVALHANDLE;
238 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
239 return MMSYSERR_INVALPARAM;
241 ret = MMSYSERR_INVALFLAG;
243 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
244 return MMSYSERR_NOERROR;
246 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
247 * size. some fields are private to msacm internals, and are exposed
248 * in ACMSTREAMHEADER in the dwReservedDriver array
250 padsh = (PACMDRVSTREAMHEADER)pash;
252 padsh->fdwConvert = fdwPrepare;
253 padsh->padshNext = NULL;
254 padsh->fdwDriver = padsh->dwDriver = 0L;
256 padsh->fdwPrepared = 0;
257 padsh->dwPrepared = 0;
258 padsh->pbPreparedSrc = 0;
259 padsh->cbPreparedSrcLength = 0;
260 padsh->pbPreparedDst = 0;
261 padsh->cbPreparedDstLength = 0;
263 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
264 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
265 ret = MMSYSERR_NOERROR;
266 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
267 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
268 padsh->fdwPrepared = padsh->fdwStatus;
269 padsh->dwPrepared = 0;
270 padsh->pbPreparedSrc = padsh->pbSrc;
271 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
272 padsh->pbPreparedDst = padsh->pbDst;
273 padsh->cbPreparedDstLength = padsh->cbDstLength;
275 padsh->fdwPrepared = 0;
276 padsh->dwPrepared = 0;
277 padsh->pbPreparedSrc = 0;
278 padsh->cbPreparedSrcLength = 0;
279 padsh->pbPreparedDst = 0;
280 padsh->cbPreparedDstLength = 0;
282 TRACE("=> (%d)\n", ret);
286 /***********************************************************************
287 * acmStreamReset (MSACM32.42)
289 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
292 MMRESULT ret = MMSYSERR_NOERROR;
294 TRACE("(0x%08x, %ld)\n", has, fdwReset);
297 ret = MMSYSERR_INVALFLAG;
298 } else if ((was = ACM_GetStream(has)) == NULL) {
299 return MMSYSERR_INVALHANDLE;
300 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
301 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
303 TRACE("=> (%d)\n", ret);
307 /***********************************************************************
308 * acmStreamSize (MSACM32.43)
310 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
311 LPDWORD pdwOutputBytes, DWORD fdwSize)
314 ACMDRVSTREAMSIZE adss;
317 TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
319 if ((was = ACM_GetStream(has)) == NULL) {
320 return MMSYSERR_INVALHANDLE;
322 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
323 return MMSYSERR_INVALFLAG;
326 *pdwOutputBytes = 0L;
328 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
329 case ACM_STREAMSIZEF_DESTINATION:
330 adss.cbDstLength = cbInput;
331 adss.cbSrcLength = 0;
333 case ACM_STREAMSIZEF_SOURCE:
334 adss.cbSrcLength = cbInput;
335 adss.cbDstLength = 0;
338 return MMSYSERR_INVALFLAG;
341 adss.cbStruct = sizeof(adss);
342 adss.fdwSize = fdwSize;
343 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
344 (DWORD)&was->drvInst, (DWORD)&adss);
345 if (ret == MMSYSERR_NOERROR) {
346 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
347 case ACM_STREAMSIZEF_DESTINATION:
348 *pdwOutputBytes = adss.cbSrcLength;
350 case ACM_STREAMSIZEF_SOURCE:
351 *pdwOutputBytes = adss.cbDstLength;
355 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
359 /***********************************************************************
360 * acmStreamUnprepareHeader (MSACM32.44)
362 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
366 MMRESULT ret = MMSYSERR_NOERROR;
367 PACMDRVSTREAMHEADER padsh;
369 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
371 if ((was = ACM_GetStream(has)) == NULL)
372 return MMSYSERR_INVALHANDLE;
373 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
374 return MMSYSERR_INVALPARAM;
376 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
377 return ACMERR_UNPREPARED;
379 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
380 * size. some fields are private to msacm internals, and are exposed
381 * in ACMSTREAMHEADER in the dwReservedDriver array
383 padsh = (PACMDRVSTREAMHEADER)pash;
385 /* check that pointers have not been modified */
386 if (padsh->pbPreparedSrc != padsh->pbSrc ||
387 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
388 padsh->pbPreparedDst != padsh->pbDst ||
389 padsh->cbPreparedDstLength < padsh->cbDstLength) {
390 return MMSYSERR_INVALPARAM;
393 padsh->fdwConvert = fdwUnprepare;
395 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
396 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
397 ret = MMSYSERR_NOERROR;
398 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
400 TRACE("=> (%d)\n", ret);