// // fpunit.cpp // #include "stdafx.h" #include "fpunit.h" #include "pbfilter.h" #include "vfwmsgs.h" // // The unit filter name // WCHAR g_bstrUnitFilterName[] = L"PlaybackUnitSource"; WCHAR g_bstrUnitBridgeFilterName[] = L"PlaybackBridgeFilter"; CPlaybackUnit::CPlaybackUnit() :m_pIGraphBuilder(NULL), m_hGraphEventHandle(NULL), m_pBridgeFilter(NULL), m_pSourceFilter(NULL) { LOG((MSP_TRACE, "CPlaybackUnit::CPlaybackUnit[%p] - enter. ", this)); LOG((MSP_TRACE, "CPlaybackUnit::CPlaybackUnit - exit")); } CPlaybackUnit::~CPlaybackUnit() { LOG((MSP_TRACE, "CPlaybackUnit::~CPlaybackUnit[%p] - enter. ", this)); LOG((MSP_TRACE, "CPlaybackUnit::~CPlaybackUnit - exit")); } // // --- Public members --- // /*++ Inititalize the playback unit try to create the graph builder, initialize critical section, rgisters for the graph events --*/ HRESULT CPlaybackUnit::Initialize( ) { LOG((MSP_TRACE, "CPlaybackUnit::Initialize[%p] - enter. ", this)); // // initialize should only be called once. it it is not, there is a bug in // our code // if (NULL != m_pIGraphBuilder) { LOG((MSP_ERROR, "CPlaybackUnit::Initialize - already initialized")); TM_ASSERT(FALSE); return E_UNEXPECTED; } // // attempt to initialize critical section // BOOL bCSInitSuccess = InitializeCriticalSectionAndSpinCount(&m_CriticalSection, 0); if (!bCSInitSuccess) { LOG((MSP_ERROR, "CPlaybackUnit::Initialize - failed to initialize critical section. LastError=%ld", GetLastError())); return E_OUTOFMEMORY; } // // Create filter graph // HRESULT hr = CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &m_pIGraphBuilder ); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::Initialize - failed to create filter graph. Returns 0x%08x", hr)); DeleteCriticalSection(&m_CriticalSection); return hr; } // // Register for filter graph events // IMediaEvent *pMediaEvent = NULL; hr = m_pIGraphBuilder->QueryInterface(IID_IMediaEvent, (void**)&pMediaEvent); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to qi graph for IMediaEvent, Returns 0x%08x", hr)); // Clean-up m_pIGraphBuilder->Release(); m_pIGraphBuilder = NULL; DeleteCriticalSection(&m_CriticalSection); return hr; } // // Get filter graph's event // HANDLE hEvent = NULL; hr = pMediaEvent->GetEventHandle((OAEVENT*)&hEvent); // // Clean-up // pMediaEvent->Release(); pMediaEvent = NULL; if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to get graph's event. Returns 0x%08x", hr)); // Clean-up m_pIGraphBuilder->Release(); m_pIGraphBuilder = NULL; DeleteCriticalSection(&m_CriticalSection); return hr; } // // Register for the graph event // BOOL fSuccess = RegisterWaitForSingleObject( &m_hGraphEventHandle, // pointer to the returned handle hEvent, // the event handle to wait for. CPlaybackUnit::HandleGraphEvent, // the callback function. this, // the context for the callback. INFINITE, // wait forever. WT_EXECUTEDEFAULT | WT_EXECUTEINWAITTHREAD // use the wait thread to call the callback. ); if ( ! fSuccess ) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to register wait event", hr)); // Clean-up m_pIGraphBuilder->Release(); m_pIGraphBuilder = NULL; DeleteCriticalSection(&m_CriticalSection); return hr; } LOG((MSP_TRACE, "CPlaybackUnit::Initialize - exit")); return S_OK; } // // SetupFromFile try to create a filter graph and // the bridge filter with input pins based on the file // HRESULT CPlaybackUnit::SetupFromFile( IN BSTR bstrFileName ) { LOG((MSP_TRACE, "CPlaybackUnit::SetupFromFile[%p] - enter", this)); // // Check arguments // if (IsBadStringPtr(bstrFileName, -1)) { LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - bad file name passed in")); TM_ASSERT(FALSE); return E_UNEXPECTED; } // // Make sure we have been initialized // if (NULL == m_pIGraphBuilder) { LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - not yet initialized.")); TM_ASSERT(FALSE); return E_UNEXPECTED; } // // lock before accessing data members // CCSLock Lock(&m_CriticalSection); // // Make sure the graph is stopped // HRESULT hr = IsGraphInState( State_Stopped ); if( FAILED(hr) ) { // // Stop the graph // hr = Stop(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "graph cannot be stop. Returns 0x%08x", hr)); return hr; } } // // Remove the existing source filter // if we have one // if( m_pSourceFilter != NULL) { hr = RemoveSourceFilter(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "RemoveSourceFilter failed. Returns 0x%08x", hr)); return hr; } } // // Add the source filter to the filter graph // hr = m_pIGraphBuilder->AddSourceFilter( bstrFileName, g_bstrUnitFilterName, &m_pSourceFilter ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "AddSourceFilter failed. Returns 0x%08x", hr)); return hr; } // // Get the source pin // IPin* pSourcePin = NULL; hr = GetSourcePin( &pSourcePin ); if( FAILED(hr) ) { // Clean-up RemoveSourceFilter(); LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "GetSourcePin failed. Returns 0x%08x", hr)); return hr; } // // We add bridge filters to the graph // hr = AddBridgeFilter(); if( FAILED(hr) ) { // Clean-up pSourcePin->Release(); RemoveSourceFilter(); LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "AddBridgeFilters failed. Returns 0x%08x", hr)); return hr; } // // Let graph to render // hr = m_pIGraphBuilder->Render( pSourcePin ); if( FAILED(hr) ) { // Clean-up pSourcePin->Release(); RemoveSourceFilter(); LOG((MSP_ERROR, "CPlaybackUnit::SetupFromFile - " "AddBridgeFilters failed. Returns 0x%08x", hr)); return hr; } // // Clean-up // pSourcePin->Release(); pSourcePin = NULL; LOG((MSP_TRACE, "CPlaybackUnit::SetupFromFile - finished")); return S_OK; } HRESULT CPlaybackUnit::GetState(OAFilterState *pGraphState) { LOG((MSP_TRACE, "CPlaybackUnit::GetState[%p] - enter", this)); // // make sure we have been initialized. // if (NULL == m_pIGraphBuilder) { LOG((MSP_ERROR, "CPlaybackUnit::GetState - not yet initialized.")); TM_ASSERT(FALSE); return E_UNEXPECTED; } // // get media control interface so we change state // IMediaControl *pIMediaControl = NULL; { // // will be accessing data members -- in a lock // CCSLock Lock(&m_CriticalSection); HRESULT hr = m_pIGraphBuilder->QueryInterface( IID_IMediaControl, (void**)&pIMediaControl ); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - failed to qi for IMediaControl. hr = %lx", hr)); return hr; } } // // try to get state outside the lock // OAFilterState GraphState = (OAFilterState) -1; HRESULT hr = pIMediaControl->GetState(10, &GraphState); pIMediaControl->Release(); pIMediaControl = NULL; // // did we succeed at all? // if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - failed to get state. hr = %lx", hr)); return hr; } // // is the state transition still in progress? // if (VFW_S_STATE_INTERMEDIATE == hr) { LOG((MSP_WARN, "CPlaybackUnit::ChangeState - state transition in progress. " "returNing VFW_S_STATE_INTERMEDIATE")); // // continue -- the state is what we are transitioning to // } // // log if we got VFW_S_CANT_CUE // if (VFW_S_CANT_CUE == hr) { LOG((MSP_WARN, "CPlaybackUnit::GetState - fg returned VFW_S_CANT_CUE")); // // continue -- we still should have received a valid state // } // // log the state // switch (GraphState) { case State_Stopped: LOG((MSP_TRACE, "CPlaybackUnit::GetState - State_Stopped")); *pGraphState = GraphState; break; case State_Running: LOG((MSP_TRACE, "CPlaybackUnit::GetState - State_Running")); *pGraphState = GraphState; break; case State_Paused: LOG((MSP_TRACE, "CPlaybackUnit::GetState- State_Paused")); *pGraphState = GraphState; break; default: LOG((MSP_TRACE, "CPlaybackUnit::GetState- unknown state %ld", GraphState)); hr = E_FAIL; break; } LOG((MSP_(hr), "CPlaybackUnit::GetState - finish. hr = %lx", hr)); return hr; } VOID CPlaybackUnit::HandleGraphEvent( IN VOID *pContext, IN BOOLEAN bReason) { LOG((MSP_TRACE, "CPlaybackUnit::HandleGraphEvent - enter FT:[%p].", pContext)); // // get recording unit pointer out of context // CPlaybackUnit *pPlaybackUnit = static_cast(pContext); if (IsBadReadPtr(pPlaybackUnit, sizeof(CPlaybackUnit)) ) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - bad context")); return; } // // the graph was not initialized. something went wrong. // if (NULL == pPlaybackUnit->m_pIGraphBuilder) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - not initialized. filter graph null")); return; } // // lock the object (just in case the object pointer is bad, do inside try/catch // try { EnterCriticalSection(&(pPlaybackUnit->m_CriticalSection)); } catch(...) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - exception accessing critical section")); return; } // // get the media event interface so we can retrieve the event // IMediaEvent *pMediaEvent = NULL; HRESULT hr = pPlaybackUnit->m_pIGraphBuilder->QueryInterface(IID_IMediaEvent, (void**)&pMediaEvent); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to qi graph for IMediaEvent")); LeaveCriticalSection(&(pPlaybackUnit->m_CriticalSection)); return; } // // while holding critical section, get the terminal on which to fire the event // //CFileRecordingTerminal *pRecordingterminal = pPlaybackUnit->m_pRecordingTerminal; //pRecordingterminal->AddRef(); // // no longer need to access data members, release critical section // LeaveCriticalSection(&(pPlaybackUnit->m_CriticalSection)); // // get the actual event // long lEventCode = 0; LONG_PTR lParam1 = 0; LONG_PTR lParam2 = 0; hr = pMediaEvent->GetEvent(&lEventCode, &lParam1, &lParam2, 0); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to get the event. hr = %lx", hr)); // Clean-up pMediaEvent->FreeEventParams(lEventCode, lParam1, lParam2); pMediaEvent->Release(); pMediaEvent = NULL; return; } LOG((MSP_EVENT, "CPlaybackUnit::HandleGraphEvent - received event code:[0x%lx] param1:[%p] param2:[%p]", lEventCode, lParam1, lParam2)); // // ask file terminal to handle the event // // Clean-up pMediaEvent->FreeEventParams(lEventCode, lParam1, lParam2); pMediaEvent->Release(); pMediaEvent = NULL; if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::HandleGraphEvent - failed to fire event on the terminal. hr = %lx", hr)); return; } } HRESULT CPlaybackUnit::IsGraphInState( IN OAFilterState State ) { LOG((MSP_TRACE, "CPlaybackUnit::IsGraphInState[%p] - enter", this)); // // Get the graph state // OAFilterState DSState; HRESULT hr = GetState(&DSState); // // is the state transition still in progress? // if (VFW_S_STATE_INTERMEDIATE == hr) { LOG((MSP_ERROR, "CPlaybackUnit::IsGraphInState - exit" " graph is not yet initialized. Returns TAPI_E_WRONG_STATE")); return TAPI_E_WRONG_STATE; } // // is the return anything other than S_OK // if (hr != S_OK) { LOG((MSP_ERROR, "CPlaybackUnit::IsGraphInState - exit " "failed to get state of the filter graph. Returns 0x%08x", hr)); return hr; } if (State != DSState) { LOG((MSP_ERROR, "CPlaybackUnit::IsGraphInState - exit " "other state then we asked for. Returns TAPI_E_WRONG_STATE")); return TAPI_E_WRONG_STATE; } LOG((MSP_(hr), "CPlaybackUnit::IsGraphInState - exit. Returns 0x%08x", hr)); return hr; } /*++ Renoves the source filter from the filter graph and set the source filter on NULL. --*/ HRESULT CPlaybackUnit::RemoveSourceFilter() { LOG((MSP_TRACE, "CPlaybackUnit::RemoveSourceFilter[%p] - enter", this)); // // Do we have a source filter? // if( m_pSourceFilter == NULL ) { LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - " "we have a NULL source filter already. Returns S_OK")); return S_OK; } // // Get the IFilterGraph interface // IFilterGraph* pFilterGraph = NULL; HRESULT hr = m_pIGraphBuilder->QueryInterface( IID_IFilterGraph, (void**)&pFilterGraph ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::RemoveSourceFilter - " "QI for IFilterGraph failed. Returns 0x%08x", hr)); return hr; } // // Remove the source filter from the graph // pFilterGraph->RemoveFilter( m_pSourceFilter ); // // Clean-up the source filter anyway // m_pSourceFilter->Release(); m_pSourceFilter = NULL; // Clean-up pFilterGraph->Release(); pFilterGraph = NULL; LOG((MSP_(hr), "CPlaybackUnit::AddSourceFilter - exit. Returns 0x%08x", hr)); return hr; } /*++ Removes the bridge filter from the filter graph and set the bridge filter on NULL. --*/ HRESULT CPlaybackUnit::RemoveBridgeFilter( ) { LOG((MSP_TRACE, "CPlaybackUnit::RemoveBridgeFilter[%p] - enter", this)); // // Do we have a bridge filter? // if( m_pBridgeFilter == NULL ) { LOG((MSP_TRACE, "CPlaybackUnit::RemoveBridgeFilter - " "we have a NULL bridge filter already. Returns S_OK")); return S_OK; } // // Get the IFilterGraph interface // IFilterGraph* pFilterGraph = NULL; HRESULT hr = m_pIGraphBuilder->QueryInterface( IID_IFilterGraph, (void**)&pFilterGraph ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::RemoveBridgeFilter - " "QI for IFilterGraph failed. Returns 0x%08x", hr)); return hr; } // // Remove the bridge filter from the graph // pFilterGraph->RemoveFilter( m_pBridgeFilter ); // // Clean-up the bridge filter anyway // m_pBridgeFilter = NULL; // Clean-up pFilterGraph->Release(); pFilterGraph = NULL; LOG((MSP_(hr), "CPlaybackUnit::RemoveBridgeFilter - exit. Returns 0x%08x", hr)); return hr; } HRESULT CPlaybackUnit::GetSourcePin( OUT IPin** ppPin ) { LOG((MSP_TRACE, "CPlaybackUnit::GetSourcePin[%p] - enter", this)); TM_ASSERT( m_pSourceFilter ); // // Reset the value // *ppPin = NULL; // // Get the in enumeration // IEnumPins* pEnumPins = NULL; HRESULT hr = m_pSourceFilter->EnumPins( &pEnumPins ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::GetSourcePin - exit " "EnumPins failed. Returns 0x%08x", hr)); return hr; } // // Get the first pin // IPin* pPin = NULL; ULONG uFetched = 0; hr = pEnumPins->Next(1, &pPin, &uFetched ); // // Release the enumeration // pEnumPins->Release(); pEnumPins = NULL; if( hr != S_OK ) { LOG((MSP_ERROR, "CPlaybackUnit::GetSourcePin - exit " "we don't have a pin. Returns E_FAIL")); return E_FAIL; } // // Return the pin // *ppPin = pPin; LOG((MSP_TRACE, "CPlaybackUnit::GetSourcePin - exit S_OK")); return S_OK; } HRESULT CPlaybackUnit::AddBridgeFilter( ) { LOG((MSP_TRACE, "CPlaybackUnit::AddBridgeFilter[%p] - enter", this)); if( m_pBridgeFilter ) { LOG((MSP_TRACE, "CPlaybackUnit::AddBridgeFilter - " "we already have a bridge filter. Return S_OK")); return S_OK; } // // Create the new bridge filter // m_pBridgeFilter = new CPBFilter(); if( m_pBridgeFilter == NULL) { LOG((MSP_ERROR, "CPlaybackUnit::AddBridgeFilter - exit " "new allocation for CPBFilter failed. Returns E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // Initialize the bridge filter // HRESULT hr = m_pBridgeFilter->Initialize( this ); if( FAILED(hr) ) { // Clean-up delete m_pBridgeFilter; m_pBridgeFilter = NULL; LOG((MSP_ERROR, "CPlaybackUnit::AddBridgeFilter - exit " "initialize failed. Returns 0x%08x", hr)); return hr; } // // Add this bridge filter to the graph // hr = m_pIGraphBuilder->AddFilter( m_pBridgeFilter, g_bstrUnitBridgeFilterName ); if( FAILED(hr) ) { // Clean-up delete m_pBridgeFilter; m_pBridgeFilter = NULL; LOG((MSP_ERROR, "CPlaybackUnit::AddBridgeFilter - exit " "Add filter failed. Returns 0x%08x", hr)); return hr; } LOG((MSP_(hr), "CPlaybackUnit::AddBridgeFilter - exit. Returns 0x%08x", hr)); return hr; } // // retrieve the media supported by the filter // HRESULT CPlaybackUnit::get_MediaTypes( OUT long* pMediaTypes ) { LOG((MSP_TRACE, "CPlaybackUnit::get_MediaTypes[%p] - enter", this)); TM_ASSERT( pMediaTypes != NULL ); TM_ASSERT( m_pBridgeFilter != NULL ); HRESULT hr = E_FAIL; // // lock before accessing data members // CCSLock Lock(&m_CriticalSection); // // Get the media types from the filter // hr = m_pBridgeFilter->get_MediaTypes( pMediaTypes ); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::get_MediaTypes - exit " "get_MediaTypes failed. Returns 0x%08x", hr)); return hr; } LOG((MSP_(hr), "CPlaybackUnit::get_MediaTypes - exit. Returns S_OK")); return S_OK; } HRESULT CPlaybackUnit::GetMediaPin( IN long nMediaType, IN int nIndex, OUT CPBPin** ppPin ) { LOG((MSP_TRACE, "CPlaybackUnit::GetMediaPin[%p] - enter", this)); TM_ASSERT( ppPin != NULL ); TM_ASSERT( m_pBridgeFilter != NULL ); HRESULT hr = E_FAIL; *ppPin = NULL; // // lock before accessing data members // CCSLock Lock(&m_CriticalSection); // // Get the media types from the filter // int nPins = m_pBridgeFilter->GetPinCount(); int nMediaPin = 0; for(int nPin=0; nPin < nPins; nPin++) { CPBPin* pPin = static_cast(m_pBridgeFilter->GetPin(nPin)); if( pPin ) { long mt = 0; pPin->get_MediaType( &mt ); if( (mt == nMediaType) && (nIndex == nMediaPin) ) { *ppPin = pPin; hr = S_OK; break; } if( mt == nMediaType ) { nMediaPin++; } } } LOG((MSP_(hr), "CPlaybackUnit::GetMediaPin - exit. Returns 0x%08x", hr)); return hr; } /////////////////////////////////////////////////////////////////////////////// HRESULT CPlaybackUnit::ChangeState(OAFilterState DesiredState) { LOG((MSP_TRACE, "CPlaybackUnit::ChangeState[%p] - enter", this)); // // make sure we have been initialized // if (NULL == m_pIGraphBuilder) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - not yet initialized.")); TM_ASSERT(FALSE); return E_UNEXPECTED; } // // check the current state first // OAFilterState GraphState; HRESULT hr = GetState(&GraphState); // // is the state transition still in progress? // if (VFW_S_STATE_INTERMEDIATE == hr) { LOG((MSP_WARN, "CPlaybackUnit::ChangeState - state transition in progress. returing TAPI_E_WRONG_STATE")); return TAPI_E_WRONG_STATE; } // // is the return anything other than S_OK // if (hr != S_OK) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - failed to get state of the filter graph. hr = %lx", hr)); return hr; } TM_ASSERT(hr == S_OK); // // nothing to do if we are already in that state // if (DesiredState == GraphState) { LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - graph is already in state %ld. nothing to do.", DesiredState)); return S_OK; } // // get media control interface so we change state // IMediaControl *pIMediaControl = NULL; { // // will be accessing data members -- in a lock // CCSLock Lock(&m_CriticalSection); hr = m_pIGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&pIMediaControl); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - failed to qi for IMediaControl. hr = %lx", hr)); return hr; } } // // try to make state transition // switch (DesiredState) { case State_Stopped: LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - stopping")); hr = pIMediaControl->Stop(); break; case State_Running: LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - starting")); hr = pIMediaControl->Run(); break; case State_Paused: LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - pausing")); hr = pIMediaControl->Pause(); break; default: LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - unknown state %ld", DesiredState)); hr = E_INVALIDARG; break; } pIMediaControl->Release(); pIMediaControl = NULL; if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::ChangeState - state change failed. hr = %lx", hr)); return hr; } LOG((MSP_TRACE, "CPlaybackUnit::ChangeState - finish")); return S_OK; } /////////////////////////////////////////////////////////////////////////////// HRESULT CPlaybackUnit::Start() { LOG((MSP_TRACE, "CPlaybackUnit::Start[%p] - enter", this)); HRESULT hr = ChangeState(State_Running); LOG((MSP_(hr), "CPlaybackUnit::Start - finish. hr = %lx", hr)); return hr; } HRESULT CPlaybackUnit::Pause() { LOG((MSP_TRACE, "CPlaybackUnit::Pause[%p] - enter", this)); HRESULT hr = ChangeState(State_Paused); LOG((MSP_(hr), "CPlaybackUnit::Pause - finish. hr = %lx", hr)); return hr; } HRESULT CPlaybackUnit::Stop() { LOG((MSP_TRACE, "CPlaybackUnit::Stop[%p] - enter", this)); HRESULT hr = ChangeState(State_Stopped); LOG((MSP_(hr), "CPlaybackUnit::Stop - finish. hr = %lx", hr)); return hr; } HRESULT CPlaybackUnit::Shutdown() { // // if we don't have filter graph, we have not passed initialization // if (NULL == m_pIGraphBuilder) { LOG((MSP_TRACE, "CPlaybackUnit::Shutdown - not yet initialized. nothing to shut down")); return S_OK; } // // first of all, make sure the graph is stopped // HRESULT hr = Stop(); if (FAILED(hr)) { LOG((MSP_ERROR, "CPlaybackUnit::Shutdown - exit " "failed to stop filter graph, hr = 0x%08x", hr)); return hr; } // // unregister wait event // BOOL bUnregisterResult = ::UnregisterWaitEx(m_hGraphEventHandle, (HANDLE)-1); m_hGraphEventHandle = NULL; if (!bUnregisterResult) { LOG((MSP_ERROR, "CPlaybackUnit::Shutdown - failed to unregisted even. continuing anyway")); } // // Remove the bridge filter // hr = RemoveBridgeFilter(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::Shutdown - exit " "RemoveBridgeFilter failed, hr = 0x%08x", hr)); return hr; } // // Remove the source filter // hr = RemoveSourceFilter(); if( FAILED(hr) ) { LOG((MSP_ERROR, "CPlaybackUnit::Shutdown - exit " "RemoveSourceFilter failed, hr = 0x%08x", hr)); return hr; } // // release filter graph // if( m_pIGraphBuilder != NULL ) { m_pIGraphBuilder->Release(); m_pIGraphBuilder = NULL; } // // no need to keep critical section around any longer -- no one should be // using this object anymore // DeleteCriticalSection(&m_CriticalSection); LOG((MSP_TRACE, "CPlaybackUnit::Shutdown - finished")); return S_OK; } // eof