Logo Search packages:      
Sourcecode: wine version File versions  Download package

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"
#define NOBITMAP
#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 = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_CLOSE, (LPARAM)&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;
    }

    pash->cbSrcLengthUsed = 0;
    pash->cbDstLengthUsed = 0;

    /* 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 = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_CONVERT, (LPARAM)&was->drvInst, (LPARAM)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 = MSACM_Message((HACMDRIVER)wad, ACMDM_STREAM_OPEN, (LPARAM)&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))
            continue;
          ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
          if (ret != MMSYSERR_NOERROR)
            continue;
          if ((wad = MSACM_GetDriver(had)) != 0) {
            was->obj.dwType = WINE_ACMOBJ_STREAM;
            was->obj.pACMDriverID = wad->obj.pACMDriverID;
            was->pDrv = wad;
            was->hAcmDriver = had;

            ret = MSACM_Message((HACMDRIVER)wad, ACMDM_STREAM_OPEN, (LPARAM)&was->drvInst, 0L);
            TRACE("%s => %08x\n", debugstr_w(wadi->pszDriverAlias), ret);
            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;
    was->drvInst.has = (HACMSTREAM)was;
    if (!(fdwOpen & ACM_STREAMOPENF_QUERY)) {
      if (phas)
          *phas = (HACMSTREAM)was;
      TRACE("=> (%d)\n", ret);
      return ret;
    }
errCleanUp:
    if (phas)
      *phas = NULL;
    HeapFree(MSACM_hHeap, 0, was);
    TRACE("=> (%d)\n", ret);
    return ret;
}


/***********************************************************************
 *           acmStreamPrepareHeader (MSACM32.@)
 */
MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
                               DWORD fdwPrepare)
{
    PWINE_ACMSTREAM     was;
    MMRESULT            ret = MMSYSERR_NOERROR;
    PACMDRVSTREAMHEADER padsh;

    TRACE("(%p, %p, %ld)\n", has, pash, fdwPrepare);

    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 (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 = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_PREPARE, (LPARAM)&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.@)
 */
MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
{
    PWINE_ACMSTREAM     was;
    MMRESULT            ret = MMSYSERR_NOERROR;

    TRACE("(%p, %ld)\n", has, fdwReset);

    if (fdwReset) {
        WARN("invalid flag\n");
      ret = MMSYSERR_INVALFLAG;
    } else if ((was = ACM_GetStream(has)) == NULL) {
        WARN("invalid handle\n");
      return MMSYSERR_INVALHANDLE;
    } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
      ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_RESET, (LPARAM)&was->drvInst, 0);
    }
    TRACE("=> (%d)\n", ret);
    return ret;
}

/***********************************************************************
 *           acmStreamSize (MSACM32.@)
 */
MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput,
                        LPDWORD pdwOutputBytes, DWORD fdwSize)
{
    PWINE_ACMSTREAM     was;
    ACMDRVSTREAMSIZE    adss;
    MMRESULT            ret;

    TRACE("(%p, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);

    if ((was = ACM_GetStream(has)) == NULL) {
        WARN("invalid handle\n");
      return MMSYSERR_INVALHANDLE;
    }
    if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
        WARN("invalid flag\n");
      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:
        WARN("invalid flag\n");
      return MMSYSERR_INVALFLAG;
    }

    adss.cbStruct = sizeof(adss);
    adss.fdwSize = fdwSize;
    ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_SIZE,
                            (LPARAM)&was->drvInst, (LPARAM)&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.@)
 */
MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash,
                               DWORD fdwUnprepare)
{
    PWINE_ACMSTREAM     was;
    MMRESULT            ret = MMSYSERR_NOERROR;
    PACMDRVSTREAMHEADER padsh;

    TRACE("(%p, %p, %ld)\n", has, pash, fdwUnprepare);

    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 = fdwUnprepare;

    ret = MSACM_Message((HACMDRIVER)was->pDrv, ACMDM_STREAM_UNPREPARE, (LPARAM)&was->drvInst, (LPARAM)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;
}

Generated by  Doxygen 1.6.0   Back to index