1 /**************************************************************************
2 
3 
4   This file will contain an interface to ACM drivers.
5   Its content will be based mainly on wine/dlls/msacm32
6   actually, for audio decompression only the following functions
7   are needed:
8 
9   acmStreamOpen ( takes formats of src and dest, returns stream handle )
10   acmStreamPrepareHeader ( takes stream handler and info on data )
11   acmStreamConvert ( the same as PrepareHeader )
12   acmStreamUnprepareHeader
13   acmStreamClose
14   acmStreamSize
15   maybe acmStreamReset
16 
17   In future I'll also add functions for format enumeration,
18   but not right now.
19 
20 
21 ***************************************************************************/
22 #include "config.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "winbase.h"
29 #include "windef.h"
30 #include "winuser.h"
31 #include "vfw.h"
32 #include "winestring.h"
33 #include "driver.h"
34 #include "winerror.h"
35 #include "msacm.h"
36 #include "msacmdrv.h"
37 #include "wineacm.h"
38 #include "ext.h"
39 #include "debugtools.h"
40 
41 #include "driver.h"
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #pragma pack(1)
47 #define OpenDriverA DrvOpen
48 #define CloseDriver DrvClose
49 
50 #pragma pack(1)
51 
ACM_GetStream(HACMSTREAM has)52 static PWINE_ACMSTREAM	ACM_GetStream(HACMSTREAM has)
53 {
54     return (PWINE_ACMSTREAM)has;
55 }
56 
57 /***********************************************************************
58  *           acmDriverAddA (MSACM32.2)
59  */
acmDriverAddA(PHACMDRIVERID phadid,HINSTANCE hinstModule,LPARAM lParam,DWORD dwPriority,DWORD fdwAdd)60 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
61 			      LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
62 {
63     if (!phadid)
64 	return MMSYSERR_INVALPARAM;
65 
66     /* Check if any unknown flags */
67     if (fdwAdd &
68 	~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
69 	  ACM_DRIVERADDF_GLOBAL))
70 	return MMSYSERR_INVALFLAG;
71 
72     /* Check if any incompatible flags */
73     if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) &&
74 	(fdwAdd & ACM_DRIVERADDF_NOTIFYHWND))
75 	return MMSYSERR_INVALFLAG;
76 
77     /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a
78      * LoadDriver on it, to be sure we can call SendDriverMessage on the
79      * hDrvr handle.
80      */
81     *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, hinstModule);
82 
83     /* FIXME: lParam, dwPriority and fdwAdd ignored */
84     (void)lParam;
85     (void)dwPriority;
86 
87     return MMSYSERR_NOERROR;
88 }
89 
90 /***********************************************************************
91  *           acmDriverClose (MSACM32.4)
92  */
acmDriverClose(HACMDRIVER had,DWORD fdwClose)93 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
94 {
95     PWINE_ACMDRIVER  p;
96     PWINE_ACMDRIVER* tp;
97 
98     if (fdwClose)
99 	return MMSYSERR_INVALFLAG;
100 
101     p = MSACM_GetDriver(had);
102     if (!p)
103 	return MMSYSERR_INVALHANDLE;
104 
105     for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
106 	if (*tp == p) {
107 	    *tp = (*tp)->pNextACMDriver;
108 	    break;
109 	}
110     }
111 
112     if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
113 	CloseDriver(p->hDrvr);
114 
115     HeapFree(MSACM_hHeap, 0, p);
116 
117     return MMSYSERR_NOERROR;
118 }
119 
120 /***********************************************************************
121  *           acmDriverEnum (MSACM32.7)
122  */
acmDriverEnum(ACMDRIVERENUMCB fnCallback,DWORD dwInstance,DWORD fdwEnum)123 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
124 {
125     PWINE_ACMDRIVERID	p;
126     DWORD		fdwSupport;
127 
128     if (!fnCallback) {
129 	return MMSYSERR_INVALPARAM;
130     }
131 
132     if (fdwEnum && ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
133 	return MMSYSERR_INVALFLAG;
134     }
135 
136     for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) {
137 	fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
138 	if (!p->bEnabled) {
139 	    if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
140 		fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
141 	    else
142 		continue;
143 	}
144 	(*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport);
145     }
146 
147     return MMSYSERR_NOERROR;
148 }
149 
150 /***********************************************************************
151  *           acmDriverID (MSACM32.8)
152  */
acmDriverID(HACMOBJ hao,PHACMDRIVERID phadid,DWORD fdwDriverID)153 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
154 {
155     PWINE_ACMOBJ pao;
156 
157     pao = MSACM_GetObj(hao);
158     if (!pao)
159 	return MMSYSERR_INVALHANDLE;
160 
161     if (!phadid)
162 	return MMSYSERR_INVALPARAM;
163 
164     if (fdwDriverID)
165 	return MMSYSERR_INVALFLAG;
166 
167     *phadid = (HACMDRIVERID) pao->pACMDriverID;
168 
169     return MMSYSERR_NOERROR;
170 }
171 
172 /***********************************************************************
173  *           acmDriverMessage (MSACM32.9)
174  * FIXME
175  *   Not implemented
176  */
acmDriverMessage(HACMDRIVER had,UINT uMsg,LPARAM lParam1,LPARAM lParam2)177 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
178 {
179     PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
180     if (!pad)
181 	return MMSYSERR_INVALPARAM;
182 
183     /* FIXME: Check if uMsg legal */
184 
185     if (!SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2))
186 	return MMSYSERR_NOTSUPPORTED;
187 
188     return MMSYSERR_NOERROR;
189 }
190 
191 
192 /***********************************************************************
193  *           acmDriverOpen (MSACM32.10)
194  */
acmDriverOpen(PHACMDRIVER phad,HACMDRIVERID hadid,DWORD fdwOpen)195 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
196 {
197     PWINE_ACMDRIVERID	padid;
198     PWINE_ACMDRIVER	pad;
199     ICOPEN		icopen;
200     /* HDRVR		hdrv; -- not used */
201 
202 
203 
204     TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
205 
206     if (!phad)
207 	return MMSYSERR_INVALPARAM;
208 
209     padid = MSACM_GetDriverID(hadid);
210     if (!padid)
211 	return MMSYSERR_INVALHANDLE;
212 
213     if (fdwOpen)
214 	return MMSYSERR_INVALFLAG;
215 
216     pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
217     if (!pad) return MMSYSERR_NOMEM;
218 
219     pad->obj.pACMDriverID = padid;
220     icopen.fccType		= mmioFOURCC('a', 'u', 'd', 'c');
221     icopen.fccHandler		= (long)padid->pszFileName;
222     icopen.dwSize		= sizeof(ICOPEN);
223     icopen.dwFlags		= 0;
224 
225     icopen.pV1Reserved = padid->pszFileName;
226     if (!padid->hInstModule)
227 	pad->hDrvr = OpenDriverA((long)&icopen);
228     else
229 	pad->hDrvr = padid->hInstModule;
230 
231     if (!pad->hDrvr) {
232 	HeapFree(MSACM_hHeap, 0, pad);
233 	return MMSYSERR_ERROR;
234     }
235 
236     pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
237 
238     /* insert new pad at beg of list */
239     pad->pNextACMDriver = padid->pACMDriverList;
240     padid->pACMDriverList = pad;
241 
242     /* FIXME: Create a WINE_ACMDRIVER32 */
243     *phad = (HACMDRIVER)pad;
244 
245     return MMSYSERR_NOERROR;
246 }
247 
248 /***********************************************************************
249  *           acmDriverRemove (MSACM32.12)
250  */
acmDriverRemove(HACMDRIVERID hadid,DWORD fdwRemove)251 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
252 {
253     PWINE_ACMDRIVERID padid;
254 
255     padid = MSACM_GetDriverID(hadid);
256     if (!padid)
257 	return MMSYSERR_INVALHANDLE;
258 
259     if (fdwRemove)
260 	return MMSYSERR_INVALFLAG;
261 
262     MSACM_UnregisterDriver(padid);
263 
264     return MMSYSERR_NOERROR;
265 }
266 
267 
268 
269 /**********************************************************************/
270 
271 HANDLE MSACM_hHeap = (HANDLE) NULL;
272 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
273 PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
274 
275 /***********************************************************************
276  *           MSACM_RegisterDriver32()
277  */
MSACM_RegisterDriver(const char * pszFileName,WORD wFormatTag,HINSTANCE hinstModule)278 PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName,
279 				       WORD wFormatTag,
280 				       HINSTANCE hinstModule)
281 {
282     PWINE_ACMDRIVERID padid;
283 
284     TRACE("('%s', '%x', 0x%08x)\n", pszFileName, wFormatTag, hinstModule);
285 
286     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
287     padid->pszFileName = (char*)malloc(strlen(pszFileName)+1);
288     strcpy(padid->pszFileName, pszFileName);
289 //    1~strdup(pszDriverAlias);
290     padid->wFormatTag = wFormatTag;
291     padid->hInstModule = hinstModule;
292     padid->bEnabled = TRUE;
293     padid->pACMDriverList = NULL;
294     padid->pNextACMDriverID = NULL;
295     padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
296     if (MSACM_pLastACMDriverID)
297 	MSACM_pLastACMDriverID->pNextACMDriverID = padid;
298     MSACM_pLastACMDriverID = padid;
299     if (!MSACM_pFirstACMDriverID)
300 	MSACM_pFirstACMDriverID = padid;
301 
302     return padid;
303 }
304 
305 
306 /***********************************************************************
307  *           MSACM_UnregisterDriver32()
308  */
MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)309 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
310 {
311     PWINE_ACMDRIVERID pNextACMDriverID;
312 
313     while (p->pACMDriverList)
314 	acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
315 
316     if (p->pszFileName)
317 	free(p->pszFileName);
318 
319     if (p == MSACM_pFirstACMDriverID)
320 	MSACM_pFirstACMDriverID = p->pNextACMDriverID;
321     if (p == MSACM_pLastACMDriverID)
322 	MSACM_pLastACMDriverID = p->pPrevACMDriverID;
323 
324     if (p->pPrevACMDriverID)
325 	p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
326     if (p->pNextACMDriverID)
327 	p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
328 
329     pNextACMDriverID = p->pNextACMDriverID;
330 
331     HeapFree(MSACM_hHeap, 0, p);
332 
333     return pNextACMDriverID;
334 }
335 
336 /***********************************************************************
337  *           MSACM_UnregisterAllDrivers32()
338  * FIXME
339  *   Where should this function be called?
340  */
MSACM_UnregisterAllDrivers(void)341 void MSACM_UnregisterAllDrivers(void)
342 {
343     PWINE_ACMDRIVERID p;
344 
345     for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p));
346 }
347 
348 /***********************************************************************
349  *           MSACM_GetDriverID32()
350  */
MSACM_GetDriverID(HACMDRIVERID hDriverID)351 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
352 {
353     return (PWINE_ACMDRIVERID)hDriverID;
354 }
355 
356 /***********************************************************************
357  *           MSACM_GetDriver32()
358  */
MSACM_GetDriver(HACMDRIVER hDriver)359 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
360 {
361     return (PWINE_ACMDRIVER)hDriver;
362 }
363 
364 /***********************************************************************
365  *           MSACM_GetObj32()
366  */
MSACM_GetObj(HACMOBJ hObj)367 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj)
368 {
369     return (PWINE_ACMOBJ)hObj;
370 }
371 
372 
373 
374 /***********************************************************************
375  *           acmStreamOpen (MSACM32.40)
376  */
acmStreamOpen(PHACMSTREAM phas,HACMDRIVER had,PWAVEFORMATEX pwfxSrc,PWAVEFORMATEX pwfxDst,PWAVEFILTER pwfltr,DWORD dwCallback,DWORD dwInstance,DWORD fdwOpen)377 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
378 			      PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
379 			      DWORD dwInstance, DWORD fdwOpen)
380 {
381     PWINE_ACMSTREAM	was;
382     PWINE_ACMDRIVER	wad;
383     MMRESULT		ret;
384     int			wfxSrcSize;
385     int			wfxDstSize;
386 
387     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
388 	  phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
389 
390     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
391 	  pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
392 	  pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
393 
394     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
395 	  pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
396 	  pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
397 
398 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
399     wfxSrcSize = SIZEOF_WFX(pwfxSrc);
400     wfxDstSize = SIZEOF_WFX(pwfxDst);
401 #undef SIZEOF_WFX
402 
403     was = (PWINE_ACMSTREAM) HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
404     if (was == NULL)
405 	return MMSYSERR_NOMEM;
406     was->drvInst.cbStruct = sizeof(was->drvInst);
407     was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
408     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
409     // LHACM is checking for 0x1
410     // but if this will not help
411     // was->drvInst.pwfxSrc->wFormatTag = 1;
412     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
413     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
414     if (pwfltr) {
415 	was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
416 	memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
417     } else {
418 	was->drvInst.pwfltr = NULL;
419     }
420     was->drvInst.dwCallback = dwCallback;
421     was->drvInst.dwInstance = dwInstance;
422     was->drvInst.fdwOpen = fdwOpen;
423     was->drvInst.fdwDriver = 0L;
424     was->drvInst.dwDriver = 0L;
425     was->drvInst.has = (HACMSTREAM)was;
426 
427     if (had) {
428 	if (!(wad = MSACM_GetDriver(had))) {
429 	    ret = MMSYSERR_INVALPARAM;
430 	    goto errCleanUp;
431 	}
432 
433 	was->obj.pACMDriverID = wad->obj.pACMDriverID;
434 	was->pDrv = wad;
435 	was->hAcmDriver = 0; /* not to close it in acmStreamClose */
436 
437 	ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
438 	if (ret != MMSYSERR_NOERROR)
439 	    goto errCleanUp;
440     } else {
441 	PWINE_ACMDRIVERID wadi;
442 	/* short drv_tag; -- not used */
443 	ret = ACMERR_NOTPOSSIBLE;
444 /*	if(pwfxSrc->wFormatTag==1)//compression
445 	    drv_tag=pwfxDst->wFormatTag;
446 	    else
447 	    if(pwfxDst->wFormatTag==1)//decompression
448 		drv_tag=pwfxSrc->wFormatTag;
449 		else
450 		goto errCleanUp;
451 
452 	    ret=acmDriverOpen2(drv_tag);
453 	    if (ret == MMSYSERR_NOERROR) {
454 		if ((wad = MSACM_GetDriver(had)) != 0) {
455 		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
456 		    was->pDrv = wad;
457 		    was->hAcmDriver = had;
458 
459 		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
460 		    if (ret == MMSYSERR_NOERROR) {
461 			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
462 			    acmDriverClose(had, 0L);
463 			}
464 			break;
465 		    }
466 		}
467 		acmDriverClose(had, 0L);*/
468 	//if(MSACM_pFirstACMDriverID==NULL)
469 	//    MSACM_RegisterAllDrivers();
470 
471 	for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID)
472 	{
473 	    /* Check Format */
474 	    if ((int)wadi->wFormatTag != (int)pwfxSrc->wFormatTag) continue;
475 
476 	    ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
477 	    if (ret == MMSYSERR_NOERROR) {
478 		if ((wad = MSACM_GetDriver(had)) != 0) {
479 		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
480 		    was->pDrv = wad;
481 		    was->hAcmDriver = had;
482 
483 		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
484 		    //lhacm - crash printf("RETOPEN %d\n", ret);
485                     //ret = 0;
486 		    if (ret == MMSYSERR_NOERROR) {
487 			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
488 			    acmDriverClose(had, 0L);
489 			}
490 			break;
491 		    }
492 		}
493 		// no match, close this acm driver and try next one
494 		acmDriverClose(had, 0L);
495 	    }
496 	}
497 	if (ret != MMSYSERR_NOERROR) {
498 	    ret = ACMERR_NOTPOSSIBLE;
499 	    goto errCleanUp;
500 	}
501     }
502     ret = MMSYSERR_NOERROR;
503     if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
504 	if (phas)
505 	    *phas = (HACMSTREAM)was;
506 	TRACE("=> (%d)\n", ret);
507 	CodecAlloc();
508 	return ret;
509     }
510 errCleanUp:
511     if (phas)
512 	*phas = (HACMSTREAM)0;
513     HeapFree(MSACM_hHeap, 0, was);
514     TRACE("=> (%d)\n", ret);
515     return ret;
516 }
517 
518 
acmStreamClose(HACMSTREAM has,DWORD fdwClose)519 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
520 {
521     PWINE_ACMSTREAM	was;
522     MMRESULT		ret;
523 
524     TRACE("(0x%08x, %ld)\n", has, fdwClose);
525 
526     if ((was = ACM_GetStream(has)) == NULL) {
527 	return MMSYSERR_INVALHANDLE;
528     }
529     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
530     if (ret == MMSYSERR_NOERROR) {
531 	if (was->hAcmDriver)
532 	    acmDriverClose(was->hAcmDriver, 0L);
533 	HeapFree(MSACM_hHeap, 0, was);
534 	CodecRelease();
535     }
536     TRACE("=> (%d)\n", ret);
537     return ret;
538 }
539 
540 /***********************************************************************
541  *           acmStreamConvert (MSACM32.38)
542  */
acmStreamConvert(HACMSTREAM has,PACMSTREAMHEADER pash,DWORD fdwConvert)543 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
544 				 DWORD fdwConvert)
545 {
546     PWINE_ACMSTREAM	was;
547     MMRESULT		ret = MMSYSERR_NOERROR;
548     PACMDRVSTREAMHEADER	padsh;
549 
550     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
551 
552     if ((was = ACM_GetStream(has)) == NULL)
553 	return MMSYSERR_INVALHANDLE;
554     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
555 	return MMSYSERR_INVALPARAM;
556 
557     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
558 	return ACMERR_UNPREPARED;
559 
560     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
561      * size. some fields are private to msacm internals, and are exposed
562      * in ACMSTREAMHEADER in the dwReservedDriver array
563      */
564     padsh = (PACMDRVSTREAMHEADER)pash;
565 
566     /* check that pointers have not been modified */
567     if (padsh->pbPreparedSrc != padsh->pbSrc ||
568 	padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
569 	padsh->pbPreparedDst != padsh->pbDst ||
570 	padsh->cbPreparedDstLength < padsh->cbDstLength) {
571 	return MMSYSERR_INVALPARAM;
572     }
573 
574     padsh->fdwConvert = fdwConvert;
575 
576     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
577     if (ret == MMSYSERR_NOERROR) {
578 	padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
579     }
580     TRACE("=> (%d)\n", ret);
581     return ret;
582 }
583 
584 
585 /***********************************************************************
586  *           acmStreamPrepareHeader (MSACM32.41)
587  */
acmStreamPrepareHeader(HACMSTREAM has,PACMSTREAMHEADER pash,DWORD fdwPrepare)588 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
589 				       DWORD fdwPrepare)
590 {
591     PWINE_ACMSTREAM	was;
592     MMRESULT		ret = MMSYSERR_NOERROR;
593     PACMDRVSTREAMHEADER	padsh;
594 
595     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
596 
597     if ((was = ACM_GetStream(has)) == NULL)
598 	return MMSYSERR_INVALHANDLE;
599     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
600 	return MMSYSERR_INVALPARAM;
601     if (fdwPrepare)
602 	ret = MMSYSERR_INVALFLAG;
603 
604     if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
605 	return MMSYSERR_NOERROR;
606 
607     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
608      * size. some fields are private to msacm internals, and are exposed
609      * in ACMSTREAMHEADER in the dwReservedDriver array
610      */
611     padsh = (PACMDRVSTREAMHEADER)pash;
612 
613     padsh->fdwConvert = fdwPrepare;
614     padsh->padshNext = NULL;
615     padsh->fdwDriver = padsh->dwDriver = 0L;
616 
617     padsh->fdwPrepared = 0;
618     padsh->dwPrepared = 0;
619     padsh->pbPreparedSrc = 0;
620     padsh->cbPreparedSrcLength = 0;
621     padsh->pbPreparedDst = 0;
622     padsh->cbPreparedDstLength = 0;
623 
624     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
625     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
626 	ret = MMSYSERR_NOERROR;
627 	padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
628 	padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
629 	padsh->fdwPrepared = padsh->fdwStatus;
630 	padsh->dwPrepared = 0;
631 	padsh->pbPreparedSrc = padsh->pbSrc;
632 	padsh->cbPreparedSrcLength = padsh->cbSrcLength;
633 	padsh->pbPreparedDst = padsh->pbDst;
634 	padsh->cbPreparedDstLength = padsh->cbDstLength;
635     } else {
636 	padsh->fdwPrepared = 0;
637 	padsh->dwPrepared = 0;
638 	padsh->pbPreparedSrc = 0;
639 	padsh->cbPreparedSrcLength = 0;
640 	padsh->pbPreparedDst = 0;
641 	padsh->cbPreparedDstLength = 0;
642     }
643     TRACE("=> (%d)\n", ret);
644     return ret;
645 }
646 
647 /***********************************************************************
648  *           acmStreamReset (MSACM32.42)
649  */
acmStreamReset(HACMSTREAM has,DWORD fdwReset)650 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
651 {
652     PWINE_ACMSTREAM	was;
653     MMRESULT		ret = MMSYSERR_NOERROR;
654 
655     TRACE("(0x%08x, %ld)\n", has, fdwReset);
656 
657     if (fdwReset) {
658 	ret = MMSYSERR_INVALFLAG;
659     } else if ((was = ACM_GetStream(has)) == NULL) {
660 	return MMSYSERR_INVALHANDLE;
661     } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
662 	ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
663     }
664     TRACE("=> (%d)\n", ret);
665     return ret;
666 }
667 
668 /***********************************************************************
669  *           acmStreamSize (MSACM32.43)
670  */
acmStreamSize(HACMSTREAM has,DWORD cbInput,LPDWORD pdwOutputBytes,DWORD fdwSize)671 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
672 			      LPDWORD pdwOutputBytes, DWORD fdwSize)
673 {
674     PWINE_ACMSTREAM	was;
675     ACMDRVSTREAMSIZE	adss;
676     MMRESULT		ret;
677 
678     TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
679 
680     if ((was = ACM_GetStream(has)) == NULL) {
681 	return MMSYSERR_INVALHANDLE;
682     }
683     if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
684 	return MMSYSERR_INVALFLAG;
685     }
686 
687     *pdwOutputBytes = 0L;
688 
689     switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
690     case ACM_STREAMSIZEF_DESTINATION:
691 	adss.cbDstLength = cbInput;
692 	adss.cbSrcLength = 0;
693 	break;
694     case ACM_STREAMSIZEF_SOURCE:
695 	adss.cbSrcLength = cbInput;
696 	adss.cbDstLength = 0;
697 	break;
698     default:
699 	return MMSYSERR_INVALFLAG;
700     }
701 
702     adss.cbStruct = sizeof(adss);
703     adss.fdwSize = fdwSize;
704     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE,
705 			    (DWORD)&was->drvInst, (DWORD)&adss);
706     if (ret == MMSYSERR_NOERROR) {
707 	switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
708 	case ACM_STREAMSIZEF_DESTINATION:
709 	    *pdwOutputBytes = adss.cbSrcLength;
710 	    break;
711 	case ACM_STREAMSIZEF_SOURCE:
712 	    *pdwOutputBytes = adss.cbDstLength;
713 	    break;
714 	}
715     }
716     TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
717     return ret;
718 }
719 
720 /***********************************************************************
721  *           acmStreamUnprepareHeader (MSACM32.44)
722  */
acmStreamUnprepareHeader(HACMSTREAM has,PACMSTREAMHEADER pash,DWORD fdwUnprepare)723 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
724 					 DWORD fdwUnprepare)
725 {
726     PWINE_ACMSTREAM	was;
727     MMRESULT		ret = MMSYSERR_NOERROR;
728     PACMDRVSTREAMHEADER	padsh;
729 
730     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
731 
732     if ((was = ACM_GetStream(has)) == NULL)
733 	return MMSYSERR_INVALHANDLE;
734     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
735 	return MMSYSERR_INVALPARAM;
736 
737     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
738 	return ACMERR_UNPREPARED;
739 
740     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
741      * size. some fields are private to msacm internals, and are exposed
742      * in ACMSTREAMHEADER in the dwReservedDriver array
743      */
744     padsh = (PACMDRVSTREAMHEADER)pash;
745 
746     /* check that pointers have not been modified */
747     if (padsh->pbPreparedSrc != padsh->pbSrc ||
748 	padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
749 	padsh->pbPreparedDst != padsh->pbDst ||
750 	padsh->cbPreparedDstLength < padsh->cbDstLength) {
751 	return MMSYSERR_INVALPARAM;
752     }
753 
754     padsh->fdwConvert = fdwUnprepare;
755 
756     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
757     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
758 	ret = MMSYSERR_NOERROR;
759 	padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
760     }
761     TRACE("=> (%d)\n", ret);
762     return ret;
763 }
764