📄 stream.c
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* MSACM32 library
*
* Copyright 1998 Patrik Stridvall
* 1999 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* TODO
* + asynchronous conversion is not implemented
* + callback/notification
* * acmStreamMessage
* + properly close ACM streams
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "mmsystem.h"
#include "mmreg.h"
#include "msacm.h"
#include "msacmdrv.h"
#include "wineacm.h"
WINE_DEFAULT_DEBUG_CHANNEL(msacm);
static PWINE_ACMSTREAM ACM_GetStream(HACMSTREAM has)
{
TRACE("(%p)\n", has);
return (PWINE_ACMSTREAM)has;
}
/***********************************************************************
* acmStreamClose (MSACM32.@)
*/
MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
{
PWINE_ACMSTREAM was;
MMRESULT ret;
TRACE("(%p, %ld)\n", has, fdwClose);
if ((was = ACM_GetStream(has)) == NULL) {
WARN("invalid handle\n");
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.@)
*/
MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash,
DWORD fdwConvert)
{
PWINE_ACMSTREAM was;
MMRESULT ret = MMSYSERR_NOERROR;
PACMDRVSTREAMHEADER padsh;
TRACE("(%p, %p, %ld)\n", has, pash, fdwConvert);
if ((was = ACM_GetStream(has)) == NULL) {
WARN("invalid handle\n");
return MMSYSERR_INVALHANDLE;
}
if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER)) {
WARN("invalid parameter\n");
return MMSYSERR_INVALPARAM;
}
if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)) {
WARN("unprepared header\n");
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) {
WARN("invalid parameter\n");
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;
}
/***********************************************************************
* acmStreamMessage (MSACM32.@)
*/
MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1,
LPARAM lParam2)
{
FIXME("(%p, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return MMSYSERR_ERROR;
}
/***********************************************************************
* acmStreamOpen (MSACM32.@)
*/
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;
WAVEFORMATEX wfxSrc, wfxDst;
TRACE("(%p, %p, %p, %p, %p, %ld, %ld, %ld)\n",
phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
/* NOTE: pwfxSrc and/or pwfxDst can point to a structure smaller than
* WAVEFORMATEX so don't use them directly when not sure */
if (pwfxSrc->wFormatTag == WAVE_FORMAT_PCM) {
memcpy(&wfxSrc, pwfxSrc, sizeof(PCMWAVEFORMAT));
wfxSrc.wBitsPerSample = pwfxSrc->wBitsPerSample;
wfxSrc.cbSize = 0;
pwfxSrc = &wfxSrc;
}
if (pwfxDst->wFormatTag == WAVE_FORMAT_PCM) {
memcpy(&wfxDst, pwfxDst, sizeof(PCMWAVEFORMAT));
wfxDst.wBitsPerSample = pwfxDst->wBitsPerSample;
wfxDst.cbSize = 0;
pwfxDst = &wfxDst;
}
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);
/* (WS) In query mode, phas should be NULL. If it is not, then instead
* of returning an error we are making sure it is NULL, preventing some
* applications that pass garbage for phas from crashing.
*/
if (fdwOpen & ACM_STREAMOPENF_QUERY) phas = NULL;
if (pwfltr && (pwfxSrc->wFormatTag != pwfxDst->wFormatTag)) {
WARN("invalid parameter\n");
return MMSYSERR_INVALPARAM;
}
wfxSrcSize = wfxDstSize = sizeof(WAVEFORMATEX);
if (pwfxSrc->wFormatTag != WAVE_FORMAT_PCM) wfxSrcSize += pwfxSrc->cbSize;
if (pwfxDst->wFormatTag != WAVE_FORMAT_PCM) wfxDstSize += pwfxDst->cbSize;
was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize +
((pwfltr) ? sizeof(WAVEFILTER) : 0));
if (was == NULL) {
WARN("no memory\n");
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;
/* real value will be stored once ACMDM_STREAM_OPEN succeeds */
was->drvInst.has = 0L;
if (had) {
if (!(wad = MSACM_GetDriver(had))) {
ret = MMSYSERR_INVALPARAM;
goto errCleanUp;
}
was->obj.dwType = WINE_ACMOBJ_STREAM;
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;
ret = ACMERR_NOTPOSSIBLE;
for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
if ((wadi->fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED) ||
!MSACM_FindFormatTagInCache(wadi, pwfxSrc->wFormatTag, NULL) ||
!MSACM_FindFormatTagInCache(wadi, pwfxDst->wFormatTag, NULL))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -