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   Modified for use with MPlayer, detailed changelog at
21   http://svn.mplayerhq.hu/mplayer/trunk/
22 
23 ***************************************************************************/
24 #include "config.h"
25 #include "debug.h"
26 
27 #include "wine/winbase.h"
28 #include "wine/windef.h"
29 #include "wine/winuser.h"
30 #include "wine/vfw.h"
31 #include "wine/winestring.h"
32 #include "wine/driver.h"
33 #include "wine/winerror.h"
34 #include "wine/msacm.h"
35 #include "wine/msacmdrv.h"
36 #include "wineacm.h"
37 #ifndef __MINGW32__
38 #include "ext.h"
39 #endif
40 #include "drv.h"
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #pragma pack(1)
46 #define OpenDriverA DrvOpen
47 #define CloseDriver DrvClose
48 
ACM_GetStream(HACMSTREAM has)49 static inline PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
50 {
51     return (PWINE_ACMSTREAM)has;
52 }
53 
54 /***********************************************************************
55  *           acmDriverAddA (MSACM32.2)
56  */
acmDriverAddA(PHACMDRIVERID phadid,HINSTANCE hinstModule,LPARAM lParam,DWORD dwPriority,DWORD fdwAdd)57 MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
58 			      LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
59 {
60     if (!phadid)
61 	return MMSYSERR_INVALPARAM;
62 
63     /* Check if any unknown flags */
64     if (fdwAdd &
65 	~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
66 	  ACM_DRIVERADDF_GLOBAL))
67 	return MMSYSERR_INVALFLAG;
68 
69     /* Check if any incompatible flags */
70     if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) &&
71 	(fdwAdd & ACM_DRIVERADDF_NOTIFYHWND))
72 	return MMSYSERR_INVALFLAG;
73 
74     /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a
75      * LoadDriver on it, to be sure we can call SendDriverMessage on the
76      * hDrvr handle.
77      */
78     *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, 0, hinstModule);
79 
80     /* FIXME: lParam, dwPriority and fdwAdd ignored */
81 
82     return MMSYSERR_NOERROR;
83 }
84 
85 /***********************************************************************
86  *           acmDriverClose (MSACM32.4)
87  */
acmDriverClose(HACMDRIVER had,DWORD fdwClose)88 MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
89 {
90     PWINE_ACMDRIVER  p;
91     PWINE_ACMDRIVER* tp;
92 
93     if (fdwClose)
94 	return MMSYSERR_INVALFLAG;
95 
96     p = MSACM_GetDriver(had);
97     if (!p)
98 	return MMSYSERR_INVALHANDLE;
99 
100     for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
101 	if (*tp == p) {
102 	    *tp = (*tp)->pNextACMDriver;
103 	    break;
104 	}
105     }
106 
107     if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
108 	CloseDriver(p->hDrvr);
109 
110     HeapFree(MSACM_hHeap, 0, p);
111 
112     return MMSYSERR_NOERROR;
113 }
114 
115 /***********************************************************************
116  *           acmDriverEnum (MSACM32.7)
117  */
acmDriverEnum(ACMDRIVERENUMCB fnCallback,DWORD dwInstance,DWORD fdwEnum)118 MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
119 {
120     PWINE_ACMDRIVERID	p;
121     DWORD		fdwSupport;
122 
123     if (!fnCallback) {
124 	return MMSYSERR_INVALPARAM;
125     }
126 
127     if (fdwEnum && ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
128 	return MMSYSERR_INVALFLAG;
129     }
130 
131     for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) {
132 	fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
133 	if (!p->bEnabled) {
134 	    if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
135 		fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
136 	    else
137 		continue;
138 	}
139 	(*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport);
140     }
141 
142     return MMSYSERR_NOERROR;
143 }
144 
145 /***********************************************************************
146  *           acmDriverID (MSACM32.8)
147  */
acmDriverID(HACMOBJ hao,PHACMDRIVERID phadid,DWORD fdwDriverID)148 MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
149 {
150     PWINE_ACMOBJ pao;
151 
152     pao = MSACM_GetObj(hao);
153     if (!pao)
154 	return MMSYSERR_INVALHANDLE;
155 
156     if (!phadid)
157 	return MMSYSERR_INVALPARAM;
158 
159     if (fdwDriverID)
160 	return MMSYSERR_INVALFLAG;
161 
162     *phadid = (HACMDRIVERID) pao->pACMDriverID;
163 
164     return MMSYSERR_NOERROR;
165 }
166 
167 /***********************************************************************
168  *           acmDriverMessage (MSACM32.9)
169  * FIXME
170  *   Not implemented
171  */
acmDriverMessage(HACMDRIVER had,UINT uMsg,LPARAM lParam1,LPARAM lParam2)172 LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
173 {
174     PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
175     if (!pad)
176 	return MMSYSERR_INVALPARAM;
177 
178     /* FIXME: Check if uMsg legal */
179 
180     if (!SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2))
181 	return MMSYSERR_NOTSUPPORTED;
182 
183     return MMSYSERR_NOERROR;
184 }
185 
186 
187 /***********************************************************************
188  *           acmDriverOpen (MSACM32.10)
189  */
acmDriverOpen(PHACMDRIVER phad,HACMDRIVERID hadid,DWORD fdwOpen)190 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
191 {
192     PWINE_ACMDRIVERID	padid;
193     PWINE_ACMDRIVER	pad;
194     ICOPEN		icopen;
195 
196 
197     TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
198 
199     if (!phad)
200 	return MMSYSERR_INVALPARAM;
201 
202     padid = MSACM_GetDriverID(hadid);
203     if (!padid)
204 	return MMSYSERR_INVALHANDLE;
205 
206     if (fdwOpen)
207 	return MMSYSERR_INVALFLAG;
208 
209     pad = (PWINE_ACMDRIVER) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
210     if (!pad)
211 	return MMSYSERR_NOMEM;
212 
213     pad->obj.pACMDriverID = padid;
214     icopen.fccType		= mmioFOURCC('a', 'u', 'd', 'c');
215     icopen.fccHandler		= (long)padid->pszFileName;
216     icopen.dwSize		= sizeof(ICOPEN);
217     icopen.dwFlags		= 0;
218 
219     icopen.pV1Reserved = padid->pszFileName;
220     if (!padid->hInstModule)
221 	pad->hDrvr = OpenDriverA((long)&icopen);
222     else
223 	pad->hDrvr = padid->hInstModule;
224 
225     if (!pad->hDrvr) {
226 	HeapFree(MSACM_hHeap, 0, pad);
227 	return MMSYSERR_ERROR;
228     }
229 
230     pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
231 
232     /* insert new pad at beg of list */
233     pad->pNextACMDriver = padid->pACMDriverList;
234     padid->pACMDriverList = pad;
235 
236     /* FIXME: Create a WINE_ACMDRIVER32 */
237     *phad = (HACMDRIVER)pad;
238 
239     return MMSYSERR_NOERROR;
240 }
241 
242 /***********************************************************************
243  *           acmDriverRemove (MSACM32.12)
244  */
acmDriverRemove(HACMDRIVERID hadid,DWORD fdwRemove)245 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
246 {
247     PWINE_ACMDRIVERID padid;
248 
249     padid = MSACM_GetDriverID(hadid);
250     if (!padid)
251 	return MMSYSERR_INVALHANDLE;
252 
253     if (fdwRemove)
254 	return MMSYSERR_INVALFLAG;
255 
256     MSACM_UnregisterDriver(padid);
257 
258     return MMSYSERR_NOERROR;
259 }
260 
261 
262 
263 /**********************************************************************/
264 
265 HANDLE MSACM_hHeap = (HANDLE) NULL;
266 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
267 PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
268 
269 /***********************************************************************
270  *           MSACM_RegisterDriver32()
271  */
MSACM_RegisterDriver(const char * pszFileName,WORD wFormatTag,HINSTANCE hinstModule)272 PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName,
273 				       WORD wFormatTag,
274 				       HINSTANCE hinstModule)
275 {
276     PWINE_ACMDRIVERID padid;
277 
278     TRACE("('%s', '%x', 0x%08x)\n", pszFileName, wFormatTag, hinstModule);
279 
280 #ifndef WIN32_LOADER
281 	MSACM_hHeap = GetProcessHeap();
282 #endif
283     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
284     padid->pszFileName = malloc(strlen(pszFileName)+1);
285     strcpy(padid->pszFileName, pszFileName);
286 //    1~strdup(pszDriverAlias);
287     padid->wFormatTag = wFormatTag;
288     padid->hInstModule = hinstModule;
289     padid->bEnabled = TRUE;
290     padid->pACMDriverList = NULL;
291     padid->pNextACMDriverID = NULL;
292     padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
293     if (MSACM_pLastACMDriverID)
294 	MSACM_pLastACMDriverID->pNextACMDriverID = padid;
295     MSACM_pLastACMDriverID = padid;
296     if (!MSACM_pFirstACMDriverID)
297 	MSACM_pFirstACMDriverID = padid;
298 
299     return padid;
300 }
301 
302 
303 /***********************************************************************
304  *           MSACM_UnregisterDriver32()
305  */
MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)306 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
307 {
308     PWINE_ACMDRIVERID pNextACMDriverID;
309 
310     while (p->pACMDriverList)
311 	acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
312 
313     free(p->pszFileName);
314 
315     if (p == MSACM_pFirstACMDriverID)
316 	MSACM_pFirstACMDriverID = p->pNextACMDriverID;
317     if (p == MSACM_pLastACMDriverID)
318 	MSACM_pLastACMDriverID = p->pPrevACMDriverID;
319 
320     if (p->pPrevACMDriverID)
321 	p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
322     if (p->pNextACMDriverID)
323 	p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
324 
325     pNextACMDriverID = p->pNextACMDriverID;
326 
327     HeapFree(MSACM_hHeap, 0, p);
328 
329     return pNextACMDriverID;
330 }
331 
332 /***********************************************************************
333  *           MSACM_UnregisterAllDrivers32()
334  * FIXME
335  *   Where should this function be called?
336  */
MSACM_UnregisterAllDrivers(void)337 void MSACM_UnregisterAllDrivers(void)
338 {
339     PWINE_ACMDRIVERID p;
340 
341     for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p));
342 }
343 
344 /***********************************************************************
345  *           MSACM_GetDriverID32()
346  */
MSACM_GetDriverID(HACMDRIVERID hDriverID)347 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
348 {
349     return (PWINE_ACMDRIVERID)hDriverID;
350 }
351 
352 /***********************************************************************
353  *           MSACM_GetDriver32()
354  */
MSACM_GetDriver(HACMDRIVER hDriver)355 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
356 {
357     return (PWINE_ACMDRIVER)hDriver;
358 }
359 
360 /***********************************************************************
361  *           MSACM_GetObj32()
362  */
MSACM_GetObj(HACMOBJ hObj)363 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj)
364 {
365     return (PWINE_ACMOBJ)hObj;
366 }
367 
368 
369 
370 /***********************************************************************
371  *           acmStreamOpen (MSACM32.40)
372  */
acmStreamOpen(PHACMSTREAM phas,HACMDRIVER had,PWAVEFORMATEX pwfxSrc,PWAVEFORMATEX pwfxDst,PWAVEFILTER pwfltr,DWORD dwCallback,DWORD dwInstance,DWORD fdwOpen)373 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
374 			      PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
375 			      DWORD dwInstance, DWORD fdwOpen)
376 {
377     PWINE_ACMSTREAM	was;
378     PWINE_ACMDRIVER	wad;
379     MMRESULT		ret;
380     int			wfxSrcSize;
381     int			wfxDstSize;
382 
383     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
384 	  phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
385 
386     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
387 	  pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec,
388 	  pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
389 
390     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n",
391 	  pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec,
392 	  pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
393 
394 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
395     wfxSrcSize = SIZEOF_WFX(pwfxSrc);
396     wfxDstSize = SIZEOF_WFX(pwfxDst);
397 #undef SIZEOF_WFX
398 
399     was = (PWINE_ACMSTREAM) HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
400     if (was == NULL)
401 	return MMSYSERR_NOMEM;
402     was->drvInst.cbStruct = sizeof(was->drvInst);
403     was->drvInst.pwfxSrc = (PWAVEFORMATEX)(was + 1);
404     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
405     // LHACM is checking for 0x1
406     // but if this will not help
407     // was->drvInst.pwfxSrc->wFormatTag = 1;
408     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)(was + 1) + wfxSrcSize);
409     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
410     if (pwfltr) {
411 	was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)(was + 1) + wfxSrcSize + wfxDstSize);
412 	memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
413     } else {
414 	was->drvInst.pwfltr = NULL;
415     }
416     was->drvInst.dwCallback = dwCallback;
417     was->drvInst.dwInstance = dwInstance;
418     was->drvInst.fdwOpen = fdwOpen;
419     was->drvInst.fdwDriver = 0L;
420     was->drvInst.dwDriver = 0L;
421     was->drvInst.has = (HACMSTREAM)was;
422 
423     if (had) {
424 	if (!(wad = MSACM_GetDriver(had))) {
425 	    ret = MMSYSERR_INVALPARAM;
426 	    goto errCleanUp;
427 	}
428 
429 	was->obj.pACMDriverID = wad->obj.pACMDriverID;
430 	was->pDrv = wad;
431 	was->hAcmDriver = 0; /* not to close it in acmStreamClose */
432 
433 	ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
434 	if (ret != MMSYSERR_NOERROR)
435 	    goto errCleanUp;
436     } else {
437 	PWINE_ACMDRIVERID wadi;
438 	//short drv_tag;
439 	ret = ACMERR_NOTPOSSIBLE;
440 /*	if(pwfxSrc->wFormatTag==1)//compression
441 	    drv_tag=pwfxDst->wFormatTag;
442 	    else
443 	    if(pwfxDst->wFormatTag==1)//decompression
444 		drv_tag=pwfxSrc->wFormatTag;
445 		else
446 		goto errCleanUp;
447 
448 	    ret=acmDriverOpen2(drv_tag);
449 	    if (ret == MMSYSERR_NOERROR) {
450 		if ((wad = MSACM_GetDriver(had)) != 0) {
451 		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
452 		    was->pDrv = wad;
453 		    was->hAcmDriver = had;
454 
455 		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
456 		    if (ret == MMSYSERR_NOERROR) {
457 			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
458 			    acmDriverClose(had, 0L);
459 			}
460 			break;
461 		    }
462 		}
463 		acmDriverClose(had, 0L);*/
464 	//if(MSACM_pFirstACMDriverID==NULL)
465 	//    MSACM_RegisterAllDrivers();
466 
467 	for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID)
468 	{
469 	    /* Check Format */
470 	    if ((int)wadi->wFormatTag != (int)pwfxSrc->wFormatTag) continue;
471 
472 	    ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
473 	    if (ret == MMSYSERR_NOERROR) {
474 		if ((wad = MSACM_GetDriver(had)) != 0) {
475 		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
476 		    was->pDrv = wad;
477 		    was->hAcmDriver = had;
478 
479 		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
480 		    //lhacm - crash printf("RETOPEN %d\n", ret);
481                     //ret = 0;
482 		    if (ret == MMSYSERR_NOERROR) {
483 			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
484 			    acmDriverClose(had, 0L);
485 			}
486 			break;
487 		    }
488 		}
489 		// no match, close this acm driver and try next one
490 		acmDriverClose(had, 0L);
491 	    }
492 	}
493 	if (ret != MMSYSERR_NOERROR) {
494 	    ret = ACMERR_NOTPOSSIBLE;
495 	    goto errCleanUp;
496 	}
497     }
498     ret = MMSYSERR_NOERROR;
499     if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
500 	if (phas)
501 	    *phas = (HACMSTREAM)was;
502 	TRACE("=> (%d)\n", ret);
503 #ifdef WIN32_LOADER
504         CodecAlloc();
505 #endif
506 	return ret;
507     }
508 errCleanUp:
509     if (phas)
510 	*phas = (HACMSTREAM)0;
511     HeapFree(MSACM_hHeap, 0, was);
512     TRACE("=> (%d)\n", ret);
513     return ret;
514 }
515 
516 
acmStreamClose(HACMSTREAM has,DWORD fdwClose)517 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
518 {
519     PWINE_ACMSTREAM	was;
520     MMRESULT		ret;
521 
522     TRACE("(0x%08x, %ld)\n", has, fdwClose);
523 
524     if ((was = ACM_GetStream(has)) == NULL) {
525 	return MMSYSERR_INVALHANDLE;
526     }
527     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
528     if (ret == MMSYSERR_NOERROR) {
529 	if (was->hAcmDriver)
530 	    acmDriverClose(was->hAcmDriver, 0L);
531 	HeapFree(MSACM_hHeap, 0, was);
532 #ifdef WIN32_LOADER
533         CodecRelease();
534 #endif
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