]> git.sesse.net Git - vlc/blob - loader/afl.c
don't use float32 by default (should fix sound issues under windows)
[vlc] / loader / afl.c
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 CVS changelog at
21   http://www.mplayerhq.hu/cgi-bin/cvsweb.cgi/main/
22   $Id$
23   
24 ***************************************************************************/
25 #include "config.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 "driver.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
49 static inline PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
50 {
51     return (PWINE_ACMSTREAM)has;
52 }
53
54 /***********************************************************************
55  *           acmDriverAddA (MSACM32.2)
56  */
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  */
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  */
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  */
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  */
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  */
190 MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
191 {
192     PWINE_ACMDRIVERID   padid;
193     PWINE_ACMDRIVER     pad;
194     ICOPEN              icopen;
195     HDRVR               hdrv;
196
197
198     TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
199
200     if (!phad)
201         return MMSYSERR_INVALPARAM;
202     
203     padid = MSACM_GetDriverID(hadid); 
204     if (!padid)
205         return MMSYSERR_INVALHANDLE;
206     
207     if (fdwOpen)
208         return MMSYSERR_INVALFLAG;
209     
210     pad = (PWINE_ACMDRIVER) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
211     if (!pad)
212         return MMSYSERR_NOMEM;
213
214     pad->obj.pACMDriverID = padid;
215     icopen.fccType              = mmioFOURCC('a', 'u', 'd', 'c');
216     icopen.fccHandler           = (long)padid->pszFileName;
217     icopen.dwSize               = sizeof(ICOPEN);
218     icopen.dwFlags              = 0;
219
220     icopen.pV1Reserved = padid->pszFileName;
221     if (!padid->hInstModule)
222         pad->hDrvr = OpenDriverA((long)&icopen);
223     else
224         pad->hDrvr = padid->hInstModule;
225     
226     if (!pad->hDrvr) {
227         HeapFree(MSACM_hHeap, 0, pad);
228         return MMSYSERR_ERROR;
229     }
230
231     pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
232
233     /* insert new pad at beg of list */
234     pad->pNextACMDriver = padid->pACMDriverList;
235     padid->pACMDriverList = pad;
236
237     /* FIXME: Create a WINE_ACMDRIVER32 */
238     *phad = (HACMDRIVER)pad;
239
240     return MMSYSERR_NOERROR;
241 }
242
243 /***********************************************************************
244  *           acmDriverRemove (MSACM32.12)
245  */
246 MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
247 {
248     PWINE_ACMDRIVERID padid;
249     
250     padid = MSACM_GetDriverID(hadid);
251     if (!padid)
252         return MMSYSERR_INVALHANDLE;
253     
254     if (fdwRemove)
255         return MMSYSERR_INVALFLAG;
256     
257     MSACM_UnregisterDriver(padid);
258     
259     return MMSYSERR_NOERROR;
260 }
261
262
263
264 /**********************************************************************/
265
266 HANDLE MSACM_hHeap = (HANDLE) NULL;
267 PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
268 PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
269
270 /***********************************************************************
271  *           MSACM_RegisterDriver32() 
272  */
273 PWINE_ACMDRIVERID MSACM_RegisterDriver(const char* pszFileName,
274                                        WORD wFormatTag,
275                                        HINSTANCE hinstModule)
276 {
277     PWINE_ACMDRIVERID padid;
278
279     TRACE("('%s', '%x', 0x%08x)\n", pszFileName, wFormatTag, hinstModule);
280
281 #ifndef WIN32_LOADER
282         MSACM_hHeap = GetProcessHeap();
283 #endif
284     padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
285     padid->pszFileName = (char*)malloc(strlen(pszFileName)+1);
286     strcpy(padid->pszFileName, pszFileName);
287 //    1~strdup(pszDriverAlias);
288     padid->wFormatTag = wFormatTag;
289     padid->hInstModule = hinstModule;
290     padid->bEnabled = TRUE;
291     padid->pACMDriverList = NULL;
292     padid->pNextACMDriverID = NULL;
293     padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
294     if (MSACM_pLastACMDriverID)
295         MSACM_pLastACMDriverID->pNextACMDriverID = padid;
296     MSACM_pLastACMDriverID = padid;
297     if (!MSACM_pFirstACMDriverID)
298         MSACM_pFirstACMDriverID = padid;
299     
300     return padid;
301 }
302
303
304 /***********************************************************************
305  *           MSACM_UnregisterDriver32()
306  */
307 PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
308 {
309     PWINE_ACMDRIVERID pNextACMDriverID;
310     
311     while (p->pACMDriverList)
312         acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
313     
314     if (p->pszFileName)
315         free(p->pszFileName);
316     
317     if (p == MSACM_pFirstACMDriverID)
318         MSACM_pFirstACMDriverID = p->pNextACMDriverID;
319     if (p == MSACM_pLastACMDriverID)
320         MSACM_pLastACMDriverID = p->pPrevACMDriverID;
321
322     if (p->pPrevACMDriverID)
323         p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
324     if (p->pNextACMDriverID)
325         p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
326     
327     pNextACMDriverID = p->pNextACMDriverID;
328     
329     HeapFree(MSACM_hHeap, 0, p);
330     
331     return pNextACMDriverID;
332 }
333
334 /***********************************************************************
335  *           MSACM_UnregisterAllDrivers32()
336  * FIXME
337  *   Where should this function be called?
338  */
339 void MSACM_UnregisterAllDrivers(void)
340 {
341     PWINE_ACMDRIVERID p;
342
343     for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p));
344 }
345
346 /***********************************************************************
347  *           MSACM_GetDriverID32() 
348  */
349 PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
350 {
351     return (PWINE_ACMDRIVERID)hDriverID;
352 }
353
354 /***********************************************************************
355  *           MSACM_GetDriver32()
356  */
357 PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
358 {
359     return (PWINE_ACMDRIVER)hDriver;
360 }
361
362 /***********************************************************************
363  *           MSACM_GetObj32()
364  */
365 PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj)
366 {
367     return (PWINE_ACMOBJ)hObj;
368 }
369
370
371
372 /***********************************************************************
373  *           acmStreamOpen (MSACM32.40)
374  */
375 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
376                               PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
377                               DWORD dwInstance, DWORD fdwOpen)
378 {
379     PWINE_ACMSTREAM     was;
380     PWINE_ACMDRIVER     wad;
381     MMRESULT            ret;
382     int                 wfxSrcSize;
383     int                 wfxDstSize;
384     
385     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
386           phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
387
388     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
389           pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, 
390           pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
391
392     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
393           pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, 
394           pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
395
396 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
397     wfxSrcSize = SIZEOF_WFX(pwfxSrc);
398     wfxDstSize = SIZEOF_WFX(pwfxDst);
399 #undef SIZEOF_WFX
400
401     was = (PWINE_ACMSTREAM) HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
402     if (was == NULL)
403         return MMSYSERR_NOMEM;
404     was->drvInst.cbStruct = sizeof(was->drvInst);
405     was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
406     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
407     // LHACM is checking for 0x1
408     // but if this will not help
409     // was->drvInst.pwfxSrc->wFormatTag = 1;
410     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
411     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
412     if (pwfltr) {
413         was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
414         memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
415     } else {
416         was->drvInst.pwfltr = NULL;
417     }
418     was->drvInst.dwCallback = dwCallback;    
419     was->drvInst.dwInstance = dwInstance;
420     was->drvInst.fdwOpen = fdwOpen;
421     was->drvInst.fdwDriver = 0L;  
422     was->drvInst.dwDriver = 0L;     
423     was->drvInst.has = (HACMSTREAM)was;
424     
425     if (had) {
426         if (!(wad = MSACM_GetDriver(had))) {
427             ret = MMSYSERR_INVALPARAM;
428             goto errCleanUp;
429         }
430         
431         was->obj.pACMDriverID = wad->obj.pACMDriverID;
432         was->pDrv = wad;
433         was->hAcmDriver = 0; /* not to close it in acmStreamClose */
434
435         ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
436         if (ret != MMSYSERR_NOERROR)
437             goto errCleanUp;
438     } else {
439         PWINE_ACMDRIVERID wadi;
440         short drv_tag;
441         ret = ACMERR_NOTPOSSIBLE;
442 /*      if(pwfxSrc->wFormatTag==1)//compression
443             drv_tag=pwfxDst->wFormatTag;
444             else
445             if(pwfxDst->wFormatTag==1)//decompression
446                 drv_tag=pwfxSrc->wFormatTag;
447                 else
448                 goto errCleanUp;
449
450             ret=acmDriverOpen2(drv_tag); 
451             if (ret == MMSYSERR_NOERROR) {
452                 if ((wad = MSACM_GetDriver(had)) != 0) {
453                     was->obj.pACMDriverID = wad->obj.pACMDriverID;
454                     was->pDrv = wad;
455                     was->hAcmDriver = had;
456                     
457                     ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
458                     if (ret == MMSYSERR_NOERROR) {
459                         if (fdwOpen & ACM_STREAMOPENF_QUERY) {
460                             acmDriverClose(had, 0L);
461                         }
462                         break;
463                     }
464                 }
465                 acmDriverClose(had, 0L);*/
466         //if(MSACM_pFirstACMDriverID==NULL)
467         //    MSACM_RegisterAllDrivers();
468         
469         for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID)
470         {
471             /* Check Format */
472             if ((int)wadi->wFormatTag != (int)pwfxSrc->wFormatTag) continue;
473
474             ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
475             if (ret == MMSYSERR_NOERROR) {
476                 if ((wad = MSACM_GetDriver(had)) != 0) {
477                     was->obj.pACMDriverID = wad->obj.pACMDriverID;
478                     was->pDrv = wad;
479                     was->hAcmDriver = had;
480                     
481                     ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
482                     //lhacm - crash printf("RETOPEN %d\n", ret);
483                     //ret = 0;
484                     if (ret == MMSYSERR_NOERROR) {
485                         if (fdwOpen & ACM_STREAMOPENF_QUERY) {
486                             acmDriverClose(had, 0L);
487                         }
488                         break;
489                     }
490                 }
491                 // no match, close this acm driver and try next one 
492                 acmDriverClose(had, 0L);
493             }
494         }
495         if (ret != MMSYSERR_NOERROR) {
496             ret = ACMERR_NOTPOSSIBLE;
497             goto errCleanUp;
498         }
499     }
500     ret = MMSYSERR_NOERROR;
501     if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
502         if (phas)
503             *phas = (HACMSTREAM)was;
504         TRACE("=> (%d)\n", ret);
505 #ifdef WIN32_LOADER
506         CodecAlloc();
507 #endif
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
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 #ifdef WIN32_LOADER
535         CodecRelease();
536 #endif
537     }
538     TRACE("=> (%d)\n", ret);
539     return ret;
540 }
541
542 /***********************************************************************
543  *           acmStreamConvert (MSACM32.38)
544  */
545 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, 
546                                  DWORD fdwConvert)
547 {
548     PWINE_ACMSTREAM     was;
549     MMRESULT            ret = MMSYSERR_NOERROR;
550     PACMDRVSTREAMHEADER padsh;
551
552     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
553
554     if ((was = ACM_GetStream(has)) == NULL)
555         return MMSYSERR_INVALHANDLE;
556     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
557         return MMSYSERR_INVALPARAM;
558
559     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
560         return ACMERR_UNPREPARED;
561
562     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
563      * size. some fields are private to msacm internals, and are exposed
564      * in ACMSTREAMHEADER in the dwReservedDriver array
565      */
566     padsh = (PACMDRVSTREAMHEADER)pash;
567
568     /* check that pointers have not been modified */
569     if (padsh->pbPreparedSrc != padsh->pbSrc ||
570         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
571         padsh->pbPreparedDst != padsh->pbDst ||
572         padsh->cbPreparedDstLength < padsh->cbDstLength) {
573         return MMSYSERR_INVALPARAM;
574     }   
575
576     padsh->fdwConvert = fdwConvert;
577
578     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
579     if (ret == MMSYSERR_NOERROR) {
580         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
581     }
582     TRACE("=> (%d)\n", ret);
583     return ret;
584 }
585
586
587 /***********************************************************************
588  *           acmStreamPrepareHeader (MSACM32.41)
589  */
590 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
591                                        DWORD fdwPrepare)
592 {
593     PWINE_ACMSTREAM     was;
594     MMRESULT            ret = MMSYSERR_NOERROR;
595     PACMDRVSTREAMHEADER padsh;
596
597     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
598     
599     if ((was = ACM_GetStream(has)) == NULL)
600         return MMSYSERR_INVALHANDLE;
601     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
602         return MMSYSERR_INVALPARAM;
603     if (fdwPrepare)
604         ret = MMSYSERR_INVALFLAG;
605
606     if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
607         return MMSYSERR_NOERROR;
608
609     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
610      * size. some fields are private to msacm internals, and are exposed
611      * in ACMSTREAMHEADER in the dwReservedDriver array
612      */
613     padsh = (PACMDRVSTREAMHEADER)pash;
614
615     padsh->fdwConvert = fdwPrepare;
616     padsh->padshNext = NULL;
617     padsh->fdwDriver = padsh->dwDriver = 0L;
618
619     padsh->fdwPrepared = 0;
620     padsh->dwPrepared = 0;
621     padsh->pbPreparedSrc = 0;
622     padsh->cbPreparedSrcLength = 0;
623     padsh->pbPreparedDst = 0;
624     padsh->cbPreparedDstLength = 0;
625
626     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
627     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
628         ret = MMSYSERR_NOERROR;
629         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
630         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
631         padsh->fdwPrepared = padsh->fdwStatus;
632         padsh->dwPrepared = 0;
633         padsh->pbPreparedSrc = padsh->pbSrc;
634         padsh->cbPreparedSrcLength = padsh->cbSrcLength;
635         padsh->pbPreparedDst = padsh->pbDst;
636         padsh->cbPreparedDstLength = padsh->cbDstLength;
637     } else {
638         padsh->fdwPrepared = 0;
639         padsh->dwPrepared = 0;
640         padsh->pbPreparedSrc = 0;
641         padsh->cbPreparedSrcLength = 0;
642         padsh->pbPreparedDst = 0;
643         padsh->cbPreparedDstLength = 0;
644     }
645     TRACE("=> (%d)\n", ret);
646     return ret;
647 }
648
649 /***********************************************************************
650  *           acmStreamReset (MSACM32.42)
651  */
652 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
653 {
654     PWINE_ACMSTREAM     was;
655     MMRESULT            ret = MMSYSERR_NOERROR;
656
657     TRACE("(0x%08x, %ld)\n", has, fdwReset);
658
659     if (fdwReset) {
660         ret = MMSYSERR_INVALFLAG;
661     } else if ((was = ACM_GetStream(has)) == NULL) {
662         return MMSYSERR_INVALHANDLE;
663     } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
664         ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
665     }
666     TRACE("=> (%d)\n", ret);
667     return ret;
668 }
669
670 /***********************************************************************
671  *           acmStreamSize (MSACM32.43)
672  */
673 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, 
674                               LPDWORD pdwOutputBytes, DWORD fdwSize)
675 {
676     PWINE_ACMSTREAM     was;
677     ACMDRVSTREAMSIZE    adss;
678     MMRESULT            ret;
679     
680     TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
681     
682     if ((was = ACM_GetStream(has)) == NULL) {
683         return MMSYSERR_INVALHANDLE;
684     }
685     if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
686         return MMSYSERR_INVALFLAG;
687     }
688
689     *pdwOutputBytes = 0L;
690     
691     switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
692     case ACM_STREAMSIZEF_DESTINATION:
693         adss.cbDstLength = cbInput;
694         adss.cbSrcLength = 0;
695         break;
696     case ACM_STREAMSIZEF_SOURCE:
697         adss.cbSrcLength = cbInput;
698         adss.cbDstLength = 0;
699         break;
700     default:    
701         return MMSYSERR_INVALFLAG;
702     }
703     
704     adss.cbStruct = sizeof(adss);
705     adss.fdwSize = fdwSize;
706     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, 
707                             (DWORD)&was->drvInst, (DWORD)&adss);
708     if (ret == MMSYSERR_NOERROR) {
709         switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
710         case ACM_STREAMSIZEF_DESTINATION:
711             *pdwOutputBytes = adss.cbSrcLength;
712             break;
713         case ACM_STREAMSIZEF_SOURCE:
714             *pdwOutputBytes = adss.cbDstLength;
715             break;
716         }
717     }
718     TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
719     return ret;
720 }
721
722 /***********************************************************************
723  *           acmStreamUnprepareHeader (MSACM32.44)
724  */
725 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
726                                          DWORD fdwUnprepare)
727 {
728     PWINE_ACMSTREAM     was;
729     MMRESULT            ret = MMSYSERR_NOERROR;
730     PACMDRVSTREAMHEADER padsh;
731
732     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
733     
734     if ((was = ACM_GetStream(has)) == NULL)
735         return MMSYSERR_INVALHANDLE;
736     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
737         return MMSYSERR_INVALPARAM;
738
739     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
740         return ACMERR_UNPREPARED;
741
742     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
743      * size. some fields are private to msacm internals, and are exposed
744      * in ACMSTREAMHEADER in the dwReservedDriver array
745      */
746     padsh = (PACMDRVSTREAMHEADER)pash;
747
748     /* check that pointers have not been modified */
749     if (padsh->pbPreparedSrc != padsh->pbSrc ||
750         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
751         padsh->pbPreparedDst != padsh->pbDst ||
752         padsh->cbPreparedDstLength < padsh->cbDstLength) {
753         return MMSYSERR_INVALPARAM;
754     }   
755
756     padsh->fdwConvert = fdwUnprepare;
757
758     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
759     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
760         ret = MMSYSERR_NOERROR;
761         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
762     }
763     TRACE("=> (%d)\n", ret);
764     return ret;
765 }