diff loader/afl.c @ 1:3b5f5d1c5041

Initial revision
author arpi_esp
date Sat, 24 Feb 2001 20:28:24 +0000
parents
children d8c1b0b38edc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loader/afl.c	Sat Feb 24 20:28:24 2001 +0000
@@ -0,0 +1,763 @@
+/**************************************************************************
+
+
+  This file will contain an interface to ACM drivers.
+  Its content will be based mainly on wine/dlls/msacm32
+  actually, for audio decompression only the following functions
+  are needed:
+  
+  acmStreamOpen ( takes formats of src and dest, returns stream handle )
+  acmStreamPrepareHeader ( takes stream handler and info on data )
+  acmStreamConvert ( the same as PrepareHeader )
+  acmStreamUnprepareHeader
+  acmStreamClose
+  acmStreamSize
+  maybe acmStreamReset
+  
+  In future I'll also add functions for format enumeration, 
+  but not right now.
+
+  
+***************************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <wine/winbase.h>
+#include <wine/windef.h>
+#include <wine/winuser.h>
+#include <wine/vfw.h>
+#include <wine/winestring.h>
+#include <wine/driver.h>
+#include <wine/winerror.h>
+#include <wine/msacm.h>
+#include <wine/msacmdrv.h>
+#include "wineacm.h"
+#pragma pack(1)
+#define OpenDriverA DrvOpen
+extern HDRVR VFWAPI DrvOpen(long);
+#define CloseDriver DrvClose
+extern HDRVR VFWAPI DrvClose(long);
+
+static PWINE_ACMSTREAM	ACM_GetStream(HACMSTREAM has)
+{
+    return (PWINE_ACMSTREAM)has;
+}
+
+/***********************************************************************
+ *           acmDriverAddA (MSACM32.2)
+ */
+MMRESULT WINAPI acmDriverAddA(PHACMDRIVERID phadid, HINSTANCE hinstModule,
+			      LPARAM lParam, DWORD dwPriority, DWORD fdwAdd)
+{
+    if (!phadid)
+	return MMSYSERR_INVALPARAM;
+    
+    /* Check if any unknown flags */
+    if (fdwAdd & 
+	~(ACM_DRIVERADDF_FUNCTION|ACM_DRIVERADDF_NOTIFYHWND|
+	  ACM_DRIVERADDF_GLOBAL))
+	return MMSYSERR_INVALFLAG;
+    
+    /* Check if any incompatible flags */
+    if ((fdwAdd & ACM_DRIVERADDF_FUNCTION) && 
+	(fdwAdd & ACM_DRIVERADDF_NOTIFYHWND))
+	return MMSYSERR_INVALFLAG;
+    
+    /* FIXME: in fact, should GetModuleFileName(hinstModule) and do a 
+     * LoadDriver on it, to be sure we can call SendDriverMessage on the
+     * hDrvr handle.
+     */
+    *phadid = (HACMDRIVERID) MSACM_RegisterDriver(NULL, NULL, hinstModule);
+    
+    /* FIXME: lParam, dwPriority and fdwAdd ignored */
+    
+    return MMSYSERR_NOERROR;
+}
+
+/***********************************************************************
+ *           acmDriverClose (MSACM32.4)
+ */
+MMRESULT WINAPI acmDriverClose(HACMDRIVER had, DWORD fdwClose)
+{
+    PWINE_ACMDRIVER  p;
+    PWINE_ACMDRIVER* tp;
+    
+    if (fdwClose)
+	return MMSYSERR_INVALFLAG;
+    
+    p = MSACM_GetDriver(had);
+    if (!p)
+	return MMSYSERR_INVALHANDLE;
+
+    for (tp = &(p->obj.pACMDriverID->pACMDriverList); *tp; *tp = (*tp)->pNextACMDriver) {
+	if (*tp == p) {
+	    *tp = (*tp)->pNextACMDriver;
+	    break;
+	}
+    }
+    
+    if (p->hDrvr && !p->obj.pACMDriverID->pACMDriverList)
+	CloseDriver(p->hDrvr);
+    
+    HeapFree(MSACM_hHeap, 0, p);
+    
+    return MMSYSERR_NOERROR;
+}
+
+/***********************************************************************
+ *           acmDriverEnum (MSACM32.7)
+ */
+MMRESULT WINAPI acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum)
+{
+    PWINE_ACMDRIVERID	p;
+    DWORD		fdwSupport;
+
+    if (!fnCallback) {
+	return MMSYSERR_INVALPARAM;
+    }
+    
+    if (fdwEnum && ~(ACM_DRIVERENUMF_NOLOCAL|ACM_DRIVERENUMF_DISABLED)) {
+	return MMSYSERR_INVALFLAG;
+    }
+    
+    for (p = MSACM_pFirstACMDriverID; p; p = p->pNextACMDriverID) {
+	fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CODEC;
+	if (!p->bEnabled) {
+	    if (fdwEnum & ACM_DRIVERENUMF_DISABLED)
+		fdwSupport |= ACMDRIVERDETAILS_SUPPORTF_DISABLED;
+	    else
+		continue;
+	}
+	(*fnCallback)((HACMDRIVERID) p, dwInstance, fdwSupport);
+    }
+    
+    return MMSYSERR_NOERROR;
+}
+
+/***********************************************************************
+ *           acmDriverID (MSACM32.8)
+ */
+MMRESULT WINAPI acmDriverID(HACMOBJ hao, PHACMDRIVERID phadid, DWORD fdwDriverID)
+{
+    PWINE_ACMOBJ pao;
+    
+    pao = MSACM_GetObj(hao);
+    if (!pao)
+	return MMSYSERR_INVALHANDLE;
+    
+    if (!phadid)
+	return MMSYSERR_INVALPARAM;
+    
+    if (fdwDriverID)
+	return MMSYSERR_INVALFLAG;
+    
+    *phadid = (HACMDRIVERID) pao->pACMDriverID;
+    
+    return MMSYSERR_NOERROR;
+}
+
+/***********************************************************************
+ *           acmDriverMessage (MSACM32.9)
+ * FIXME
+ *   Not implemented
+ */
+LRESULT WINAPI acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
+{
+    PWINE_ACMDRIVER pad = MSACM_GetDriver(had);
+    if (!pad)
+	return MMSYSERR_INVALPARAM;
+    
+    /* FIXME: Check if uMsg legal */
+    
+    if (!SendDriverMessage(pad->hDrvr, uMsg, lParam1, lParam2))
+	return MMSYSERR_NOTSUPPORTED;
+    
+    return MMSYSERR_NOERROR;
+}
+
+
+/***********************************************************************
+ *           acmDriverOpen (MSACM32.10)
+ */
+MMRESULT WINAPI acmDriverOpen(PHACMDRIVER phad, HACMDRIVERID hadid, DWORD fdwOpen)
+{
+    PWINE_ACMDRIVERID	padid;
+    PWINE_ACMDRIVER	pad;
+    ICOPEN		icopen;
+    HDRVR		hdrv;
+
+
+
+    TRACE("(%p, %x, %08lu)\n", phad, hadid, fdwOpen);
+
+    if (!phad)
+	return MMSYSERR_INVALPARAM;
+    
+    padid = MSACM_GetDriverID(hadid); 
+    if (!padid)
+	return MMSYSERR_INVALHANDLE;
+    
+    if (fdwOpen)
+	return MMSYSERR_INVALFLAG;
+    
+    pad = HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVER));
+    if (!pad) return MMSYSERR_NOMEM;
+
+    pad->obj.pACMDriverID = padid;
+    icopen.fccType		= mmioFOURCC('a', 'u', 'd', 'c');
+    icopen.fccHandler		= (long)padid->pszFileName;
+    icopen.dwSize		= sizeof(ICOPEN);
+    icopen.dwFlags		= 0;
+
+   if (!padid->hInstModule)
+	pad->hDrvr = OpenDriverA((long)&icopen);
+    else
+	pad->hDrvr = padid->hInstModule;
+    
+    if (!pad->hDrvr) {
+	HeapFree(MSACM_hHeap, 0, pad);
+	return MMSYSERR_ERROR;
+    }
+    
+    pad->pfnDriverProc = GetProcAddress(pad->hDrvr, "DriverProc");
+
+    /* insert new pad at beg of list */
+    pad->pNextACMDriver = padid->pACMDriverList;
+    padid->pACMDriverList = pad;
+
+    /* FIXME: Create a WINE_ACMDRIVER32 */
+    *phad = (HACMDRIVER)pad;
+    
+    return MMSYSERR_NOERROR;
+}
+
+/***********************************************************************
+ *           acmDriverRemove (MSACM32.12)
+ */
+MMRESULT WINAPI acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove)
+{
+    PWINE_ACMDRIVERID padid;
+    
+    padid = MSACM_GetDriverID(hadid);
+    if (!padid)
+	return MMSYSERR_INVALHANDLE;
+    
+    if (fdwRemove)
+	return MMSYSERR_INVALFLAG;
+    
+    MSACM_UnregisterDriver(padid);
+    
+    return MMSYSERR_NOERROR;
+}
+
+
+
+/**********************************************************************/
+
+HANDLE MSACM_hHeap = (HANDLE) NULL;
+PWINE_ACMDRIVERID MSACM_pFirstACMDriverID = NULL;
+PWINE_ACMDRIVERID MSACM_pLastACMDriverID = NULL;
+
+/***********************************************************************
+ *           MSACM_RegisterDriver32() 
+ */
+PWINE_ACMDRIVERID MSACM_RegisterDriver(LPSTR pszDriverAlias, LPSTR pszFileName,
+				       HINSTANCE hinstModule)
+//
+// File names are stored in driver.c. I reuse this variable to store driver ID
+// in it. If it's <0x10000, it is primary codec for corresponding format.
+//				       
+{ 
+    PWINE_ACMDRIVERID padid;
+
+    TRACE("('%s', '%x', 0x%08x)\n", pszDriverAlias, pszFileName, hinstModule);
+
+    padid = (PWINE_ACMDRIVERID) HeapAlloc(MSACM_hHeap, 0, sizeof(WINE_ACMDRIVERID));
+    padid->pszDriverAlias = (char*)malloc(strlen(pszDriverAlias)+1);
+    strcpy(padid->pszDriverAlias, pszDriverAlias);
+//    1~strdup(pszDriverAlias);
+    padid->pszFileName = pszFileName;
+    padid->hInstModule = hinstModule;
+    padid->bEnabled = TRUE;
+    padid->pACMDriverList = NULL;
+    padid->pNextACMDriverID = NULL;
+    padid->pPrevACMDriverID = MSACM_pLastACMDriverID;
+    if (MSACM_pLastACMDriverID)
+	MSACM_pLastACMDriverID->pNextACMDriverID = padid;
+    MSACM_pLastACMDriverID = padid;
+    if (!MSACM_pFirstACMDriverID)
+	MSACM_pFirstACMDriverID = padid;
+    
+    return padid;
+}
+
+/***********************************************************************
+ *           MSACM_RegisterAllDrivers32() 
+ */
+void MSACM_RegisterAllDrivers(void)
+{
+    LPSTR pszBuffer;
+    DWORD dwBufferLength;
+    
+    if (MSACM_pFirstACMDriverID)
+	return;
+    
+    MSACM_RegisterDriver("divxa32", (LPSTR)0x161, 0);  // DivX/WMA     [07]
+    MSACM_RegisterDriver("msadp32", (LPSTR)0x2, 0);    // MS ADPCM     [08]
+    MSACM_RegisterDriver("l3codeca", (LPSTR)0x55, 0);  // MPEG Layer-3 [12]
+//    MSACM_RegisterDriver("imaadp32", (LPSTR)0x11, 0);  // IMA ADPCM    [13]
+//    MSACM_RegisterDriver("msgsm32", (LPSTR)0x32, 0);   // MS GSM 6.10  [14]
+}
+
+/***********************************************************************
+ *           MSACM_UnregisterDriver32()
+ */
+PWINE_ACMDRIVERID MSACM_UnregisterDriver(PWINE_ACMDRIVERID p)
+{
+    PWINE_ACMDRIVERID pNextACMDriverID;
+    
+    while (p->pACMDriverList)
+	acmDriverClose((HACMDRIVER) p->pACMDriverList, 0);
+    
+    if (p->pszDriverAlias)
+	HeapFree(MSACM_hHeap, 0, p->pszDriverAlias);
+//    if (p->pszFileName)
+//	HeapFree(MSACM_hHeap, 0, p->pszFileName);
+    
+    if (p == MSACM_pFirstACMDriverID)
+	MSACM_pFirstACMDriverID = p->pNextACMDriverID;
+    if (p == MSACM_pLastACMDriverID)
+	MSACM_pLastACMDriverID = p->pPrevACMDriverID;
+
+    if (p->pPrevACMDriverID)
+	p->pPrevACMDriverID->pNextACMDriverID = p->pNextACMDriverID;
+    if (p->pNextACMDriverID)
+	p->pNextACMDriverID->pPrevACMDriverID = p->pPrevACMDriverID;
+    
+    pNextACMDriverID = p->pNextACMDriverID;
+    
+    HeapFree(MSACM_hHeap, 0, p);
+    
+    return pNextACMDriverID;
+}
+
+/***********************************************************************
+ *           MSACM_UnregisterAllDrivers32()
+ * FIXME
+ *   Where should this function be called?
+ */
+void MSACM_UnregisterAllDrivers(void)
+{
+    PWINE_ACMDRIVERID p;
+
+    for (p = MSACM_pFirstACMDriverID; p; p = MSACM_UnregisterDriver(p));
+}
+
+/***********************************************************************
+ *           MSACM_GetDriverID32() 
+ */
+PWINE_ACMDRIVERID MSACM_GetDriverID(HACMDRIVERID hDriverID)
+{
+    return (PWINE_ACMDRIVERID)hDriverID;
+}
+
+/***********************************************************************
+ *           MSACM_GetDriver32()
+ */
+PWINE_ACMDRIVER MSACM_GetDriver(HACMDRIVER hDriver)
+{
+    return (PWINE_ACMDRIVER)hDriver;
+}
+
+/***********************************************************************
+ *           MSACM_GetObj32()
+ */
+PWINE_ACMOBJ MSACM_GetObj(HACMOBJ hObj)
+{
+    return (PWINE_ACMOBJ)hObj;
+}
+
+
+
+/***********************************************************************
+ *           acmStreamOpen (MSACM32.40)
+ */
+MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
+			      PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
+			      DWORD dwInstance, DWORD fdwOpen)
+{
+    PWINE_ACMSTREAM	was;
+    PWINE_ACMDRIVER	wad;
+    MMRESULT		ret;
+    int			wfxSrcSize;
+    int			wfxDstSize;
+    
+    TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
+	  phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
+
+    TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
+	  pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, 
+	  pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
+
+    TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
+	  pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, 
+	  pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
+
+#define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
+    wfxSrcSize = SIZEOF_WFX(pwfxSrc);
+    wfxDstSize = SIZEOF_WFX(pwfxDst);
+#undef SIZEOF_WFX
+
+    was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
+    if (was == NULL)
+	return MMSYSERR_NOMEM;
+    
+    was->drvInst.cbStruct = sizeof(was->drvInst);
+    was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
+    memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
+    was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
+    memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
+    if (pwfltr) {
+	was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
+	memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
+    } else {
+	was->drvInst.pwfltr = NULL;
+    }
+    was->drvInst.dwCallback = dwCallback;    
+    was->drvInst.dwInstance = dwInstance;
+    was->drvInst.fdwOpen = fdwOpen;
+    was->drvInst.fdwDriver = 0L;  
+    was->drvInst.dwDriver = 0L;     
+    was->drvInst.has = (HACMSTREAM)was;
+    
+    if (had) {
+	if (!(wad = MSACM_GetDriver(had))) {
+	    ret = MMSYSERR_INVALPARAM;
+	    goto errCleanUp;
+	}
+	
+	was->obj.pACMDriverID = wad->obj.pACMDriverID;
+	was->pDrv = wad;
+	was->hAcmDriver = 0; /* not to close it in acmStreamClose */
+
+	ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
+	if (ret != MMSYSERR_NOERROR)
+	    goto errCleanUp;
+    } else {
+	PWINE_ACMDRIVERID wadi;
+	short drv_tag;
+	ret = ACMERR_NOTPOSSIBLE;
+/*	if(pwfxSrc->wFormatTag==1)//compression
+	    drv_tag=pwfxDst->wFormatTag;
+	    else
+	    if(pwfxDst->wFormatTag==1)//decompression
+		drv_tag=pwfxSrc->wFormatTag;
+		else
+		goto errCleanUp;
+
+	    ret=acmDriverOpen2(drv_tag); 
+	    if (ret == MMSYSERR_NOERROR) {
+		if ((wad = MSACM_GetDriver(had)) != 0) {
+		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
+		    was->pDrv = wad;
+		    was->hAcmDriver = had;
+		    
+		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
+		    if (ret == MMSYSERR_NOERROR) {
+			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
+			    acmDriverClose(had, 0L);
+			}
+			break;
+		    }
+		}
+		acmDriverClose(had, 0L);*/
+	if(MSACM_pFirstACMDriverID==NULL)
+	    MSACM_RegisterAllDrivers();	
+	
+	for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
+	    ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
+	    if (ret == MMSYSERR_NOERROR) {
+		if ((wad = MSACM_GetDriver(had)) != 0) {
+		    was->obj.pACMDriverID = wad->obj.pACMDriverID;
+		    was->pDrv = wad;
+		    was->hAcmDriver = had;
+		    
+		    ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
+		    if (ret == MMSYSERR_NOERROR) {
+			if (fdwOpen & ACM_STREAMOPENF_QUERY) {
+			    acmDriverClose(had, 0L);
+			}
+			break;
+		    }
+		}
+		// no match, close this acm driver and try next one 
+		acmDriverClose(had, 0L);
+	    }
+	}
+	if (ret != MMSYSERR_NOERROR) {
+	    ret = ACMERR_NOTPOSSIBLE;
+	    goto errCleanUp;
+	}
+    }
+    ret = MMSYSERR_NOERROR;
+    if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
+	if (phas)
+	    *phas = (HACMSTREAM)was;
+	TRACE("=> (%d)\n", ret);
+	return ret;
+    }
+errCleanUp:		
+    if (phas)
+	*phas = (HACMSTREAM)0;
+    HeapFree(MSACM_hHeap, 0, was);
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}
+
+
+MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
+{
+    PWINE_ACMSTREAM	was;
+    MMRESULT		ret;
+		
+    TRACE("(0x%08x, %ld)\n", has, fdwClose);
+    
+    if ((was = ACM_GetStream(has)) == NULL) {
+	return MMSYSERR_INVALHANDLE;
+    }
+    ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
+    if (ret == MMSYSERR_NOERROR) {
+	if (was->hAcmDriver)
+	    acmDriverClose(was->hAcmDriver, 0L);	
+	HeapFree(MSACM_hHeap, 0, was);
+    }
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *           acmStreamConvert (MSACM32.38)
+ */
+MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, 
+				 DWORD fdwConvert)
+{
+    PWINE_ACMSTREAM	was;
+    MMRESULT		ret = MMSYSERR_NOERROR;
+    PACMDRVSTREAMHEADER	padsh;
+
+    TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
+    
+    if ((was = ACM_GetStream(has)) == NULL)
+	return MMSYSERR_INVALHANDLE;
+    if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
+	return MMSYSERR_INVALPARAM;
+
+    if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
+	return ACMERR_UNPREPARED;
+
+    /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
+     * size. some fields are private to msacm internals, and are exposed
+     * in ACMSTREAMHEADER in the dwReservedDriver array
+     */
+    padsh = (PACMDRVSTREAMHEADER)pash;
+
+    /* check that pointers have not been modified */
+    if (padsh->pbPreparedSrc != padsh->pbSrc ||
+	padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
+	padsh->pbPreparedDst != padsh->pbDst ||
+	padsh->cbPreparedDstLength < padsh->cbDstLength) {
+	return MMSYSERR_INVALPARAM;
+    }	
+
+    padsh->fdwConvert = fdwConvert;
+
+    ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
+    if (ret == MMSYSERR_NOERROR) {
+	padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
+    }
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}
+
+
+/***********************************************************************
+ *           acmStreamPrepareHeader (MSACM32.41)
+ */
+MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
+				       DWORD fdwPrepare)
+{
+    PWINE_ACMSTREAM	was;
+    MMRESULT		ret = MMSYSERR_NOERROR;
+    PACMDRVSTREAMHEADER	padsh;
+
+    TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
+    
+    if ((was = ACM_GetStream(has)) == NULL)
+	return MMSYSERR_INVALHANDLE;
+    if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
+	return MMSYSERR_INVALPARAM;
+    if (fdwPrepare)
+	ret = MMSYSERR_INVALFLAG;
+
+    if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
+	return MMSYSERR_NOERROR;
+
+    /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
+     * size. some fields are private to msacm internals, and are exposed
+     * in ACMSTREAMHEADER in the dwReservedDriver array
+     */
+    padsh = (PACMDRVSTREAMHEADER)pash;
+
+    padsh->fdwConvert = fdwPrepare;
+    padsh->padshNext = NULL;
+    padsh->fdwDriver = padsh->dwDriver = 0L;
+
+    padsh->fdwPrepared = 0;
+    padsh->dwPrepared = 0;
+    padsh->pbPreparedSrc = 0;
+    padsh->cbPreparedSrcLength = 0;
+    padsh->pbPreparedDst = 0;
+    padsh->cbPreparedDstLength = 0;
+
+    ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
+    if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
+	ret = MMSYSERR_NOERROR;
+	padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
+	padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
+	padsh->fdwPrepared = padsh->fdwStatus;
+	padsh->dwPrepared = 0;
+	padsh->pbPreparedSrc = padsh->pbSrc;
+	padsh->cbPreparedSrcLength = padsh->cbSrcLength;
+	padsh->pbPreparedDst = padsh->pbDst;
+	padsh->cbPreparedDstLength = padsh->cbDstLength;
+    } else {
+	padsh->fdwPrepared = 0;
+	padsh->dwPrepared = 0;
+	padsh->pbPreparedSrc = 0;
+	padsh->cbPreparedSrcLength = 0;
+	padsh->pbPreparedDst = 0;
+	padsh->cbPreparedDstLength = 0;
+    }
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *           acmStreamReset (MSACM32.42)
+ */
+MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
+{
+    PWINE_ACMSTREAM	was;
+    MMRESULT		ret = MMSYSERR_NOERROR;
+
+    TRACE("(0x%08x, %ld)\n", has, fdwReset);
+
+    if (fdwReset) {
+	ret = MMSYSERR_INVALFLAG;
+    } else if ((was = ACM_GetStream(has)) == NULL) {
+	return MMSYSERR_INVALHANDLE;
+    } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
+	ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
+    }
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}
+
+/***********************************************************************
+ *           acmStreamSize (MSACM32.43)
+ */
+MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, 
+			      LPDWORD pdwOutputBytes, DWORD fdwSize)
+{
+    PWINE_ACMSTREAM	was;
+    ACMDRVSTREAMSIZE	adss;
+    MMRESULT		ret;
+    
+    TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
+    
+    if ((was = ACM_GetStream(has)) == NULL) {
+	return MMSYSERR_INVALHANDLE;
+    }
+    if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
+	return MMSYSERR_INVALFLAG;
+    }
+
+    *pdwOutputBytes = 0L;
+    
+    switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
+    case ACM_STREAMSIZEF_DESTINATION:
+	adss.cbDstLength = cbInput;
+	adss.cbSrcLength = 0;
+	break;
+    case ACM_STREAMSIZEF_SOURCE:
+	adss.cbSrcLength = cbInput;
+	adss.cbDstLength = 0;
+	break;
+    default:	
+	return MMSYSERR_INVALFLAG;
+    }
+    
+    adss.cbStruct = sizeof(adss);
+    adss.fdwSize = fdwSize;
+    ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, 
+			    (DWORD)&was->drvInst, (DWORD)&adss);
+    if (ret == MMSYSERR_NOERROR) {
+	switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
+	case ACM_STREAMSIZEF_DESTINATION:
+	    *pdwOutputBytes = adss.cbSrcLength;
+	    break;
+	case ACM_STREAMSIZEF_SOURCE:
+	    *pdwOutputBytes = adss.cbDstLength;
+	    break;
+	}
+    }
+    TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
+    return ret;
+}
+
+/***********************************************************************
+ *           acmStreamUnprepareHeader (MSACM32.44)
+ */
+MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
+					 DWORD fdwUnprepare)
+{
+    PWINE_ACMSTREAM	was;
+    MMRESULT		ret = MMSYSERR_NOERROR;
+    PACMDRVSTREAMHEADER	padsh;
+
+    TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
+    
+    if ((was = ACM_GetStream(has)) == NULL)
+	return MMSYSERR_INVALHANDLE;
+    if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
+	return MMSYSERR_INVALPARAM;
+
+    if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
+	return ACMERR_UNPREPARED;
+
+    /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
+     * size. some fields are private to msacm internals, and are exposed
+     * in ACMSTREAMHEADER in the dwReservedDriver array
+     */
+    padsh = (PACMDRVSTREAMHEADER)pash;
+
+    /* check that pointers have not been modified */
+    if (padsh->pbPreparedSrc != padsh->pbSrc ||
+	padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
+	padsh->pbPreparedDst != padsh->pbDst ||
+	padsh->cbPreparedDstLength < padsh->cbDstLength) {
+	return MMSYSERR_INVALPARAM;
+    }	
+
+    padsh->fdwConvert = fdwUnprepare;
+
+    ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
+    if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
+	ret = MMSYSERR_NOERROR;
+	padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
+    }
+    TRACE("=> (%d)\n", ret);
+    return ret;
+}