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