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.
939 lines
22 KiB
939 lines
22 KiB
// MultiTrackTerminal.cpp: implementation of the CMultiTrackTerminal class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "MultiTrackTerminal.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CMultiTrackTerminal::CMultiTrackTerminal()
|
|
:m_nNumberOfTracks(0)
|
|
{
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::CMultiTrackTerminal[%p] - enter", this));
|
|
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::CMultiTrackTerminal - finish"));
|
|
}
|
|
|
|
CMultiTrackTerminal::~CMultiTrackTerminal()
|
|
{
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::~CMultiTrackTerminal - enter"));
|
|
|
|
ReleaseAllTracks();
|
|
|
|
|
|
//
|
|
// we should have no tracks at this point, and counter should be in sync
|
|
//
|
|
|
|
TM_ASSERT(m_nNumberOfTracks == 0);
|
|
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::~CMultiTrackTerminal - finish"));
|
|
|
|
}
|
|
|
|
|
|
HRESULT CMultiTrackTerminal::get_TrackTerminals(OUT VARIANT *pVariant)
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_TrackTerminals[%p] - enter. pVariant [%p]", this, pVariant));
|
|
|
|
|
|
//
|
|
// Check parameters
|
|
//
|
|
|
|
if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"bad pointer argument - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// the caller needs to provide us with an empty variant
|
|
//
|
|
|
|
if (pVariant->vt != VT_EMPTY)
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"variant argument is not empty"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// create the collection object - see mspbase\mspcoll.h
|
|
//
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
typedef CTapiIfCollection<ITTerminal*> TerminalCollection;
|
|
|
|
CComObject<TerminalCollection> *pCollection = NULL;
|
|
|
|
|
|
hr = CComObject<TerminalCollection>::CreateInstance(&pCollection);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"can't create collection - exit %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// get the Collection's IDispatch interface
|
|
//
|
|
|
|
IDispatch *pDispatch = NULL;
|
|
|
|
hr = pCollection->QueryInterface(IID_IDispatch,
|
|
(void **) &pDispatch );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"QI for IDispatch on collection failed - exit %lx", hr));
|
|
|
|
delete pCollection;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
|
|
//
|
|
// Init the collection using an iterator -- pointers to the beginning and
|
|
// the ending element plus one.
|
|
//
|
|
|
|
hr = pCollection->Initialize( m_TrackTerminals.GetSize(),
|
|
m_TrackTerminals.GetData(),
|
|
m_TrackTerminals.GetData() + m_TrackTerminals.GetSize() );
|
|
}
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"Initialize on collection failed - exit %lx", hr));
|
|
|
|
pDispatch->Release();
|
|
delete pCollection;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// put the IDispatch interface pointer into the variant
|
|
//
|
|
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
|
|
"placing IDispatch value %p in variant", pDispatch));
|
|
|
|
VariantInit(pVariant);
|
|
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = pDispatch;
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_TrackTerminals - exit S_OK"));
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CMultiTrackTerminal::EnumerateTrackTerminals(
|
|
IEnumTerminal **ppEnumTerminal
|
|
)
|
|
{
|
|
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::EnumerateTrackTerminals entered. ppEnumTerminal[%p]", ppEnumTerminal));
|
|
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
|
|
if (IsBadWritePtr(ppEnumTerminal, sizeof(IEnumTerminal*)))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals ppEnumTerminal is a bad pointer"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// don't return garbage
|
|
//
|
|
|
|
*ppEnumTerminal = NULL;
|
|
|
|
|
|
|
|
typedef _CopyInterface<ITTerminal> CCopy;
|
|
typedef CSafeComEnum<IEnumTerminal, &IID_IEnumTerminal,
|
|
ITTerminal *, CCopy> CEnumerator;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// create enumeration object
|
|
//
|
|
|
|
CMSPComObject<CEnumerator> *pEnum = NULL;
|
|
|
|
hr = CMSPComObject<CEnumerator>::CreateInstance(&pEnum);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals Could not create enumerator object, %x", hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// get pEnum's IID_IEnumTerminal interface
|
|
//
|
|
|
|
hr = pEnum->QueryInterface(IID_IEnumTerminal, (void**)ppEnumTerminal);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals query enum interface failed, %x", hr));
|
|
|
|
*ppEnumTerminal = NULL;
|
|
|
|
|
|
//
|
|
// don't yet have outstanding reference count on pEnum, so delete it.
|
|
//
|
|
// note: this can lead to a problem if FinalRelease of pEnum is
|
|
// supposed to deallocate resources that have been allocated in its
|
|
// constructor
|
|
//
|
|
|
|
delete pEnum;
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// access data member track terminal list from a lock
|
|
//
|
|
|
|
{
|
|
CLock lock(m_lock);
|
|
|
|
|
|
// The CSafeComEnum can handle zero-sized array.
|
|
|
|
hr = pEnum->Init(
|
|
m_TrackTerminals.GetData(), // the begin itor
|
|
m_TrackTerminals.GetData() + m_TrackTerminals.GetSize(), // the end itor,
|
|
NULL, // IUnknown
|
|
AtlFlagCopy // copy the data.
|
|
);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals init enumerator object failed, %x", hr));
|
|
(*ppEnumTerminal)->Release();
|
|
*ppEnumTerminal= NULL;
|
|
return hr;
|
|
}
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::EnumerateTrackTerminals - exit S_OK"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CMultiTrackTerminal::get_MediaTypesInUse(
|
|
OUT long *plMediaTypesInUse
|
|
)
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_MediaTypesInUse - enter. "
|
|
"plMediaTypesInUse [%p]", plMediaTypesInUse));
|
|
|
|
if (IsBadWritePtr(plMediaTypesInUse, sizeof(long)))
|
|
{
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_MediaTypesInUse plMediaTypesInUse "
|
|
"does not point to a valid long"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// enumerate all the terminal and OR their media types and media types in use
|
|
//
|
|
|
|
long lMediaTypesInUse = 0;
|
|
|
|
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
|
|
|
|
for ( int i = 0; i < m_TrackTerminals.GetSize(); i++ )
|
|
{
|
|
|
|
long lMT = 0;
|
|
|
|
|
|
//
|
|
// is the track terminal a multitrack terminal itself?
|
|
//
|
|
|
|
ITMultiTrackTerminal *pMTT = NULL;
|
|
|
|
HRESULT hr = m_TrackTerminals[i]->QueryInterface(IID_ITMultiTrackTerminal,
|
|
(void**)&pMTT);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
//
|
|
// this is a multitrack terminal. get its mediatypes in use
|
|
//
|
|
|
|
hr = pMTT->get_MediaTypesInUse(&lMT);
|
|
|
|
|
|
pMTT->Release();
|
|
pMTT = NULL;
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
//
|
|
// failed to get track's media types in use.
|
|
// continue to the next track
|
|
//
|
|
|
|
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_MediaTypesInUse "
|
|
"get_MediaTypesInUse on terminal (%d) failed.", i));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the track is not a multitrack terminal, so use its ITTerminal
|
|
// interface to get its media type
|
|
//
|
|
|
|
hr = m_TrackTerminals[i]->get_MediaType(&lMT);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
//
|
|
// failed to get track's media types in use.
|
|
// continue to the next track
|
|
//
|
|
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_MediaTypesInUse "
|
|
"get_MediaType on terminal (%d) failed.", i));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::get_MediaTypesInUse "
|
|
"track terminal (%d) has media type of %lx.", i, lMT));
|
|
|
|
lMediaTypesInUse |= lMT;
|
|
}
|
|
|
|
|
|
*plMediaTypesInUse = lMediaTypesInUse;
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_EnumerateTrackTerminals - "
|
|
"exit S_OK. MediaTypeInUse %lx", lMediaTypesInUse));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
HRESULT CMultiTrackTerminal::get_DirectionsInUse(
|
|
OUT TERMINAL_DIRECTION *ptdDirectionsInUse
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_DirectionsInUse - enter. plDirectionsInUsed[%p]", ptdDirectionsInUse));
|
|
|
|
|
|
if (IsBadWritePtr(ptdDirectionsInUse, sizeof(TERMINAL_DIRECTION)))
|
|
{
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_DirectionsInUse plDirectionsInUsed"
|
|
"does not point to a valid long"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// don't return gardbage
|
|
//
|
|
|
|
*ptdDirectionsInUse = TD_NONE;
|
|
|
|
//
|
|
// enumerate all the terminal and OR their media types and media types in use
|
|
//
|
|
|
|
TERMINAL_DIRECTION tdDirInUse = TD_NONE;
|
|
|
|
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
|
|
for ( int i = 0; i < m_TrackTerminals.GetSize(); i++ )
|
|
{
|
|
|
|
TERMINAL_DIRECTION td = TD_NONE;
|
|
|
|
|
|
//
|
|
// is the track terminal a multitrack terminal itself?
|
|
//
|
|
|
|
ITMultiTrackTerminal *pMTT = NULL;
|
|
|
|
HRESULT hr = m_TrackTerminals[i]->QueryInterface(IID_ITMultiTrackTerminal,
|
|
(void**)&pMTT);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
//
|
|
// this is a multitrack terminal. get its mediatypes in use
|
|
//
|
|
|
|
hr = pMTT->get_DirectionsInUse(&td);
|
|
|
|
|
|
pMTT->Release();
|
|
pMTT = NULL;
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
//
|
|
// failed to get track's media types in use.
|
|
// continue to the next track
|
|
//
|
|
|
|
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_DirectionsInUse "
|
|
"get_MediaTypesInUse on terminal (%d) failed.", i));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// the track is not a multitrack terminal, so use its ITTerminal
|
|
// interface to get its direction
|
|
//
|
|
|
|
hr = m_TrackTerminals[i]->get_Direction(&td);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
|
|
//
|
|
// failed to get track's media types in use.
|
|
// continue to the next track
|
|
//
|
|
|
|
LOG((MSP_ERROR,
|
|
"CMultiTrackTerminal::get_DirectionsInUse "
|
|
"get_MediaType on terminal (%d) failed.", i));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
LOG((MSP_TRACE,
|
|
"CMultiTrackTerminal::get_DirectionsInUse "
|
|
"track terminal (%d) has media type of %lx.", i, td));
|
|
|
|
//
|
|
// based on directions we have collected so far, and on the direction that we just got, calculate total direction
|
|
//
|
|
|
|
switch (tdDirInUse)
|
|
{
|
|
|
|
case TD_NONE:
|
|
|
|
tdDirInUse = td;
|
|
|
|
break;
|
|
|
|
|
|
case TD_RENDER:
|
|
|
|
if ( (td != TD_RENDER) && (td != TD_NONE) )
|
|
{
|
|
tdDirInUse = TD_MULTITRACK_MIXED;
|
|
}
|
|
|
|
break;
|
|
|
|
case TD_CAPTURE:
|
|
|
|
if ( (td != TD_CAPTURE) && (td != TD_NONE) )
|
|
{
|
|
tdDirInUse = TD_MULTITRACK_MIXED;
|
|
}
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
|
|
if ( TD_MULTITRACK_MIXED == tdDirInUse )
|
|
{
|
|
|
|
//
|
|
// if the current direction is mixed, then break -- there is no point in looking further
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
} // for (track terminals)
|
|
|
|
|
|
*ptdDirectionsInUse = tdDirInUse;
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::get_DirectionsInUse - exit S_OK. "
|
|
"plDirectionsInUsed = %lx", *ptdDirectionsInUse));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::AddTrackTerminal
|
|
//
|
|
// adds the terminal that is passed in as the argument to the
|
|
// list of track terminals managed by this multitrack terminal
|
|
//
|
|
// Note: this function increments refcount of the terminal that is being added to the list
|
|
//
|
|
|
|
HRESULT CMultiTrackTerminal::AddTrackTerminal(ITTerminal *pTrackTerminalToAdd)
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal[%p] - enter. "
|
|
"pTrackTerminalToAdd = %p", this, pTrackTerminalToAdd));
|
|
|
|
|
|
if (IsBadReadPtr(pTrackTerminalToAdd, sizeof(ITTerminal*)))
|
|
{
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal - invalid ptr"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
{
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
|
|
//
|
|
// we use a special lock to increment track counter, to avoid deadlocks
|
|
// on reference counting
|
|
//
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// add track terminal to the array
|
|
//
|
|
|
|
if (!m_TrackTerminals.Add(pTrackTerminalToAdd))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::AddTrackTerminal - "
|
|
"failed to add track to the array of terminals"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
|
|
m_nNumberOfTracks++;
|
|
|
|
|
|
//
|
|
// the counter should never ever go out of sync
|
|
//
|
|
|
|
TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//
|
|
// we are keeping a reference to the terminal, so increment refcount
|
|
//
|
|
|
|
pTrackTerminalToAdd->AddRef();
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal - finished"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::RemoveTrackTerminal
|
|
//
|
|
// removes the terminal from the list of track terminals
|
|
// managed by this multitrack terminal
|
|
//
|
|
// if success, decrementing refcount on the track terminal
|
|
//
|
|
|
|
HRESULT CMultiTrackTerminal::RemoveTrackTerminal(ITTerminal *pTrackTerminalToRemove)
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::RemoveTrackTerminal[%p] - enter"
|
|
"pTrackTerminalToRemove = %p", this, pTrackTerminalToRemove));
|
|
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
|
|
//
|
|
// decrement track counter in a special lock to prevent deadlocks
|
|
// with reference counting
|
|
//
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// remove track from the array
|
|
//
|
|
|
|
if (!m_TrackTerminals.Remove(pTrackTerminalToRemove))
|
|
{
|
|
LOG((MSP_ERROR, "CMultiTrackTerminal::RemoveTrackTerminal - "
|
|
"failed to remove from the array of terminals"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
m_nNumberOfTracks--;
|
|
|
|
|
|
//
|
|
// the counter should never ever go out of sync
|
|
//
|
|
|
|
TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
|
|
|
|
Unlock();
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// we are releasing a reference to the terminal, so decrement refcount
|
|
//
|
|
|
|
pTrackTerminalToRemove->Release();
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::RemoveTrackTerminal- finished"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::ReleaseAllTracks
|
|
//
|
|
// removes all tracks from the list of managed track terminals
|
|
// and Release's them
|
|
//
|
|
//
|
|
|
|
HRESULT CMultiTrackTerminal::ReleaseAllTracks()
|
|
{
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks[%p] - enter", this));
|
|
|
|
|
|
{
|
|
//
|
|
// access data member array in a lock
|
|
//
|
|
|
|
CLock lock(m_lock);
|
|
|
|
int nNumberOfTerminalsInArray = m_TrackTerminals.GetSize();
|
|
|
|
for (int i = 0; i < nNumberOfTerminalsInArray; i++)
|
|
{
|
|
|
|
//
|
|
// release and remove the first terminal in the array
|
|
//
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks - releasing track [%p]", m_TrackTerminals[0]));
|
|
|
|
m_TrackTerminals[0]->Release();
|
|
|
|
|
|
//
|
|
// remove element from the array and decrement track counter in a
|
|
// special lock to prevent deadlocks with reference counting
|
|
//
|
|
|
|
Lock();
|
|
|
|
|
|
m_TrackTerminals.RemoveAt(0);
|
|
|
|
|
|
m_nNumberOfTracks--;
|
|
|
|
|
|
//
|
|
// the counter should never ever go out of sync
|
|
//
|
|
|
|
TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//
|
|
// we should have cleared the array
|
|
//
|
|
|
|
TM_ASSERT(0 == m_TrackTerminals.GetSize());
|
|
}
|
|
|
|
|
|
LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks - finished"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::InternalAddRef
|
|
//
|
|
// keep track of refcount.
|
|
//
|
|
// we need to adjust refcount with the information on the number of tracks
|
|
// that we are managing.
|
|
//
|
|
|
|
ULONG CMultiTrackTerminal::InternalAddRef()
|
|
{
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::InternalAddRef[%p] - enter.", this));
|
|
|
|
|
|
LONG lReturnValue = InterlockedIncrement(&m_dwRef);
|
|
|
|
lReturnValue -= CountTracks();
|
|
|
|
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::InternalAddRef - finish. returning %ld", lReturnValue));
|
|
|
|
return lReturnValue;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::InternalRelease
|
|
//
|
|
// keep track of refcount.
|
|
// return 0 when there are no outstanding references to me or my children
|
|
//
|
|
|
|
ULONG CMultiTrackTerminal::InternalRelease()
|
|
{
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::InternalRelease[%p] - enter", this));
|
|
|
|
|
|
LONG lReturnValue = InterlockedDecrement(&m_dwRef);
|
|
|
|
lReturnValue -= CountTracks();
|
|
|
|
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::InternalRelease - finish. returning %ld", lReturnValue));
|
|
|
|
return lReturnValue;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::ChildAddRef
|
|
//
|
|
// this method is called by a track terminal when it is AddRef'd,
|
|
// so the File Rec terminal can keep track of its children's refcounts
|
|
//
|
|
|
|
void CMultiTrackTerminal::ChildAddRef()
|
|
{
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::ChildAddRef[%p] - enter.", this));
|
|
|
|
AddRef();
|
|
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::ChildAddRef - finish."));
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::ChildRelease
|
|
//
|
|
// this method is called by a track terminal when it is released,
|
|
// so the File Rec terminal can keep track of its children's refcounts
|
|
//
|
|
|
|
void CMultiTrackTerminal::ChildRelease()
|
|
{
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::ChildRelease[%p] - enter.", this));
|
|
|
|
Release();
|
|
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::ChildRelease - finish."));
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMultiTrackTerminal::CountTracks
|
|
//
|
|
// this method returns the number of tracks managed by this parent
|
|
//
|
|
|
|
int CMultiTrackTerminal::CountTracks()
|
|
{
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::CountTracks[%p] - enter", this));
|
|
|
|
|
|
//
|
|
// this lock is only used to protect accesses to this var. this is
|
|
// needed to prevent deadlocks when
|
|
//
|
|
// one thread locks the parent
|
|
// terminal and enumerates the tracks (thus getting their locks)
|
|
//
|
|
// and
|
|
//
|
|
// another thread addrefs or releases a track. this locks the
|
|
// track and attempts to notify the parent of the child's refcount
|
|
// change. if this thread tries to lock the parent, we would have a
|
|
// deadlock
|
|
//
|
|
// so instead of locking the parent on addref and release, we only use
|
|
// this "addref/release" lock
|
|
//
|
|
|
|
|
|
Lock();
|
|
|
|
int nNumberOfTracks = m_nNumberOfTracks;
|
|
|
|
Unlock();
|
|
|
|
|
|
// LOG((MSP_TRACE, "CMultiTrackTerminal::CountTracks - finished. NumberOfTracks = %d", nNumberOfTracks));
|
|
|
|
return nNumberOfTracks;
|
|
}
|