mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
8.4 KiB
313 lines
8.4 KiB
// Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
|
|
// austrm.cpp : Implementation of CAudioStream
|
|
#include "stdafx.h"
|
|
#include "project.h"
|
|
#include "austrm.h"
|
|
|
|
// Helper
|
|
void SetWaveFormatEx(
|
|
LPWAVEFORMATEX pFormat,
|
|
int nChannels,
|
|
int nBitsPerSample,
|
|
int nSamplesPerSecond
|
|
)
|
|
{
|
|
pFormat->wFormatTag = WAVE_FORMAT_PCM;
|
|
pFormat->nChannels = (WORD)nChannels;
|
|
pFormat->nSamplesPerSec = (DWORD)nSamplesPerSecond;
|
|
pFormat->nBlockAlign = (WORD)((nBitsPerSample * nChannels) / 8);
|
|
pFormat->nAvgBytesPerSec = (DWORD)(nSamplesPerSecond * pFormat->nBlockAlign);
|
|
pFormat->wBitsPerSample = (WORD)nBitsPerSample;
|
|
pFormat->cbSize = 0;
|
|
}
|
|
|
|
HRESULT ConvertWAVEFORMATEXToMediaType(
|
|
const WAVEFORMATEX *pFormat,
|
|
AM_MEDIA_TYPE **ppmt
|
|
)
|
|
{
|
|
AM_MEDIA_TYPE *pmt;
|
|
pmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(*pmt));
|
|
if (pmt == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
_ASSERTE(pFormat->wFormatTag == WAVE_FORMAT_PCM);
|
|
ZeroMemory(pmt, sizeof(*pmt));
|
|
pmt->majortype = MEDIATYPE_Audio;
|
|
pmt->formattype = FORMAT_WaveFormatEx;
|
|
pmt->bFixedSizeSamples = TRUE;
|
|
pmt->lSampleSize = pFormat->nBlockAlign;
|
|
pmt->cbFormat = sizeof(*pFormat);
|
|
pmt->pbFormat = (PBYTE)CoTaskMemAlloc(sizeof(*pFormat));
|
|
if (pmt->pbFormat == NULL) {
|
|
CoTaskMemFree(pmt);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
CopyMemory(pmt->pbFormat, pFormat, sizeof(*pFormat));
|
|
*ppmt = pmt;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CAudioStream
|
|
|
|
CAudioStream::CAudioStream() :
|
|
m_fForceFormat(false)
|
|
{
|
|
// Set to mono 16bit PCM 11025Hz
|
|
SetWaveFormatEx(&m_Format, 1, 16, 11025);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CAudioStream::ReceiveConnection(
|
|
IPin * pConnector,
|
|
const AM_MEDIA_TYPE *pmt
|
|
)
|
|
{
|
|
AUTO_CRIT_LOCK;
|
|
//
|
|
// This helper function in CStream checks basic parameters for the Pin such as
|
|
// the connecting pin's direction (we need to check this -- Sometimes the filter
|
|
// graph will try to connect us to ourselves!) and other errors like already being
|
|
// connected, etc.
|
|
//
|
|
HRESULT hr = CheckReceiveConnectionPin(pConnector);
|
|
if (hr == NOERROR) {
|
|
/* Accept only the format we've been given. If we
|
|
haven't been given a format accept PCM only
|
|
*/
|
|
if (pmt->majortype != MEDIATYPE_Audio ||
|
|
pmt->formattype != FORMAT_WaveFormatEx ||
|
|
pmt->cbFormat < sizeof(WAVEFORMATEX)) {
|
|
hr = VFW_E_TYPE_NOT_ACCEPTED;
|
|
} else {
|
|
hr = InternalSetFormat((LPWAVEFORMATEX)pmt->pbFormat, true);
|
|
if (SUCCEEDED(hr)) {
|
|
CopyMediaType(&m_ConnectedMediaType, pmt);
|
|
m_pConnectedPin = pConnector;
|
|
}
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::SetSameFormat(IMediaStream *pStream, DWORD dwFlags)
|
|
{
|
|
CComQIPtr<IAudioMediaStream, &IID_IAudioMediaStream> pSource(pStream);
|
|
if (!pSource) {
|
|
return MS_E_INCOMPATIBLE;
|
|
}
|
|
WAVEFORMATEX wfx;
|
|
HRESULT hr = pSource->GetFormat(&wfx);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = SetFormat(&wfx);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::AllocateSample(DWORD dwFlags, IStreamSample **ppNewSample)
|
|
{
|
|
IAudioStreamSample *pSample = NULL;
|
|
IAudioData *pAudioData;
|
|
HRESULT hr = CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IAudioData, (void **)&pAudioData);
|
|
if (SUCCEEDED(hr)) {
|
|
// Pick a sensible buffer size - 1/10 second
|
|
DWORD dwBufferSize = m_Format.nAvgBytesPerSec / 10 +
|
|
m_Format.nBlockAlign - 1;
|
|
dwBufferSize -= dwBufferSize % m_Format.nBlockAlign;
|
|
pAudioData->SetBuffer(dwBufferSize, NULL, 0);
|
|
pAudioData->SetFormat(&m_Format);
|
|
hr = CreateSample(pAudioData, 0, &pSample);
|
|
}
|
|
*ppNewSample = pSample;
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::CreateSharedSample(
|
|
/* [in] */ IStreamSample *pExistingSample,
|
|
DWORD dwFlags,
|
|
/* [out] */ IStreamSample **ppNewSample
|
|
)
|
|
{
|
|
AUTO_CRIT_LOCK;
|
|
// See if we can get the information we need from the existing
|
|
// sample
|
|
IAudioStreamSample *pAudioSample;
|
|
HRESULT hr = pExistingSample->QueryInterface(
|
|
IID_IAudioStreamSample,
|
|
(void **)&pAudioSample);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
IAudioData *pAudioData;
|
|
hr = pAudioSample->GetAudioData(&pAudioData);
|
|
pAudioSample->Release();
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
IAudioStreamSample *pNewSample;
|
|
hr = CreateSample(pAudioData, 0, &pNewSample);
|
|
pAudioData->Release();
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
hr = pNewSample->QueryInterface(IID_IStreamSample, (void**)ppNewSample);
|
|
pNewSample->Release();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::SetFormat(const WAVEFORMATEX *pFormat)
|
|
{
|
|
if (pFormat == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
AUTO_CRIT_LOCK;
|
|
return InternalSetFormat(pFormat, false);
|
|
}
|
|
STDMETHODIMP CAudioStream::GetFormat(LPWAVEFORMATEX pFormat)
|
|
{
|
|
if (pFormat == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
if (!m_pConnectedPin) {
|
|
return MS_E_NOSTREAM;
|
|
}
|
|
|
|
*pFormat = m_Format;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::CreateSample(
|
|
/* [in] */ IAudioData *pAudioData,
|
|
/* [in] */ DWORD dwFlags,
|
|
/* [out] */ IAudioStreamSample **ppSample
|
|
)
|
|
{
|
|
if (dwFlags != 0) {
|
|
return E_INVALIDARG;
|
|
}
|
|
if (pAudioData == NULL || ppSample == NULL) {
|
|
return E_POINTER;
|
|
}
|
|
AUTO_CRIT_LOCK;
|
|
// Check the format
|
|
WAVEFORMATEX wfx;
|
|
HRESULT hr = pAudioData->GetFormat(&wfx);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
hr = CheckFormat(&wfx);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
typedef CComObject<CAudioStreamSample> _AudioSample;
|
|
_AudioSample *pSample = new _AudioSample;
|
|
if (pSample == NULL) {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
hr = pSample->Init(pAudioData);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
pSample->InitSample(this, false);
|
|
return pSample->GetControllingUnknown()->QueryInterface(
|
|
IID_IAudioStreamSample, (void **)ppSample
|
|
);
|
|
}
|
|
|
|
HRESULT CAudioStream::CheckFormat(const WAVEFORMATEX *lpFormat, bool bForceFormat)
|
|
{
|
|
if (lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
|
|
lpFormat->nBlockAlign == 0) {
|
|
return E_INVALIDARG;
|
|
}
|
|
if ((m_pConnectedPin || bForceFormat) &&
|
|
0 != memcmp(lpFormat, &m_Format, sizeof(m_Format)))
|
|
{
|
|
// Try reconnection!
|
|
return E_INVALIDARG;
|
|
}
|
|
return S_OK;
|
|
}
|
|
HRESULT CAudioStream::InternalSetFormat(const WAVEFORMATEX *lpFormat, bool bFromPin)
|
|
{
|
|
HRESULT hr = CheckFormat(lpFormat, m_fForceFormat);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
m_Format = *lpFormat;
|
|
m_lBytesPerSecond = m_Format.nAvgBytesPerSec;
|
|
if(!bFromPin) {
|
|
m_fForceFormat = true;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Special CStream methods
|
|
//
|
|
HRESULT CAudioStream::GetMediaType(ULONG Index, AM_MEDIA_TYPE **ppMediaType)
|
|
{
|
|
if (Index != 0) {
|
|
return S_FALSE;
|
|
}
|
|
return ConvertWAVEFORMATEXToMediaType(&m_Format, ppMediaType);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CAudioData
|
|
CAudioData::CAudioData() :
|
|
m_cbSize(0),
|
|
m_pbData(0),
|
|
m_cbData(0),
|
|
m_bWeAllocatedData(false)
|
|
{
|
|
// Set to mono 16bit PCM 11025Hz
|
|
SetWaveFormatEx(&m_Format, 1, 16, 11025);
|
|
}
|
|
|
|
CAudioData::~CAudioData()
|
|
{
|
|
if (m_bWeAllocatedData) {
|
|
CoTaskMemFree(m_pbData);
|
|
}
|
|
}
|
|
|
|
|
|
STDMETHODIMP CAudioStream::GetProperties(ALLOCATOR_PROPERTIES* pProps)
|
|
{
|
|
AUTO_CRIT_LOCK;
|
|
|
|
// NB TAPI relies on this number as a max for now when
|
|
// we're connected to the AVI Mux which uses this size to
|
|
// create its own samples
|
|
pProps->cbBuffer = CAudioStream::GetChopSize();
|
|
|
|
// Default to 5 buffers (half a second at our default buffer size)
|
|
pProps->cBuffers = m_lRequestedBufferCount ? m_lRequestedBufferCount : 5;
|
|
pProps->cbAlign = 1;
|
|
pProps->cbPrefix = 0;
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP CAudioStream::SetProperties(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual)
|
|
{
|
|
HRESULT hr;
|
|
|
|
AUTO_CRIT_LOCK;
|
|
ZeroMemory(pActual, sizeof(*pActual));
|
|
if (pRequest->cbAlign == 0) {
|
|
hr = VFW_E_BADALIGN;
|
|
} else {
|
|
if (m_bCommitted == TRUE) {
|
|
hr = VFW_E_ALREADY_COMMITTED;
|
|
} else {
|
|
m_lRequestedBufferCount = pRequest->cBuffers;
|
|
hr = GetProperties(pActual);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|