// 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 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 _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; }