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
21 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(msacm);
29 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
31 return (PWINE_ACMSTREAM)has;
34 /***********************************************************************
35 * acmStreamClose (MSACM32.37)
37 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
42 TRACE("(0x%08x, %ld)\n", has, fdwClose);
44 if ((was = ACM_GetStream(has)) == NULL) {
45 return MMSYSERR_INVALHANDLE;
47 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
48 if (ret == MMSYSERR_NOERROR) {
50 acmDriverClose(was->hAcmDriver, 0L);
51 HeapFree(MSACM_hHeap, 0, was);
53 TRACE("=> (%d)\n", ret);
57 /***********************************************************************
58 * acmStreamConvert (MSACM32.38)
60 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
64 MMRESULT ret = MMSYSERR_NOERROR;
65 PACMDRVSTREAMHEADER padsh;
67 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
69 if ((was = ACM_GetStream(has)) == NULL)
70 return MMSYSERR_INVALHANDLE;
71 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
72 return MMSYSERR_INVALPARAM;
74 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
75 return ACMERR_UNPREPARED;
77 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
78 * size. some fields are private to msacm internals, and are exposed
79 * in ACMSTREAMHEADER in the dwReservedDriver array
81 padsh = (PACMDRVSTREAMHEADER)pash;
83 /* check that pointers have not been modified */
84 if (padsh->pbPreparedSrc != padsh->pbSrc ||
85 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
86 padsh->pbPreparedDst != padsh->pbDst ||
87 padsh->cbPreparedDstLength < padsh->cbDstLength) {
88 return MMSYSERR_INVALPARAM;
91 padsh->fdwConvert = fdwConvert;
93 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
94 if (ret == MMSYSERR_NOERROR) {
95 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
97 TRACE("=> (%d)\n", ret);
101 /***********************************************************************
102 * acmStreamMessage (MSACM32.39)
104 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
107 FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
108 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
109 return MMSYSERR_ERROR;
112 /***********************************************************************
113 * acmStreamOpen (MSACM32.40)
115 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
116 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
117 DWORD dwInstance, DWORD fdwOpen)
125 TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
126 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
128 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
129 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
130 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
132 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
133 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
134 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
136 if ((fdwOpen & ACM_STREAMOPENF_QUERY) && phas) return MMSYSERR_INVALPARAM;
137 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) return MMSYSERR_INVALPARAM;
139 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
140 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
141 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
143 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
145 return MMSYSERR_NOMEM;
147 was->drvInst.cbStruct = sizeof(was->drvInst);
148 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
149 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
150 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
151 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
153 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
154 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
156 was->drvInst.pwfltr = NULL;
158 was->drvInst.dwCallback = dwCallback;
159 was->drvInst.dwInstance = dwInstance;
160 was->drvInst.fdwOpen = fdwOpen;
161 was->drvInst.fdwDriver = 0L;
162 was->drvInst.dwDriver = 0L;
163 was->drvInst.has = (HACMSTREAM)was;
166 if (!(wad = MSACM_GetDriver(had))) {
167 ret = MMSYSERR_INVALPARAM;
171 was->obj.dwType = WINE_ACMOBJ_STREAM;
172 was->obj.pACMDriverID = wad->obj.pACMDriverID;
174 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
176 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
177 if (ret != MMSYSERR_NOERROR)
180 PWINE_ACMDRIVERID wadi;
182 ret = ACMERR_NOTPOSSIBLE;
183 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
184 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
185 if (ret == MMSYSERR_NOERROR) {
186 if ((wad = MSACM_GetDriver(had)) != 0) {
187 was->obj.dwType = WINE_ACMOBJ_STREAM;
188 was->obj.pACMDriverID = wad->obj.pACMDriverID;
190 was->hAcmDriver = had;
192 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
193 if (ret == MMSYSERR_NOERROR) {
194 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
195 acmDriverClose(had, 0L);
200 /* no match, close this acm driver and try next one */
201 acmDriverClose(had, 0L);
204 if (ret != MMSYSERR_NOERROR) {
205 ret = ACMERR_NOTPOSSIBLE;
209 ret = MMSYSERR_NOERROR;
210 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
212 *phas = (HACMSTREAM)was;
213 TRACE("=> (%d)\n", ret);
218 *phas = (HACMSTREAM)0;
219 HeapFree(MSACM_hHeap, 0, was);
220 TRACE("=> (%d)\n", ret);
225 /***********************************************************************
226 * acmStreamPrepareHeader (MSACM32.41)
228 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
232 MMRESULT ret = MMSYSERR_NOERROR;
233 PACMDRVSTREAMHEADER padsh;
235 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
237 if ((was = ACM_GetStream(has)) == NULL)
238 return MMSYSERR_INVALHANDLE;
239 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
240 return MMSYSERR_INVALPARAM;
242 ret = MMSYSERR_INVALFLAG;
244 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
245 return MMSYSERR_NOERROR;
247 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
248 * size. some fields are private to msacm internals, and are exposed
249 * in ACMSTREAMHEADER in the dwReservedDriver array
251 padsh = (PACMDRVSTREAMHEADER)pash;
253 padsh->fdwConvert = fdwPrepare;
254 padsh->padshNext = NULL;
255 padsh->fdwDriver = padsh->dwDriver = 0L;
257 padsh->fdwPrepared = 0;
258 padsh->dwPrepared = 0;
259 padsh->pbPreparedSrc = 0;
260 padsh->cbPreparedSrcLength = 0;
261 padsh->pbPreparedDst = 0;
262 padsh->cbPreparedDstLength = 0;
264 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
265 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
266 ret = MMSYSERR_NOERROR;
267 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
268 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
269 padsh->fdwPrepared = padsh->fdwStatus;
270 padsh->dwPrepared = 0;
271 padsh->pbPreparedSrc = padsh->pbSrc;
272 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
273 padsh->pbPreparedDst = padsh->pbDst;
274 padsh->cbPreparedDstLength = padsh->cbDstLength;
276 padsh->fdwPrepared = 0;
277 padsh->dwPrepared = 0;
278 padsh->pbPreparedSrc = 0;
279 padsh->cbPreparedSrcLength = 0;
280 padsh->pbPreparedDst = 0;
281 padsh->cbPreparedDstLength = 0;
283 TRACE("=> (%d)\n", ret);
287 /***********************************************************************
288 * acmStreamReset (MSACM32.42)
290 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
293 MMRESULT ret = MMSYSERR_NOERROR;
295 TRACE("(0x%08x, %ld)\n", has, fdwReset);
298 ret = MMSYSERR_INVALFLAG;
299 } else if ((was = ACM_GetStream(has)) == NULL) {
300 return MMSYSERR_INVALHANDLE;
301 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
302 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
304 TRACE("=> (%d)\n", ret);
308 /***********************************************************************
309 * acmStreamSize (MSACM32.43)
311 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
312 LPDWORD pdwOutputBytes, DWORD fdwSize)
315 ACMDRVSTREAMSIZE adss;
318 TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
320 if ((was = ACM_GetStream(has)) == NULL) {
321 return MMSYSERR_INVALHANDLE;
323 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
324 return MMSYSERR_INVALFLAG;
327 *pdwOutputBytes = 0L;
329 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
330 case ACM_STREAMSIZEF_DESTINATION:
331 adss.cbDstLength = cbInput;
332 adss.cbSrcLength = 0;
334 case ACM_STREAMSIZEF_SOURCE:
335 adss.cbSrcLength = cbInput;
336 adss.cbDstLength = 0;
339 return MMSYSERR_INVALFLAG;
342 adss.cbStruct = sizeof(adss);
343 adss.fdwSize = fdwSize;
344 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
345 (DWORD)&was->drvInst, (DWORD)&adss);
346 if (ret == MMSYSERR_NOERROR) {
347 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
348 case ACM_STREAMSIZEF_DESTINATION:
349 *pdwOutputBytes = adss.cbSrcLength;
351 case ACM_STREAMSIZEF_SOURCE:
352 *pdwOutputBytes = adss.cbDstLength;
356 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
360 /***********************************************************************
361 * acmStreamUnprepareHeader (MSACM32.44)
363 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
367 MMRESULT ret = MMSYSERR_NOERROR;
368 PACMDRVSTREAMHEADER padsh;
370 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
372 if ((was = ACM_GetStream(has)) == NULL)
373 return MMSYSERR_INVALHANDLE;
374 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
375 return MMSYSERR_INVALPARAM;
377 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
378 return ACMERR_UNPREPARED;
380 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
381 * size. some fields are private to msacm internals, and are exposed
382 * in ACMSTREAMHEADER in the dwReservedDriver array
384 padsh = (PACMDRVSTREAMHEADER)pash;
386 /* check that pointers have not been modified */
387 if (padsh->pbPreparedSrc != padsh->pbSrc ||
388 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
389 padsh->pbPreparedDst != padsh->pbDst ||
390 padsh->cbPreparedDstLength < padsh->cbDstLength) {
391 return MMSYSERR_INVALPARAM;
394 padsh->fdwConvert = fdwUnprepare;
396 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
397 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
398 ret = MMSYSERR_NOERROR;
399 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
401 TRACE("=> (%d)\n", ret);