Leaked source code of windows server 2003
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.
 
 
 
 
 
 

863 lines
20 KiB

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
bgaudio.cpp
Abstract:
Implementation of the audio bridge filters.
Author:
Mu Han (muhan) 11/16/1998
--*/
#include "stdafx.h"
CTAPIAudioBridgeSinkFilter::CTAPIAudioBridgeSinkFilter(
IN LPUNKNOWN pUnk,
IN IDataBridge * pIDataBridge,
OUT HRESULT * phr
)
: CTAPIBridgeSinkFilter(pUnk, pIDataBridge, phr)
{
}
HRESULT CTAPIAudioBridgeSinkFilter::CreateInstance(
IN IDataBridge * pIDataBridge,
OUT IBaseFilter ** ppIBaseFilter
)
/*++
Routine Description:
This method create a instance of the bridge's sink filter.
Arguments:
ppIBaseFilter - the returned filter interface pointer.
Return Value:
E_OUTOFMEMORY - no memory for the new object.
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSinkFilter::CreateInstance");
BGLOG((BG_TRACE, "%s entered.", __fxName));
HRESULT hr = S_OK;
CUnknown* pUnknown = new CTAPIAudioBridgeSinkFilter(NULL, pIDataBridge, &hr);
if (pUnknown == NULL)
{
hr = E_OUTOFMEMORY;
BGLOG((BG_ERROR,
"%s, out of memory creating the filter",
__fxName));
}
else if (FAILED(hr))
{
BGLOG((BG_ERROR,
"%s, the filter's constructor failed, hr:%d",
__fxName, hr));
delete pUnknown;
}
else
{
pUnknown->NonDelegatingAddRef();
hr = pUnknown->NonDelegatingQueryInterface(
__uuidof(IBaseFilter), (void **)ppIBaseFilter
);
pUnknown->NonDelegatingRelease();
}
BGLOG((BG_TRACE,
"%s, returning:%p, hr:%x", __fxName, *ppIBaseFilter, hr));
return hr;
}
HRESULT CTAPIAudioBridgeSinkFilter::GetMediaType(
IN int iPosition,
OUT CMediaType *pMediaType
)
/*++
Routine Description:
Get the media type that this filter wants to support. Currently we
only support PCM L16 8KHz samples.
Arguments:
IN int iPosition,
the index of the media type, zero based..
In CMediaType *pMediaType
Pointer to a CMediaType object to save the returned media type.
Return Value:
S_OK - success
E_OUTOFMEMORY - no memory
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSinkFilter::GetMediaType");
BGLOG((BG_TRACE,
"%s, iPosition:%d, pMediaType:%p",
__fxName, iPosition, pMediaType));
HRESULT hr = VFW_S_NO_MORE_ITEMS;
BGLOG((BG_TRACE, "%s returns %d", __fxName, hr));
return hr;
}
HRESULT CTAPIAudioBridgeSinkFilter::CheckMediaType(
const CMediaType *pMediaType
)
/*++
Routine Description:
Check the media type that this filter wants to support. Currently we
only support PCM L16 8KHz samples.
Arguments:
In CMediaType *pMediaType
Pointer to a CMediaType object to save the returned media type.
Return Value:
S_OK - success
E_OUTOFMEMORY - no memory
E_UNEXPECTED - internal media type not set
VFW_E_TYPE_NOT_ACCEPTED - media type rejected
VFW_E_INVALIDMEDIATYPE - bad media type
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSinkFilter::CheckMediaType");
BGLOG((BG_TRACE,
"%s, pMediaType:%p", __fxName, pMediaType));
ASSERT(!IsBadReadPtr(pMediaType, sizeof(AM_MEDIA_TYPE)));
// media type is only stored in source filter
// return S_OK here
// if error, the source filter will detect it anyway
HRESULT hr = S_OK;
BGLOG((BG_TRACE, "%s returns %d", __fxName, hr));
return hr;
}
CTAPIAudioBridgeSourceFilter::CTAPIAudioBridgeSourceFilter(
IN LPUNKNOWN pUnk,
OUT HRESULT * phr
)
: CTAPIBridgeSourceFilter(pUnk, phr)
{
m_fPropSet = FALSE; // allocator properties not set yet
m_fMtSet = FALSE; // media type not set yet
// m_last_wall_time, m_last_stream_time not initiated
m_fClockStarted = FALSE;
m_fJustBurst = FALSE;
m_nInputSize = 0;
m_nOutputSize = 0;
m_nOutputFree = 0;
m_pOutputSample = NULL;
}
CTAPIAudioBridgeSourceFilter::~CTAPIAudioBridgeSourceFilter ()
{
if (m_fMtSet)
{
FreeMediaType (m_mt);
}
if (NULL != m_pOutputSample)
{
m_pOutputSample->Release ();
}
}
HRESULT CTAPIAudioBridgeSourceFilter::CreateInstance(
OUT IBaseFilter ** ppIBaseFilter
)
/*++
Routine Description:
This method create a instance of the bridge's sink filter.
Arguments:
ppIBaseFilter - the returned filter interface pointer.
Return Value:
E_OUTOFMEMORY - no memory for the new object.
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSourceFilter::CreateInstance");
BGLOG((BG_TRACE, "%s entered.", __fxName));
HRESULT hr = S_OK;
CUnknown* pUnknown = new CTAPIAudioBridgeSourceFilter(NULL, &hr);
if (pUnknown == NULL)
{
hr = E_OUTOFMEMORY;
BGLOG((BG_ERROR,
"%s, out of memory creating the filter",
__fxName));
}
else if (FAILED(hr))
{
BGLOG((BG_ERROR,
"%s, the filter's constructor failed, hr:%d",
__fxName, hr));
delete pUnknown;
}
else
{
pUnknown->NonDelegatingAddRef();
hr = pUnknown->NonDelegatingQueryInterface(
__uuidof(IBaseFilter), (void **)ppIBaseFilter
);
pUnknown->NonDelegatingRelease();
}
BGLOG((BG_TRACE,
"%s, returning:%p, hr:%x", __fxName, *ppIBaseFilter, hr));
return hr;
}
HRESULT CTAPIAudioBridgeSourceFilter::GetMediaType(
IN int iPosition,
OUT CMediaType *pMediaType
)
/*++
Routine Description:
Get the media type that this filter wants to support. Currently we
only support PCM L16 8KHz samples.
Arguments:
IN int iPosition,
the index of the media type, zero based..
In CMediaType *pMediaType
Pointer to a CMediaType object to save the returned media type.
Return Value:
S_OK - success
E_OUTOFMEMORY - no memory
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSourceFilter::GetMediaType");
BGLOG((BG_TRACE,
"%s, iPosition:%d, pMediaType:%p",
__fxName, iPosition, pMediaType));
ASSERT(!IsBadWritePtr(pMediaType, sizeof(AM_MEDIA_TYPE)));
HRESULT hr;
if (iPosition == 0)
{
AM_MEDIA_TYPE *pmt = NULL;
hr = m_pOutputPin->GetFormat (&pmt);
if (FAILED(hr))
return hr;
*pMediaType = *pmt;
FreeMediaType (*pmt);
free (pmt);
}
else
{
hr = VFW_S_NO_MORE_ITEMS;
}
// END
BGLOG((BG_TRACE, "%s returns %d", __fxName, hr));
return hr;
}
HRESULT CTAPIAudioBridgeSourceFilter::CheckMediaType(
const CMediaType *pMediaType
)
/*++
Routine Description:
Check the media type that this filter wants to support. Currently we
only support PCM L16 8KHz samples.
Arguments:
In CMediaType *pMediaType
Pointer to a CMediaType object to save the returned media type.
Return Value:
S_OK - success
E_OUTOFMEMORY - no memory
VFW_E_TYPE_NOT_ACCEPTED - media type rejected
VFW_E_INVALIDMEDIATYPE - bad media type
--*/
{
ENTER_FUNCTION("CTAPIAudioBridgeSourceFilter::CheckMediaType");
BGLOG((BG_TRACE,
"%s, pMediaType:%p", __fxName, pMediaType));
ASSERT(!IsBadReadPtr(pMediaType, sizeof(AM_MEDIA_TYPE)));
if (!m_fMtSet)
{
BGLOG ((BG_ERROR, "%s tries to check media type before setting", __fxName));
return E_UNEXPECTED;
}
// create media type based on stored AM_MEDIA_TYPE
CMediaType *pmediatype = new CMediaType (m_mt);
if (NULL == pmediatype)
{
BGLOG ((BG_ERROR, "%s failed to new media type class", __fxName));
return E_OUTOFMEMORY;
}
HRESULT hr;
if (*pMediaType == *pmediatype)
hr = S_OK;
else
{
hr = VFW_E_TYPE_NOT_ACCEPTED;
BGLOG ((BG_TRACE, "%s rejects media type class %p", __fxName, pMediaType));
}
delete pmediatype;
BGLOG((BG_TRACE, "%s returns %d", __fxName, hr));
return hr;
}
HRESULT CTAPIAudioBridgeSourceFilter::SendSample(
IN IMediaSample *pSample
)
/*++
Routine Description:
Process a sample from the bridge sink filter. Overides the base implementation
Arguments:
pSample - The media sample object.
Return Value:
HRESULT.
--*/
{
HRESULT hr;
ENTER_FUNCTION ("CTAPIAudioBridgeSourceFilter::SendSample");
CAutoLock Lock(m_pLock);
_ASSERT(m_pOutputPin != NULL);
// we don't deliver anything if the filter is not in running state.
if (m_State != State_Running)
{
return S_OK;
}
// if the sample is the 1st of the burst
if (S_OK == pSample->IsDiscontinuity ())
{
LONGLONG start, end;
m_fJustBurst = TRUE;
if (S_OK != (hr = pSample->GetTime (&start, &end)))
{
BGLOG ((BG_TRACE, "%s, 1st sample in a burst, GetTime returns %x", __fxName, hr));
// timestampes stored remain unchange
return S_OK;
}
// else. in NT 5.1, 1st sample has valid timestamp.
}
// check if allocator properties is set
if (!m_fPropSet)
{
BGLOG ((BG_ERROR, "%s tries to send sample before setting allocator property", __fxName));
return E_UNEXPECTED;
}
// check if media type is set
if (!m_fMtSet)
{
BGLOG ((BG_ERROR, "%s tries to send sample before setting media type", __fxName));
return E_UNEXPECTED;
}
/*
* get size info
*/
// get input sample size and output allocator size
HRESULT nInputSize, nOutputSize;
nInputSize = pSample->GetActualDataLength ();
nOutputSize = m_prop.cbBuffer;
// 1st run, record size
if (m_nInputSize == 0 || m_nOutputSize == 0)
{
m_nInputSize = nInputSize;
m_nOutputSize = nOutputSize;
}
if (
m_nInputSize != nInputSize ||
m_nOutputSize != nOutputSize ||
m_nInputSize == 0 ||
m_nOutputSize == 0
)
{
BGLOG ((BG_ERROR, "%s, sample size (%d => %d) or output size (%d => %d) is changed",
__fxName, m_nInputSize, nInputSize, m_nOutputSize, nOutputSize));
return E_UNEXPECTED;
}
/*
* get time info
*/
REFERENCE_TIME wall;
// wall time
if (FAILED (hr = m_pClock->GetTime (&wall)))
{
BGLOG ((BG_ERROR, "%s failed to get wall time", __fxName));
return hr;
}
// if timestamp not initiated
if (!m_fClockStarted)
{
m_last_stream_time = 0;
m_last_wall_time = wall;
m_fClockStarted = TRUE;
// delta is the time of playing sample:
m_output_sample_time = nOutputSize * 80000; // s->10000ns, bits->bytes
m_output_sample_time /= ((WAVEFORMATEX*)m_mt.pbFormat)->wBitsPerSample *
((WAVEFORMATEX*)m_mt.pbFormat)->nSamplesPerSec;
m_output_sample_time *= 1000; // bytes/100ns
}
/*
* calculate new stream time
*/
if (m_fJustBurst)
{
// 1st useful sample after burst
m_last_stream_time += (wall - m_last_wall_time);
m_last_wall_time = wall;
m_fJustBurst = FALSE;
// clear buffer
if (NULL != m_pOutputSample)
{
m_pOutputSample->Release ();
m_pOutputSample = NULL;
m_nOutputFree = 0;
}
}
REFERENCE_TIME end = m_last_stream_time + m_output_sample_time;
/*
* case 1: input size == output size
*/
if (m_nInputSize == m_nOutputSize)
{
if (FAILED (pSample->SetTime (&m_last_stream_time, &end)))
{
BGLOG ((BG_ERROR, "%s failed to set time", __fxName));
}
// adjust time
m_last_stream_time = end;
m_last_wall_time += m_output_sample_time;
// deliver directly
return m_pOutputPin->Deliver(pSample);
}
/*
* case 2: size differs
*/
BYTE *pInputBuffer, *pOutputBuffer;
if (FAILED (hr = pSample->GetPointer (&pInputBuffer)))
{
BGLOG ((BG_ERROR, "%s failed to get buffer pointer from input sample %p",
__fxName, pSample));
return hr;
}
LONG nNextPos = 0;
// old fashion goto
DELIVERY_BUFFER:
// get delivery buffer if it's null
if (NULL == m_pOutputSample)
{
hr = m_pOutputPin->GetDeliveryBuffer (
&m_pOutputSample, // media sample **
NULL, // start time
NULL, // end time
AM_GBF_NOTASYNCPOINT // dynamic format changes are not allowed,
);
if (FAILED (hr))
{
BGLOG ((BG_ERROR, "%s, output pin failed to get delivery buffer. return %d",
__fxName, hr));
return hr;
}
if (m_pOutputSample->GetSize() < m_nOutputSize)
{
// oops, what happend, the size should be the same
BGLOG ((BG_ERROR, "%s, delivery buffer size %d and output size %d are inconsistent",
__fxName, m_pOutputSample->GetSize(), m_nOutputSize));
return E_UNEXPECTED;
}
// set size
if (FAILED (hr = m_pOutputSample->SetActualDataLength (m_nOutputSize)))
{
BGLOG ((BG_ERROR, "%s failed to set output sample size", __fxName));
return hr;
}
/*
// set format
if (FAILED (hr = m_pOutputSample->SetMediaType (&m_mt)))
{
BGLOG ((BG_ERROR, "%s failed to set media type for delivery buffer", __fxName));
return hr;
}
*/
// set time
if (FAILED (hr = m_pOutputSample->SetTime (&m_last_stream_time, &end)))
{
BGLOG ((BG_ERROR, "%s failed to set stream time for delivery buffer", __fxName));
return hr;
}
// the whole buffer is free
m_nOutputFree = m_nOutputSize;
}
// get buffer in output sample
if (FAILED (hr = m_pOutputSample->GetPointer (&pOutputBuffer)))
{
BGLOG ((BG_ERROR, "%s failed to get buffer pointer from output sample %p",
__fxName, m_pOutputSample));
// release output sample
m_pOutputSample->Release ();
m_pOutputSample = NULL;
m_nOutputFree = 0;
return hr;
}
// if input buffer is smaller than free output buffer
// copy input to output and return
if (m_nInputSize-nNextPos < m_nOutputFree)
{
CopyMemory (
(PVOID)(pOutputBuffer + (m_nOutputSize - m_nOutputFree)),
(PVOID)(pInputBuffer + nNextPos),
(DWORD)(m_nInputSize - nNextPos)
);
// reduce free buffer size
m_nOutputFree -= m_nInputSize - nNextPos;
return S_OK;
}
// else: input buffer is greater or equal to free output buffer
CopyMemory (
(PVOID)(pOutputBuffer + (m_nOutputSize - m_nOutputFree)),
(PVOID)(pInputBuffer + nNextPos),
(DWORD)(m_nOutputFree)
);
// now output sample is full, deliver it
if (FAILED (hr = m_pOutputPin->Deliver (m_pOutputSample)))
{
BGLOG ((BG_ERROR, "%s failed to deliver copied sample. return %x", __fxName, hr));
// clear sample
m_pOutputSample->Release ();
m_pOutputSample = NULL;
m_nOutputFree = 0;
return hr;
}
// adjust next position in input buffer
nNextPos += m_nOutputFree;
// clear output sample since it was deliverd
m_pOutputSample->Release ();
m_pOutputSample = NULL;
m_nOutputFree = 0;
// adjust time
m_last_stream_time = end;
m_last_wall_time += m_output_sample_time;
// check if nothing left
if (nNextPos == m_nInputSize)
return S_OK;
// there is more in input buffer
goto DELIVERY_BUFFER;
}
HRESULT CTAPIAudioBridgeSourceFilter::GetAllocatorProperties (OUT ALLOCATOR_PROPERTIES *pprop)
/*++
Routine Description:
Returns the allocator properties
Arguments:
pprop -
The pointer to an ALLOCATOR_PROPERTIES
Return Value:
E_POINTER -
if pprop is NULL
S_OK
--*/
{
ENTER_FUNCTION ("CTAPIAudioBridgeSourceFilter::GetAllocatorProperties");
_ASSERT(pprop);
if (!pprop)
return E_POINTER;
if (!m_fPropSet)
{
BGLOG ((BG_INFO, "%s retrieves allocator properties before setting", __fxName));
// return default value anyway
// buffer size = (16bits / 8bits) * 8khz * 30 ms = 480 bytes
pprop->cBuffers = 1;
pprop->cbBuffer = 480; // default
pprop->cbAlign = 0;
pprop->cbPrefix = 0;
return S_OK;
}
// properties were set
pprop->cBuffers = m_prop.cBuffers;
pprop->cbBuffer = m_prop.cbBuffer;
pprop->cbAlign = m_prop.cbAlign;
pprop->cbPrefix = m_prop.cbPrefix;
return S_OK;
}
HRESULT CTAPIAudioBridgeSourceFilter::SuggestAllocatorProperties (IN const ALLOCATOR_PROPERTIES *pprop)
/*++
Routine Description:
Asks the pin to use the allocator buffer properties
Arguments:
pprop -
The pointer to an ALLOCATOR_PROPERTIES
Return Value:
E_POINTER
S_OK
--*/
{
_ASSERT (pprop);
if (!pprop)
return E_POINTER;
m_prop.cBuffers = pprop->cBuffers;
m_prop.cbBuffer = pprop->cbBuffer;
m_prop.cbAlign = pprop->cbAlign;
m_prop.cbPrefix = pprop->cbPrefix;
m_fPropSet = TRUE;
return S_OK;
}
HRESULT CTAPIAudioBridgeSourceFilter::GetFormat (OUT AM_MEDIA_TYPE **ppmt)
/*++
Routine Description:
Retrieves the stream format
Arguments:
ppmt -
Address of a pointer to an AM_MEDIA_TYPE structure
Return Value:
E_PONTER
E_OUTOFMEMORY
HRESULT of SetFormat
S_OK
--*/
{
ENTER_FUNCTION ("CTAPIAudioBridgeSourceFilter::GetFormat");
_ASSERT (ppmt);
if (NULL == ppmt)
return E_POINTER;
if (NULL != *ppmt)
BGLOG ((BG_INFO, "is media type structure freed when passed in %s?", __fxName));
*ppmt = new AM_MEDIA_TYPE;
if (NULL == *ppmt)
{
BGLOG ((BG_ERROR, "%s out of memory", __fxName));
return E_OUTOFMEMORY;
}
if (!m_fMtSet)
{
BGLOG ((BG_INFO, "%s retrieves media type before setting. Default is to set.", __fxName));
// st format
HRESULT hr;
AM_MEDIA_TYPE mt;
WAVEFORMATEX wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = 16;
wfx.nChannels = 1;
wfx.nSamplesPerSec = 8000;
wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
wfx.nAvgBytesPerSec = ((DWORD) wfx.nBlockAlign * wfx.nSamplesPerSec);
wfx.cbSize = 0;
mt.majortype = MEDIATYPE_Audio;
mt.subtype = MEDIASUBTYPE_PCM;
mt.bFixedSizeSamples = TRUE;
mt.bTemporalCompression = FALSE;
mt.lSampleSize = 0;
mt.formattype = FORMAT_WaveFormatEx;
mt.pUnk = NULL;
mt.cbFormat = sizeof(WAVEFORMATEX);
mt.pbFormat = (BYTE*)&wfx;
hr = SetFormat (&mt);
if (FAILED (hr))
{
BGLOG ((BG_ERROR, "%s, failed to set default format", __fxName));
return hr;
}
}
CopyMediaType (*ppmt, &m_mt);
return S_OK;
}
HRESULT CTAPIAudioBridgeSourceFilter::SetFormat (IN AM_MEDIA_TYPE *pmt)
/*++
Routine Description:
Sets the stream format
Arguments:
pmt -
Pointer to an AM_MEDIA_TYPE structure
Return Value:
E_POINTER
S_OK
--*/
{
_ASSERT (pmt);
if (NULL == pmt)
return E_POINTER;
CopyMediaType (&m_mt, pmt);
m_fMtSet = TRUE;
return S_OK;
}