Fixed merge error.
[wine/wine64.git] / dlls / msacm / stream.c
blob34465907527f4d5d096ac556868f32b5758bb72c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
8 */
10 /* TODO
11 * + asynchronous conversion is not implemented
12 * + callback/notification
13 * * acmStreamMessage
14 * + properly close ACM streams
17 #include <string.h>
18 #include "winbase.h"
19 #include "winerror.h"
20 #include "windef.h"
21 #include "debugtools.h"
22 #include "mmsystem.h"
23 #include "msacm.h"
24 #include "msacmdrv.h"
25 #include "wineacm.h"
27 DEFAULT_DEBUG_CHANNEL(msacm);
29 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
31 return (PWINE_ACMSTREAM)has;
34 /***********************************************************************
35 * acmStreamClose (MSACM32.@)
37 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
39 PWINE_ACMSTREAM was;
40 MMRESULT ret;
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) {
49 if (was->hAcmDriver)
50 acmDriverClose(was->hAcmDriver, 0L);
51 HeapFree(MSACM_hHeap, 0, was);
53 TRACE("=> (%d)\n", ret);
54 return ret;
57 /***********************************************************************
58 * acmStreamConvert (MSACM32.@)
60 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
61 DWORD fdwConvert)
63 PWINE_ACMSTREAM was;
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);
98 return ret;
101 /***********************************************************************
102 * acmStreamMessage (MSACM32.@)
104 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
105 LPARAM lParam2)
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.@)
115 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
116 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
117 DWORD dwInstance, DWORD fdwOpen)
119 PWINE_ACMSTREAM was;
120 PWINE_ACMDRIVER wad;
121 MMRESULT ret;
122 int wfxSrcSize;
123 int wfxDstSize;
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 +
144 ((pwfltr) ? sizeof(WAVEFILTER) : 0));
145 if (was == NULL)
146 return MMSYSERR_NOMEM;
148 was->drvInst.cbStruct = sizeof(was->drvInst);
149 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
150 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
151 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
152 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
153 if (pwfltr) {
154 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
155 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
156 } else {
157 was->drvInst.pwfltr = NULL;
159 was->drvInst.dwCallback = dwCallback;
160 was->drvInst.dwInstance = dwInstance;
161 was->drvInst.fdwOpen = fdwOpen;
162 was->drvInst.fdwDriver = 0L;
163 was->drvInst.dwDriver = 0L;
164 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
165 was->drvInst.has = 0L;
167 if (had) {
168 if (!(wad = MSACM_GetDriver(had))) {
169 ret = MMSYSERR_INVALPARAM;
170 goto errCleanUp;
173 was->obj.dwType = WINE_ACMOBJ_STREAM;
174 was->obj.pACMDriverID = wad->obj.pACMDriverID;
175 was->pDrv = wad;
176 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
178 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
179 if (ret != MMSYSERR_NOERROR)
180 goto errCleanUp;
181 } else {
182 PWINE_ACMDRIVERID wadi;
184 ret = ACMERR_NOTPOSSIBLE;
185 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
186 if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
187 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
188 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
189 continue;
190 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
191 if (ret != MMSYSERR_NOERROR)
192 continue;
193 if ((wad = MSACM_GetDriver(had)) != 0) {
194 was->obj.dwType = WINE_ACMOBJ_STREAM;
195 was->obj.pACMDriverID = wad->obj.pACMDriverID;
196 was->pDrv = wad;
197 was->hAcmDriver = had;
199 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
200 TRACE("%s => %08x\n", wadi->pszDriverAlias, ret);
201 if (ret == MMSYSERR_NOERROR) {
202 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
203 acmDriverClose(had, 0L);
205 break;
208 /* no match, close this acm driver and try next one */
209 acmDriverClose(had, 0L);
211 if (ret != MMSYSERR_NOERROR) {
212 ret = ACMERR_NOTPOSSIBLE;
213 goto errCleanUp;
216 ret = MMSYSERR_NOERROR;
217 was->drvInst.has = (HACMSTREAM)was;
218 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
219 if (phas)
220 *phas = (HACMSTREAM)was;
221 TRACE("=> (%d)\n", ret);
222 return ret;
224 errCleanUp:
225 if (phas)
226 *phas = (HACMSTREAM)0;
227 HeapFree(MSACM_hHeap, 0, was);
228 TRACE("=> (%d)\n", ret);
229 return ret;
233 /***********************************************************************
234 * acmStreamPrepareHeader (MSACM32.@)
236 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
237 DWORD fdwPrepare)
239 PWINE_ACMSTREAM was;
240 MMRESULT ret = MMSYSERR_NOERROR;
241 PACMDRVSTREAMHEADER padsh;
243 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
245 if ((was = ACM_GetStream(has)) == NULL)
246 return MMSYSERR_INVALHANDLE;
247 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
248 return MMSYSERR_INVALPARAM;
249 if (fdwPrepare)
250 ret = MMSYSERR_INVALFLAG;
252 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
253 return MMSYSERR_NOERROR;
255 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
256 * size. some fields are private to msacm internals, and are exposed
257 * in ACMSTREAMHEADER in the dwReservedDriver array
259 padsh = (PACMDRVSTREAMHEADER)pash;
261 padsh->fdwConvert = fdwPrepare;
262 padsh->padshNext = NULL;
263 padsh->fdwDriver = padsh->dwDriver = 0L;
265 padsh->fdwPrepared = 0;
266 padsh->dwPrepared = 0;
267 padsh->pbPreparedSrc = 0;
268 padsh->cbPreparedSrcLength = 0;
269 padsh->pbPreparedDst = 0;
270 padsh->cbPreparedDstLength = 0;
272 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
273 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
274 ret = MMSYSERR_NOERROR;
275 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
276 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
277 padsh->fdwPrepared = padsh->fdwStatus;
278 padsh->dwPrepared = 0;
279 padsh->pbPreparedSrc = padsh->pbSrc;
280 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
281 padsh->pbPreparedDst = padsh->pbDst;
282 padsh->cbPreparedDstLength = padsh->cbDstLength;
283 } else {
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 TRACE("=> (%d)\n", ret);
292 return ret;
295 /***********************************************************************
296 * acmStreamReset (MSACM32.@)
298 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
300 PWINE_ACMSTREAM was;
301 MMRESULT ret = MMSYSERR_NOERROR;
303 TRACE("(0x%08x, %ld)\n", has, fdwReset);
305 if (fdwReset) {
306 ret = MMSYSERR_INVALFLAG;
307 } else if ((was = ACM_GetStream(has)) == NULL) {
308 return MMSYSERR_INVALHANDLE;
309 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
310 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
312 TRACE("=> (%d)\n", ret);
313 return ret;
316 /***********************************************************************
317 * acmStreamSize (MSACM32.@)
319 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
320 LPDWORD pdwOutputBytes, DWORD fdwSize)
322 PWINE_ACMSTREAM was;
323 ACMDRVSTREAMSIZE adss;
324 MMRESULT ret;
326 TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
328 if ((was = ACM_GetStream(has)) == NULL) {
329 return MMSYSERR_INVALHANDLE;
331 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
332 return MMSYSERR_INVALFLAG;
335 *pdwOutputBytes = 0L;
337 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
338 case ACM_STREAMSIZEF_DESTINATION:
339 adss.cbDstLength = cbInput;
340 adss.cbSrcLength = 0;
341 break;
342 case ACM_STREAMSIZEF_SOURCE:
343 adss.cbSrcLength = cbInput;
344 adss.cbDstLength = 0;
345 break;
346 default:
347 return MMSYSERR_INVALFLAG;
350 adss.cbStruct = sizeof(adss);
351 adss.fdwSize = fdwSize;
352 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
353 (DWORD)&was->drvInst, (DWORD)&adss);
354 if (ret == MMSYSERR_NOERROR) {
355 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
356 case ACM_STREAMSIZEF_DESTINATION:
357 *pdwOutputBytes = adss.cbSrcLength;
358 break;
359 case ACM_STREAMSIZEF_SOURCE:
360 *pdwOutputBytes = adss.cbDstLength;
361 break;
364 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
365 return ret;
368 /***********************************************************************
369 * acmStreamUnprepareHeader (MSACM32.@)
371 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
372 DWORD fdwUnprepare)
374 PWINE_ACMSTREAM was;
375 MMRESULT ret = MMSYSERR_NOERROR;
376 PACMDRVSTREAMHEADER padsh;
378 TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
380 if ((was = ACM_GetStream(has)) == NULL)
381 return MMSYSERR_INVALHANDLE;
382 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
383 return MMSYSERR_INVALPARAM;
385 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
386 return ACMERR_UNPREPARED;
388 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
389 * size. some fields are private to msacm internals, and are exposed
390 * in ACMSTREAMHEADER in the dwReservedDriver array
392 padsh = (PACMDRVSTREAMHEADER)pash;
394 /* check that pointers have not been modified */
395 if (padsh->pbPreparedSrc != padsh->pbSrc ||
396 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
397 padsh->pbPreparedDst != padsh->pbDst ||
398 padsh->cbPreparedDstLength < padsh->cbDstLength) {
399 return MMSYSERR_INVALPARAM;
402 padsh->fdwConvert = fdwUnprepare;
404 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
405 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
406 ret = MMSYSERR_NOERROR;
407 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
409 TRACE("=> (%d)\n", ret);
410 return ret;