Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

941 lines
22 KiB

/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
source.cpp
Abstract:
Implementation of CRtpSourceFilter class.
Environment:
User Mode - Win32
Revision History:
10-Nov-1996 DonRyan
Created.
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
///////////////////////////////////////////////////////////////////////////////
// //
// CRtpSourceFilter Implementation //
// //
///////////////////////////////////////////////////////////////////////////////
CRtpSourceFilter::CRtpSourceFilter(
LPUNKNOWN pUnk,
HRESULT * phr
)
/*++
Routine Description:
Constructor for CRtpSourceFilter class.
Arguments:
pUnk - IUnknown interface of the delegating object.
phr - pointer to the general OLE return value.
Return Values:
Returns an HRESULT value.
--*/
: CSource(
NAME("CRtpSourceFilter"),
pUnk,
CLSID_RTPSourceFilter,
phr
),
CPersistStream(pUnk, phr)
{
TraceDebug((
TRACE_TRACE,
TRACE_DEVELOP,
TEXT("[%x:0x%X]CRtpSourceFilter::CRtpSourceFilter"),
GetCurrentThreadId(), this));
WSADATA WSAData;
WORD VersionRequested = MAKEWORD(1,1);
// initialize winsock first
if (WSAStartup(VersionRequested, &WSAData)) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
TEXT("WSAStartup returned %d"),
WSAGetLastError()
));
// default
*phr = E_FAIL;
return; // bail...
}
// allocate new rtp output pin to use as default
CRtpOutputPin * pRtpOutputPin = new CRtpOutputPin(this, GetOwner(), phr);
if (FAILED(*phr)) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
TEXT("CRtpSourceFilter::CRtpSourceFilter: "
"new CRtpOutputPin() failed: 0x%X"),
*phr
));
return;
}
// validate pointer
if (pRtpOutputPin == NULL) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
TEXT("Could not create CRtpOutputPin")
));
// return default
*phr = E_OUTOFMEMORY;
return; // bail...
}
*phr = NO_ERROR;
//
// pins add themselves to filters's array...
//
}
CRtpSourceFilter::~CRtpSourceFilter(
)
/*++
Routine Description:
Destructor for CRtpSourceFilter class.
Arguments:
None.
Return Values:
None.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_DEVELOP,
TEXT("[%x:0x%X]CRtpSourceFilter::~CRtpSourceFilter"),
GetCurrentThreadId(), this));
// shutdown now
if (WSACleanup()) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
TEXT("WSACleanup returned %d"),
WSAGetLastError()
));
}
//
// pins delete themselves from filter's array
//
}
CUnknown *
CRtpSourceFilter::CreateInstance(
LPUNKNOWN punk,
HRESULT * phr
)
/*++
Routine Description:
Called by COM to create a CRtpSourceFilter object.
Arguments:
pUnk - pointer to the owner of this object.
phr - pointer to an HRESULT value for resulting information.
Return Values:
None.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::CreateInstance")
));
// attempt to create rtp sender object
CRtpSourceFilter * pNewObject = new CRtpSourceFilter(punk, phr);
// validate pointer
if (pNewObject == NULL) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
TEXT("Could not create CRtpSourceFilter")
));
// return default
*phr = E_OUTOFMEMORY;
}
// return object
return pNewObject;
}
///////////////////////////////////////////////////////////////////////////////
// //
// CBaseFilter overrided methods //
// //
///////////////////////////////////////////////////////////////////////////////
LPAMOVIESETUP_FILTER
CRtpSourceFilter::GetSetupData(
)
/*++
Routine Description:
Called by ActiveMovie to retrieve filter setup information.
Arguments:
None.
Return Values:
Returns pointer to filter info structure.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::GetSetupData")
));
// get sink filter info
return &g_RtpSourceFilter;
}
STDMETHODIMP
CRtpSourceFilter::Pause(
)
/*++
Routine Description:
Transitions filter to State_Paused state if it is not in state already.
Arguments:
None.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::Pause")
));
// obtain lock to this object
CAutoLock LockThis(pStateLock());
// check current filter state
if (m_State != State_Paused) {
// obtain number of pins
int cPins = GetPinCount();
// process each pin in filter
for (int c = 0; c < cPins; c++) {
// obtain interface pointer to output pins
CRtpOutputPin * pPin = (CRtpOutputPin *)GetPin(c);
// ignore unconnected pins
if (pPin->IsConnected()) {
// activate pin if stopped else pause
HRESULT hr;
if (m_State == State_Stopped) {
hr = pPin->Active();
} else {
//
// Note: we no longer process pause in the stream thread because
// renderers may block. The stream thread pause actually
// does nothing anyway as our current implementation simply
// stops delivering when in paused state.
//
hr = S_OK;
}
// validate
if (FAILED(hr)) {
TraceDebug((
TRACE_ERROR,
TRACE_DEVELOP,
(m_State == State_Stopped)
? TEXT("CRtpOutputPin::Active returned 0x%08lx")
: TEXT("CRtpOutputPin::Pause returned 0x%08lx"),
hr
));
return hr; // bail...
}
}
}
}
// change state now
m_State = State_Paused;
return NOERROR;
}
// ZCS bugfix 6-20-97 as per mail from amovie guys
// Here we overload the CBaseMediaFilter::GetState() method. The only
// difference is that we return VFW_S_CANT_CUE, which keeps the filter graph
// from hanging when we stop the graph before receiving any packets.
// (The video or audio renderer keeps waiting for a packet to "cue" on -- it
// is in an "inconsistent state" until it gets one -- unless we return
// VFW_S_CANT_CUE here!)
STDMETHODIMP
CRtpSourceFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
{
UNREFERENCED_PARAMETER(dwMSecs);
CheckPointer(State,E_POINTER);
ValidateReadWritePtr(State,sizeof(FILTER_STATE));
*State = m_State;
if (m_State == State_Paused)
{
return VFW_S_CANT_CUE;
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// //
// IBaseFilter implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CRtpSourceFilter::QueryVendorInfo(
LPWSTR * ppVendorInfo
)
/*++
Routine Description:
Returns a vendor information string.
Arguments:
ppVendorInfo - Pointer to a string containing vendor information.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::QueryVendorInfo")
));
// validate pointer
CheckPointer(ppVendorInfo,E_POINTER);
// allocate the description string
*ppVendorInfo = (LPWSTR)CoTaskMemAlloc(
(lstrlenW(g_VendorInfo)+1) * sizeof(WCHAR)
);
// validate pointer
if (*ppVendorInfo == NULL) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("Could not allocate vendor info")
));
return E_OUTOFMEMORY; // bail...
}
// copy vendor description string
lstrcpyW(*ppVendorInfo,g_VendorInfo);
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// //
// IPersistStream implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CRtpSourceFilter::GetClassID(
CLSID *pClsid
)
/*++
Routine Description:
Retrieves the class identifier for this filter.
Arguments:
pClsid - Pointer to a CLSID structure.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::GetClassID")
));
// transfer filter class id
*pClsid = CLSID_RTPSourceFilter;
return S_OK;
}
// ZCS: 6-22-97: copied this from the Demux filter code and modified it...
//
// Name : WriteEntry
// Purpose : A macro that implements the stuff we do to write
// a property of this filter to its persistent stream.
// Context : Used in WriteToStream() to improve readability.
// Returns : Will only return if an error is detected.
// Params :
// Entry Pointer to a buffer containing the value to write.
// InSize Integer indicating the length of the buffer
// OutSize Integer to store the written length.
// Description Char string used to describe the entry.
// Notes :
#define WriteEntry(Entry, InSize, OutSize, Description) \
{ TraceDebug((TRACE_TRACE, 4, TEXT("CRtpSourceFilter::WriteToStream: Writing %s"), Description)); \
hr = pStream->Write(Entry, InSize, &OutSize); \
if (FAILED(hr)) { \
TraceDebug((TRACE_ERROR, 2, TEXT("CRtpSourceFilter::WriteToStream: Error 0x%08x writing %s"), hr, Description)); \
return hr; \
} else if (OutSize != InSize) { \
TraceDebug((TRACE_ERROR, 2, \
TEXT("CRtpSourceFilter::WriteToStream: Too few (%d/%d) bytes written for %s"), \
uBytesWritten, sizeof(int), Description)); \
return E_INVALIDARG; \
} /* if */ }
HRESULT
CRtpSourceFilter::WriteToStream(
IStream *pStream
)
/*++
Routine Description:
Writes the filter's data to the given stream.
Arguments:
pStream - Pointer to an IStream to write the filter's data to.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::WriteToStream")
));
// validate pointer
CheckPointer(pStream,E_POINTER);
// obtain lock to this object
CAutoLock LockThis(pStateLock());
//
// Rest of this function added 6-22-97 by ZCS
//
HRESULT hr; // used in the WriteEntry macro
ULONG uBytesWritten = 0;
DWORD dwRtpAddr;
WORD wRtpPort;
DWORD dwMulticastScope;
DWORD dwQOSstate;
DWORD dwMCLoopBack;
// get the RTP session object so we can see the address, port, scope
CRtpSession *pCRtpSession;
ASSERT(m_iPins == 1);
EXECUTE_ASSERT(SUCCEEDED(((CRtpOutputPin *) *m_paStreams)->GetSession(&pCRtpSession)));
// retrieve the address of the rtp stream object
// for a receiver, local port matters
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetAddress(&wRtpPort,
NULL,
&dwRtpAddr)));
// retrieve multicast scope of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastScope(&dwMulticastScope)));
// retrieve QOS state of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetQOSstate(&dwQOSstate)));
// retrieve Multicast Loopback state of rtp stream object
EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastLoopBack(&dwMCLoopBack)));
// write RTP address/port and multicast to the PersistStream
WriteEntry(&dwRtpAddr, sizeof(dwRtpAddr), uBytesWritten,
"RTP address");
WriteEntry(&wRtpPort, sizeof(wRtpPort), uBytesWritten,
"RTP port");
WriteEntry(&dwMulticastScope, sizeof(dwMulticastScope), uBytesWritten, "multicast scope");
WriteEntry(&dwQOSstate, sizeof(dwQOSstate), uBytesWritten, "QOS state");
WriteEntry(&dwMCLoopBack, sizeof(dwMCLoopBack), uBytesWritten, "Multicast Loopback state");
return S_OK;
}
// ZCS: 6-22-97: copied this from the Demux filter code and modified it...
//
// Name : ReadEntry
// Purpose : A macro that implements the stuff we do to read
// a property of this filter from its persistent stream.
// Context : Used in ReadFromStream() to improve readability.
// Returns : Will only return if an error is detected.
// Params :
// Entry Pointer to a buffer containing the value to read.
// InSize Integer indicating the length of the buffer
// OutSize Integer to store the written length.
// Description Char string used to describe the entry.
// Notes :
HRESULT ReadEntry(IStream *pStream, void *Entry,
DWORD InSize, DWORD *pOutSize, char *Description)
{
HRESULT hr;
TraceDebug((TRACE_TRACE, 4,
TEXT("CRtpSourceFilter::ReadFromStream: Reading %s"),
Description));
hr = pStream->Read(Entry, InSize, pOutSize);
if (FAILED(hr)) {
TraceDebug((TRACE_ERROR, 2,
TEXT("CRtpSourceFilter::ReadFromStream: "
"Error 0x%08x reading %s"),
hr, Description));
return hr;
} else if (*pOutSize != InSize) {
TraceDebug((TRACE_ERROR, 2,
TEXT("CRtpSourceFilter::ReadFromStream: "
"Too few (%d/%d) bytes read for %s"),
*pOutSize, InSize, Description));
return E_INVALIDARG;
}
return(S_OK);
}
HRESULT ReadEntry(IStream *pStream, void *Entry,
DWORD InSize, DWORD *pOutSize, char *Description);
HRESULT
CRtpSourceFilter::ReadFromStream(
IStream *pStream
)
/*++
Routine Description:
Reads the filter's data from the given stream.
Arguments:
pStream - Pointer to an IStream to read the filter's data from.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::ReadFromStream")
));
// validate pointer
CheckPointer(pStream,E_POINTER);
// obtain lock to this object
CAutoLock LockThis(pStateLock());
//
// Rest of this function added 6-22-97 by ZCS based mostly on
// Don Ryan's property page code...
//
HRESULT hr;
DWORD uBytesWritten = 0;
DWORD dwRtpAddr;
WORD wRtpPort;
DWORD RtpScope;
DWORD QOSstate;
DWORD MCLoopBack;
// get the RTP session object so we can see the address, port, scope
CRtpSession *pCRtpSession = NULL;
ASSERT(m_iPins == 1);
// hr = ((CRtpOutputPin *) *m_paStreams)->GetSession(&pCRtpSession);
// if (FAILED(hr)) {
// pCRtpSession = NULL;
// }
// ASSERT(SUCCEEDED(hr));
EXECUTE_ASSERT(SUCCEEDED(((CRtpOutputPin *) *m_paStreams)->
GetSession(&pCRtpSession)));
ASSERT(!IsBadReadPtr(pCRtpSession, sizeof(pCRtpSession)));
// retrieve RTP address and port from stream
hr = ReadEntry(pStream, &dwRtpAddr, sizeof(dwRtpAddr), &uBytesWritten,
"RTP address");
if (FAILED(hr)) return(hr);
hr = ReadEntry(pStream, &wRtpPort, sizeof(wRtpPort), &uBytesWritten,
"RTP address");
if (FAILED(hr)) return(hr);
// attempt to modify the rtp address
// in unicast, the remote port is what matters for a sender
// in multicast, they have to be the same, SetAddress takes care
hr = pCRtpSession->SetAddress(wRtpPort, wRtpPort, dwRtpAddr);
// validate
if (FAILED(hr)) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("IRTPStream::SetAddress returns 0x%08lx"), hr
));
return hr; // bail...
}
// retrieve multicast scope from stream
ReadEntry(pStream, &RtpScope, sizeof(RtpScope), &uBytesWritten,
"multicast scope");
// attempt to modify the scope
hr = pCRtpSession->SetMulticastScope(RtpScope);
// validate
if (FAILED(hr)) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("IRTPStream::SetScope returns 0x%08lx"), hr
));
return hr; // bail...
}
// retrieve QOS state from stream
ReadEntry(pStream, &QOSstate, sizeof(QOSstate), &uBytesWritten,
"QOS state");
// attempt to modify the QOS state
hr = pCRtpSession->SetQOSstate(QOSstate);
// validate
if (FAILED(hr)) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("IRTPStream::SetQOSstate returns 0x%08lx"), hr
));
return hr; // bail...
}
// retrieve Multicast Loopback state from stream
ReadEntry(pStream, &MCLoopBack, sizeof(MCLoopBack), &uBytesWritten,
"Multicast Loopback state");
// attempt to modify the QOS state
MCLoopBack = (MCLoopBack)? TRUE:FALSE;
hr = pCRtpSession->SetMulticastLoopBack(MCLoopBack);
// validate
if (FAILED(hr)) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("IRTPStream::SetMulticastLoopBack returns 0x%08lx"), hr
));
return hr; // bail...
}
return S_OK;
}
int
CRtpSourceFilter::SizeMax(
)
/*++
Routine Description:
Returns an interface and increments the reference count.
Arguments:
riid - reference identifier.
ppv - pointer to the interface.
Return Values:
Returns a pointer to the interface.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::SizeMax")
));
// obtain lock to this object
CAutoLock LockThis(pStateLock());
//
// CODEWORK...
//
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// //
// ISpecifyPropertyPages implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CRtpSourceFilter::GetPages(
CAUUID * pPages
)
/*++
Routine Description:
Returns property class id associated with filter.
Arguments:
pPages - pointer to received property page class id.
Return Values:
Returns an HRESULT value.
--*/
{
TraceDebug((
TRACE_TRACE,
TRACE_ALWAYS,
TEXT("CRtpSourceFilter::GetPages")
));
// number of pages
pPages->cElems = 1;
// allocate space to place property page guid
pPages->pElems = (GUID *)CoTaskMemAlloc(sizeof(GUID));
// validate pointer
if (pPages->pElems == NULL) {
TraceDebug((
TRACE_ERROR,
TRACE_ALWAYS,
TEXT("Could not allocate property page guid")
));
return E_OUTOFMEMORY;
}
// transfer property page guid to caller
*(pPages->pElems) = CLSID_RTPRenderFilterProperties;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// //
// INonDelegatingUnknown implemented methods //
// //
///////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CRtpSourceFilter::NonDelegatingQueryInterface(
REFIID riid,
void ** ppv
)
/*++
Routine Description:
Returns an interface and increments the reference count.
Arguments:
riid - reference identifier.
ppv - pointer to the interface.
Return Values:
Returns a pointer to the interface.
--*/
{
#ifdef DEBUG_CRITICAL_PATH
TraceDebug((
TRACE_TRACE,
TRACE_CRITICAL,
TEXT("CRtpSourceFilter::NonDelegatingQueryInterface")
));
#endif // DEBUG_CRITICAL_PATH
// validate pointer
CheckPointer(ppv,E_POINTER);
// obtain proper interface
if (riid == IID_IPersistStream) {
// return pointer to this object
return GetInterface((IPersistStream *)this, ppv);
} else if (riid == IID_ISpecifyPropertyPages) {
// return pointer to this object
return GetInterface((ISpecifyPropertyPages *)this, ppv);
} else if (riid == IID_IRTPStream ||
riid == IID_IRTCPStream ||
riid == IID_IRTPParticipant) {
// obtain pointer to default output pin object
CRtpOutputPin * pRtpOutputPin = (CRtpOutputPin *)GetPin(0);
// forward request to default pin object
return pRtpOutputPin->NonDelegatingQueryInterface(riid, ppv);
} else {
// forward this request to the base object
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
}