Call IShellExecuteHook interface for ShellExecute() calls with ID
[wine/multimedia.git] / dlls / msacm / stream.c
blob5c427ec62d4a4488a7457449f1d0e19091d50df2
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 /*
4 * MSACM32 library
6 * Copyright 1998 Patrik Stridvall
7 * 1999 Eric Pouech
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
24 /* TODO
25 * + asynchronous conversion is not implemented
26 * + callback/notification
27 * * acmStreamMessage
28 * + properly close ACM streams
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "wine/debug.h"
37 #include "mmsystem.h"
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "msacmdrv.h"
41 #include "wineacm.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
45 static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
47 TRACE("(%p)\n", has);
49 return (PWINE_ACMSTREAM)has;
52 /***********************************************************************
53 * acmStreamClose (MSACM32.@)
55 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
57 PWINE_ACMSTREAM was;
58 MMRESULT ret;
60 TRACE("(%p, %ld)\n", has, fdwClose);
62 if ((was = ACM_GetStream(has)) == NULL) {
63 WARN("invalid handle\n");
64 return MMSYSERR_INVALHANDLE;
66 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
67 if (ret == MMSYSERR_NOERROR) {
68 if (was->hAcmDriver)
69 acmDriverClose(was->hAcmDriver, 0L);
70 HeapFree(MSACM_hHeap, 0, was);
72 TRACE("=> (%d)\n", ret);
73 return ret;
76 /***********************************************************************
77 * acmStreamConvert (MSACM32.@)
79 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
80 DWORD fdwConvert)
82 PWINE_ACMSTREAM was;
83 MMRESULT ret = MMSYSERR_NOERROR;
84 PACMDRVSTREAMHEADER padsh;
86 TRACE("(%p, %p, %ld)\n", has, pash, fdwConvert);
88 if ((was = ACM_GetStream(has)) == NULL) {
89 WARN("invalid handle\n");
90 return MMSYSERR_INVALHANDLE;
92 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
93 WARN("invalid parameter\n");
94 return MMSYSERR_INVALPARAM;
96 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
97 WARN("unprepared header\n");
98 return ACMERR_UNPREPARED;
101 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
102 * size. some fields are private to msacm internals, and are exposed
103 * in ACMSTREAMHEADER in the dwReservedDriver array
105 padsh = (PACMDRVSTREAMHEADER)pash;
107 /* check that pointers have not been modified */
108 if (padsh->pbPreparedSrc != padsh->pbSrc ||
109 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
110 padsh->pbPreparedDst != padsh->pbDst ||
111 padsh->cbPreparedDstLength < padsh->cbDstLength) {
112 WARN("invalid parameter\n");
113 return MMSYSERR_INVALPARAM;
116 padsh->fdwConvert = fdwConvert;
118 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
119 if (ret == MMSYSERR_NOERROR) {
120 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
122 TRACE("=> (%d)\n", ret);
123 return ret;
126 /***********************************************************************
127 * acmStreamMessage (MSACM32.@)
129 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
130 LPARAM lParam2)
132 FIXME("(%p, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
133 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
134 return MMSYSERR_ERROR;
137 /***********************************************************************
138 * acmStreamOpen (MSACM32.@)
140 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
141 PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
142 DWORD dwInstance, DWORD fdwOpen)
144 PWINE_ACMSTREAM was;
145 PWINE_ACMDRIVER wad;
146 MMRESULT ret;
147 int wfxSrcSize;
148 int wfxDstSize;
149 WAVEFORMATEX wfxSrc, wfxDst;
151 TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n",
152 phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
154 /* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
155 * WAVEFORMATEX so don't use them directly when not sure */
156 if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) {
157 memcpy(&wfxSrc, pwfxSrc, sizeof(PCMWAVEFORMAT));
158 wfxSrc.wBitsPerSample = pwfxSrc->wBitsPerSample;
159 wfxSrc.cbSize = 0;
160 pwfxSrc = &wfxSrc;
163 if (pwfxDst->wFormatTag == WAVE_FORMAT_PCM) {
164 memcpy(&wfxDst, pwfxDst, sizeof(PCMWAVEFORMAT));
165 wfxDst.wBitsPerSample = pwfxDst->wBitsPerSample;
166 wfxDst.cbSize = 0;
167 pwfxDst = &wfxDst;
170 TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
171 pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
172 pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
174 TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
175 pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
176 pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
178 /* (WS) In query mode, phas should be NULL. If it is not, then instead
179 * of returning an error we are making sure it is NULL, preventing some
180 * applications that pass garbage for phas from crashing.
182 if (fdwOpen & ACM_STREAMOPENF_QUERY) phas = NULL;
184 if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) {
185 WARN("invalid parameter\n");
186 return MMSYSERR_INVALPARAM;
189 wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
190 if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
191 if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
193 was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize +
194 ((pwfltr) ? sizeof(WAVEFILTER) : 0));
195 if (was == NULL) {
196 WARN("no memory\n");
197 return MMSYSERR_NOMEM;
200 was->drvInst.cbStruct = sizeof(was->drvInst);
201 was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
202 memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
203 was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
204 memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
205 if (pwfltr) {
206 was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
207 memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
208 } else {
209 was->drvInst.pwfltr = NULL;
211 was->drvInst.dwCallback = dwCallback;
212 was->drvInst.dwInstance = dwInstance;
213 was->drvInst.fdwOpen = fdwOpen;
214 was->drvInst.fdwDriver = 0L;
215 was->drvInst.dwDriver = 0L;
216 /* real value will be stored once ACMDM_STREAM_OPEN succeeds */
217 was->drvInst.has = 0L;
219 if (had) {
220 if (!(wad = MSACM_GetDriver(had))) {
221 ret = MMSYSERR_INVALPARAM;
222 goto errCleanUp;
225 was->obj.dwType = WINE_ACMOBJ_STREAM;
226 was->obj.pACMDriverID = wad->obj.pACMDriverID;
227 was->pDrv = wad;
228 was->hAcmDriver = 0; /* not to close it in acmStreamClose */
230 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
231 if (ret != MMSYSERR_NOERROR)
232 goto errCleanUp;
233 } else {
234 PWINE_ACMDRIVERID wadi;
236 ret = ACMERR_NOTPOSSIBLE;
237 for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
238 if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
239 !MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
240 !MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
241 continue;
242 ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
243 if (ret != MMSYSERR_NOERROR)
244 continue;
245 if ((wad = MSACM_GetDriver(had)) != 0) {
246 was->obj.dwType = WINE_ACMOBJ_STREAM;
247 was->obj.pACMDriverID = wad->obj.pACMDriverID;
248 was->pDrv = wad;
249 was->hAcmDriver = had;
251 ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
252 TRACE("%s => %08x\n", debugstr_w(wadi->pszDriverAlias), ret);
253 if (ret == MMSYSERR_NOERROR) {
254 if (fdwOpen & ACM_STREAMOPENF_QUERY) {
255 acmDriverClose(had, 0L);
257 break;
260 /* no match, close this acm driver and try next one */
261 acmDriverClose(had, 0L);
263 if (ret != MMSYSERR_NOERROR) {
264 ret = ACMERR_NOTPOSSIBLE;
265 goto errCleanUp;
268 ret = MMSYSERR_NOERROR;
269 was->drvInst.has = (HACMSTREAM)was;
270 if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
271 if (phas)
272 *phas = (HACMSTREAM)was;
273 TRACE("=> (%d)\n", ret);
274 return ret;
276 errCleanUp:
277 if (phas)
278 *phas = NULL;
279 HeapFree(MSACM_hHeap, 0, was);
280 TRACE("=> (%d)\n", ret);
281 return ret;
285 /***********************************************************************
286 * acmStreamPrepareHeader (MSACM32.@)
288 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
289 DWORD fdwPrepare)
291 PWINE_ACMSTREAM was;
292 MMRESULT ret = MMSYSERR_NOERROR;
293 PACMDRVSTREAMHEADER padsh;
295 TRACE("(%p, %p, %ld)\n", has, pash, fdwPrepare);
297 if ((was = ACM_GetStream(has)) == NULL) {
298 WARN("invalid handle\n");
299 return MMSYSERR_INVALHANDLE;
301 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
302 WARN("invalid parameter\n");
303 return MMSYSERR_INVALPARAM;
305 if (fdwPrepare)
306 ret = MMSYSERR_INVALFLAG;
308 if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
309 return MMSYSERR_NOERROR;
311 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
312 * size. some fields are private to msacm internals, and are exposed
313 * in ACMSTREAMHEADER in the dwReservedDriver array
315 padsh = (PACMDRVSTREAMHEADER)pash;
317 padsh->fdwConvert = fdwPrepare;
318 padsh->padshNext = NULL;
319 padsh->fdwDriver = padsh->dwDriver = 0L;
321 padsh->fdwPrepared = 0;
322 padsh->dwPrepared = 0;
323 padsh->pbPreparedSrc = 0;
324 padsh->cbPreparedSrcLength = 0;
325 padsh->pbPreparedDst = 0;
326 padsh->cbPreparedDstLength = 0;
328 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
329 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
330 ret = MMSYSERR_NOERROR;
331 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
332 padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
333 padsh->fdwPrepared = padsh->fdwStatus;
334 padsh->dwPrepared = 0;
335 padsh->pbPreparedSrc = padsh->pbSrc;
336 padsh->cbPreparedSrcLength = padsh->cbSrcLength;
337 padsh->pbPreparedDst = padsh->pbDst;
338 padsh->cbPreparedDstLength = padsh->cbDstLength;
339 } else {
340 padsh->fdwPrepared = 0;
341 padsh->dwPrepared = 0;
342 padsh->pbPreparedSrc = 0;
343 padsh->cbPreparedSrcLength = 0;
344 padsh->pbPreparedDst = 0;
345 padsh->cbPreparedDstLength = 0;
347 TRACE("=> (%d)\n", ret);
348 return ret;
351 /***********************************************************************
352 * acmStreamReset (MSACM32.@)
354 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
356 PWINE_ACMSTREAM was;
357 MMRESULT ret = MMSYSERR_NOERROR;
359 TRACE("(%p, %ld)\n", has, fdwReset);
361 if (fdwReset) {
362 WARN("invalid flag\n");
363 ret = MMSYSERR_INVALFLAG;
364 } else if ((was = ACM_GetStream(has)) == NULL) {
365 WARN("invalid handle\n");
366 return MMSYSERR_INVALHANDLE;
367 } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
368 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
370 TRACE("=> (%d)\n", ret);
371 return ret;
374 /***********************************************************************
375 * acmStreamSize (MSACM32.@)
377 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
378 LPDWORD pdwOutputBytes, DWORD fdwSize)
380 PWINE_ACMSTREAM was;
381 ACMDRVSTREAMSIZE adss;
382 MMRESULT ret;
384 TRACE("(%p, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
386 if ((was = ACM_GetStream(has)) == NULL) {
387 WARN("invalid handle\n");
388 return MMSYSERR_INVALHANDLE;
390 if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
391 WARN("invalid flag\n");
392 return MMSYSERR_INVALFLAG;
395 *pdwOutputBytes = 0L;
397 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
398 case ACM_STREAMSIZEF_DESTINATION:
399 adss.cbDstLength = cbInput;
400 adss.cbSrcLength = 0;
401 break;
402 case ACM_STREAMSIZEF_SOURCE:
403 adss.cbSrcLength = cbInput;
404 adss.cbDstLength = 0;
405 break;
406 default:
407 WARN("invalid flag\n");
408 return MMSYSERR_INVALFLAG;
411 adss.cbStruct = sizeof(adss);
412 adss.fdwSize = fdwSize;
413 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
414 (DWORD)&was->drvInst, (DWORD)&adss);
415 if (ret == MMSYSERR_NOERROR) {
416 switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
417 case ACM_STREAMSIZEF_DESTINATION:
418 *pdwOutputBytes = adss.cbSrcLength;
419 break;
420 case ACM_STREAMSIZEF_SOURCE:
421 *pdwOutputBytes = adss.cbDstLength;
422 break;
425 TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
426 return ret;
429 /***********************************************************************
430 * acmStreamUnprepareHeader (MSACM32.@)
432 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
433 DWORD fdwUnprepare)
435 PWINE_ACMSTREAM was;
436 MMRESULT ret = MMSYSERR_NOERROR;
437 PACMDRVSTREAMHEADER padsh;
439 TRACE("(%p, %p, %ld)\n", has, pash, fdwUnprepare);
441 if ((was = ACM_GetStream(has)) == NULL) {
442 WARN("invalid handle\n");
443 return MMSYSERR_INVALHANDLE;
445 if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
446 WARN("invalid parameter\n");
447 return MMSYSERR_INVALPARAM;
449 if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
450 WARN("unprepared header\n");
451 return ACMERR_UNPREPARED;
454 /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
455 * size. some fields are private to msacm internals, and are exposed
456 * in ACMSTREAMHEADER in the dwReservedDriver array
458 padsh = (PACMDRVSTREAMHEADER)pash;
460 /* check that pointers have not been modified */
461 if (padsh->pbPreparedSrc != padsh->pbSrc ||
462 padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
463 padsh->pbPreparedDst != padsh->pbDst ||
464 padsh->cbPreparedDstLength < padsh->cbDstLength) {
465 WARN("invalid parameter\n");
466 return MMSYSERR_INVALPARAM;
469 padsh->fdwConvert = fdwUnprepare;
471 ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
472 if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
473 ret = MMSYSERR_NOERROR;
474 padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
476 TRACE("=> (%d)\n", ret);
477 return ret;