📄 hxsm2.cpp
字号:
{
UINT32 ulRet = (m_bFixedBwValid) ? m_ulFixedBandwidth : 0;
if (!ulRet && m_pThresholds)
{
ulRet = (UINT32)m_pThresholds[m_ulCurThresh];
}
return ulRet;
}
inline
UINT32 ASMStreamInfo2::StreamID() const
{
return m_ulStreamID;
}
inline
void ASMStreamInfo2::SetStreamOffer(UINT32 ulOffer)
{
m_ulStreamOffer = ulOffer;
}
void ASMStreamInfo2::SelectBw(BOOL bPerfectPlay,
UINT32 ulAltOffer)
{
if (m_pThresholds)
{
if (bPerfectPlay)
{
/*
* If we are in perfect play mode, just select the highest bandwidth rule
* and don't negotiate any further.
*/
m_ulCurThresh = m_ulMaxEffectiveThreshold;
m_ulOffer = CurrentBw();
}
else
{
UINT32 ulOffer = ulAltOffer;
if (m_ulStreamOffer)
{
ulOffer = m_ulStreamOffer - 1;
}
if (m_ulMaxEffectiveThreshold != 0)
{
for (UINT32 i = 1; i <= m_ulMaxEffectiveThreshold; i++)
{
if ((ulOffer <= m_pThresholds[i]) ||
(i == m_ulMaxEffectiveThreshold))
{
m_ulOffer = ulOffer;
m_ulCurThresh = i;
break;
}
}
}
}
ComputeResistence(bPerfectPlay);
}
}
inline
UINT32 ASMStreamInfo2::ResistanceToLower() const
{
return m_ulResistanceToLower;
}
void ASMStreamInfo2::SelectNextLowerBw()
{
if (m_ulCurThresh > 0)
{
m_ulCurThresh--;
ComputeResistence(FALSE);
}
}
inline
UINT32 ASMStreamInfo2::GetLastBw() const
{
return m_ulLastBw;
}
void ASMStreamInfo2::SubscribeToNewBw(UINT32 ulBw, CHXSimpleList* pSubChanges)
{
BOOL bTimeStampDelivery = FALSE;
if (m_pRuleGather && m_pNegotiator)
{
m_pRuleGather->RuleGather(pSubChanges);
//update the HXASMStream with our new bandwidth
m_pNegotiator->SetBandwidthUsage(ulBw, bTimeStampDelivery);
m_pRuleGather->RuleGather(0);
}
m_ulLastBw = ulBw;
}
void ASMStreamInfo2::SubscribeToChanges(CHXSimpleList* pSubChanges)
{
if (m_pRuleGather)
{
m_pRuleGather->RuleFlush(pSubChanges);
}
}
void ASMStreamInfo2::ComputeResistence(BOOL bPerfectPlay)
{
/* NOTE:
* m_ulCurThresh and m_ulOffer must
* be valid when this function is called
*/
if (IsFixedBw() ||
bPerfectPlay ||
(m_ulMaxEffectiveThreshold == 0) ||
(m_ulCurThresh == 1))
{
m_ulResistanceToLower = 0xffffffff;
}
else
{
m_ulResistanceToLower =
(m_ulOffer - (UINT32)m_pThresholds[m_ulCurThresh - 1]) * m_ulOffer;
}
}
HXSM2::HXSM2() :
m_lRefCount(0),
m_ulNumSources(0),
m_pASMSourceInfo(0),
m_ulNumStreams(0),
m_ulOfferToRecalc(0),
m_ulSelectionBitRate(0),
m_ulMaxAccelBitRate(0),
m_ulSustainableBitRate(0),
m_pSubscriptionVariables(0),
m_bCheckOnDemandBw(FALSE)
{
m_pASMSourceInfo = new CHXSimpleList();
}
HXSM2::~HXSM2()
{
if (m_pASMSourceInfo)
{
while(!m_pASMSourceInfo->IsEmpty())
{
ASMSourceInfo2* pSrc =
(ASMSourceInfo2*)m_pASMSourceInfo->RemoveHead();
delete pSrc;
}
delete m_pASMSourceInfo;
}
}
STDMETHODIMP HXSM2::QueryInterface(THIS_ REFIID ID, void** ppInterfaceObj)
{
QInterfaceList qiList[] =
{
{ GET_IIDHANDLE(IID_IUnknown), this },
{ GET_IIDHANDLE(IID_IHXBandwidthManager), (IHXBandwidthManager*) this },
};
return QIFind(qiList, QILISTSIZE(qiList), ID, ppInterfaceObj);
}
STDMETHODIMP_(UINT32) HXSM2::AddRef(THIS)
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(UINT32) HXSM2::Release(THIS)
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
/*
* IHXBandwidthManager methods
*/
STDMETHODIMP HXSM2::RegisterSource(THIS_
HXSource* pSource,
IUnknown* pUnknown)
{
HX_RESULT res = HXR_OK;
IHXSourceBandwidthInfo* pSBI;
IHXPreferences* pPreferences = NULL;
IHXBuffer* pBuffer = 0;
ASMSourceInfo2* pASMSourceInfo = NULL;
if (HXR_OK == pSource->QueryInterface(IID_IHXSourceBandwidthInfo,
(void **)&pSBI))
{
pASMSourceInfo = new ASMSourceInfo2(pSource);
m_ulNumSources++;
m_ulNumStreams += pASMSourceInfo->StreamCount();
m_pASMSourceInfo->AddTail((void *)pASMSourceInfo);
HX_RELEASE(pSBI);
}
else
{
return HXR_OK;
}
/*
* This variable tells us the highest amount of bandwidth that we
* believe is useable. If we stream thin, then the highest value
* that the pipe can support would be the aggregate bandwidth of
* the sources. Barring any thinning, this would be the bandwidth
* from prefs (unless we can determine it through fast buffering or
* another transport feature). This value is used when starting sources
* as a initial guess for bandwidth (to set subscriptions).
*/
if (m_ulSelectionBitRate == 0)
{
pUnknown->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);
UINT32 ulTemp = 0;
UINT32 ulConnectionBw = 10485760; /* wild guess */
/* Get initial bandwidth guess from Prefs */
if ((HXR_OK == ReadPrefINT32(pPreferences, "Bandwidth", ulTemp)) &&
(ulTemp > 0))
{
ulConnectionBw = ulTemp;
}
/*
* m_ulSustainableBitRate refers to the max bitrate that we believe is
* sustainable over the connection. The client should never ask
* the server to send bits faster than this rate because it could
* cause congestion collapse.
*
* m_ulSelectionBitRate refers to the highest bitrate stream that we'll
* ever try to play. Note that people can choose to pick values
* where m_ulSelectionBitRate > m_ulSustainableBitRate. This may
* cause rebuffers because the delivery will be capped at
* m_ulSustainableBitRate. Why would someone do that? They may accept
* rebuffers if it means they get a higher quality presentation.
*/
/* See if we have a sustainable bandwidth factor */
if (HXR_OK == ReadPrefINT32(pPreferences, "SustainableBwFactor",
ulTemp))
{
/* clamp value to 0 <= ulTemp <= 100 range */
if (ulTemp > 100)
{
ulTemp = 100;
}
/* Apply factor */
m_ulSustainableBitRate =
(((ulConnectionBw / 100) * ulTemp) +
(((ulConnectionBw % 100) * ulTemp) / 100));
}
else
{
m_ulSustainableBitRate = ulConnectionBw;
}
/* See if we have a selection bandwidth factor */
if (HXR_OK == ReadPrefINT32(pPreferences, "SelectionBwFactor",
ulTemp))
{
/* clamp value to 0 <= ulTemp <= 200 range */
if (ulTemp > 200)
{
ulTemp = 200;
}
/* Apply factor */
m_ulSelectionBitRate =
(((m_ulSustainableBitRate / 100) * ulTemp) +
(((m_ulSustainableBitRate % 100) * ulTemp) / 100));
}
else
{
m_ulSelectionBitRate = m_ulSustainableBitRate;
}
/* Get MaxBandwidth from Prefs */
if (HXR_OK != ReadPrefINT32(pPreferences, "MaxBandwidth",
m_ulMaxAccelBitRate))
{
/*
* Failed to get the MaxBandwidth preference.
* Use m_ulSelectionBitRate value instead.
*/
m_ulMaxAccelBitRate = m_ulSelectionBitRate;
}
/*
* Get preference that controls whether we report
* "not enough bandwidth" conditions for on-demand clips
*/
ReadPrefBOOL(pPreferences, "CheckOnDemandBw", m_bCheckOnDemandBw);
HX_RELEASE(pPreferences);
}
return res;
}
STDMETHODIMP HXSM2::RegisterSourcesDone(THIS)
{
CHXSimpleList::Iterator i;
ASMSourceInfo2* pASMSourceInfo;
for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
{
pASMSourceInfo = (ASMSourceInfo2*)(*i);
if (pASMSourceInfo)
{
pASMSourceInfo->LastSetDelivery() = 0;
}
}
m_ulOfferToRecalc = m_ulSelectionBitRate;
if (m_ulOfferToRecalc > m_ulMaxAccelBitRate)
{
m_ulOfferToRecalc = m_ulMaxAccelBitRate;
}
Recalc();
return HXR_OK;
}
STDMETHODIMP_(BOOL) HXSM2::NotEnoughBandwidth(THIS)
{
CHXSimpleList::Iterator i;
ASMSourceInfo2* pASMSourceInfo;
UINT32 ulTotal = 0;
BOOL bCheckTotal = m_bCheckOnDemandBw;
for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
{
pASMSourceInfo = (ASMSourceInfo2*)(*i);
ulTotal += pASMSourceInfo->SubscribeBw();
if (pASMSourceInfo->IsLive())
{
bCheckTotal = TRUE;
}
}
if (bCheckTotal && ulTotal > m_ulSelectionBitRate)
{
return TRUE;
}
else
{
return FALSE;
}
}
STDMETHODIMP HXSM2::UnRegisterSource(THIS_
HXSource* pSource)
{
LISTPOSITION lPos;
ASMSourceInfo2* pASMSourceInfo = 0;
BOOL bFound = FALSE;
lPos = m_pASMSourceInfo->GetHeadPosition();
while (lPos)
{
pASMSourceInfo = (ASMSourceInfo2*)m_pASMSourceInfo->GetAt(lPos);
if (pASMSourceInfo->IsMySource(pSource))
{
m_pASMSourceInfo->RemoveAt(lPos);
pASMSourceInfo->Done();
bFound = TRUE;
break;
}
m_pASMSourceInfo->GetNext(lPos);
}
if (bFound)
{
m_ulNumStreams -= pASMSourceInfo->StreamCount();
delete pASMSourceInfo;
m_ulNumSources--;
if (m_ulNumSources > 0)
{
Recalc();
}
}
return HXR_OK;
}
STDMETHODIMP HXSM2::ChangeAccelerationStatus(THIS_
HXSource* pSource,
BOOL bMayBeAccelerated,
BOOL bUseAccelerationFactor,
UINT32 ulAccelerationFactor)
{
return HXR_OK;
}
/* Called by HXPlayer at end of each presentation */
STDMETHODIMP HXSM2::PresentationDone(THIS)
{
return HXR_OK;
}
STDMETHODIMP HXSM2::ChangeBW(THIS_
UINT32 newBW, HXSource* pSource)
{
return HXR_OK;
}
void
HXSM2::Recalc()
{
CHXSimpleList::Iterator i;
ASMStreamInfoItr streamItr(m_pASMSourceInfo);
ASMSourceInfo2* pASMSourceInfo;
ASMStreamInfo2* pASMStreamInfo;
INT32 lAggregateBandwidthUsage = 0;
UINT32 ulSourceCount;
UINT32 ulStreamCount;
float fBiasMean = (float) 0.;
ulSourceCount = m_pASMSourceInfo->GetCount();
ulStreamCount = m_ulNumStreams;
for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
{
pASMSourceInfo = (ASMSourceInfo2*)(*i);
/* Init these for later */
pASMSourceInfo->MasterOffer() = 0;
}
lAggregateBandwidthUsage = m_ulOfferToRecalc;
INT32 lCorrectAggregateBandwidthUsage = lAggregateBandwidthUsage;
/*
* For each stream that is at a fixed bitrate, remove that bitrate
* from our available bandwidth.
*/
for (streamItr.Reset(); streamItr.More(); streamItr.Next())
{
INT32 lBias;
pASMStreamInfo = streamItr.Stream();
HX_VERIFY(HXR_OK == pASMStreamInfo->GetBiasFactor(lBias));
fBiasMean += lBias;
if (pASMStreamInfo->IsFixedBw())
{
lAggregateBandwidthUsage -= pASMStreamInfo->CurrentBw();
ulStreamCount--;
}
/* Init this for later */
pASMStreamInfo->SetStreamOffer(0);
}
if (ulStreamCount != 0)
{
/* At least 1 stream is not fixed bandwidth */
fBiasMean /= ulStreamCount;
/*
* Calculate the offer for each source that has a master rulebook
* defining it's bandwidth division.
*/
INT32 lNewAggregateBandwidthUsage = lAggregateBandwidthUsage;
for (streamItr.Reset(); streamItr.More(); streamItr.Next())
{
INT32 lBias;
pASMStreamInfo = streamItr.Stream();
pASMSourceInfo = streamItr.Source();
HX_VERIFY(HXR_OK == pASMStreamInfo->GetBiasFactor(lBias));
if (pASMSourceInfo->HasMasterRuleBook())
{
UINT32 ulOffer =
(UINT32)(lAggregateBandwidthUsage / ulStreamCount);
ulOffer +=
(UINT32)(((float)lBias - fBiasMean) *
((float)lAggregateBandwidthUsage / 100.0) *
(2.0 / ulStreamCount));
pASMSourceInfo->MasterOffer() += ulOffer;
lNewAggregateBandwidthUsage -= ulOffer;
}
}
lAggregateBandwidthUsage = lNewAggregateBandwidthUsage;
}
/*
* For each source that has a master rule book, evaluate it to find
* out how much to distribute to each stream.
*/
for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
{
pASMSourceInfo = (ASMSourceInfo2*)(*i);
if (pASMSourceInfo->HasMasterRuleBook())
{
pASMSourceInfo->DistributeBw();
}
}
/*
* Now go through each of the streams that are not at a
* fixed bitrate and try to distribute the rest of the bandwidth.
*/
UINT32 ulTakenBandwidth = 0;
for (streamItr.Reset(); streamItr.More(); streamItr.Next())
{
pASMStreamInfo = streamItr.Stream();
if (!pASMStreamInfo->IsFixedBw())
{
INT32 lBias;
HX_VERIFY(HXR_OK == pASMStreamInfo->GetBiasFactor(lBias));
UINT32 ulAltOffer =
(UINT32)(lAggregateBandwidthUsage / (float)ulStreamCount);
ulAltOffer += (UINT32)(((float)lBias - fBiasMean) *
((float)lAggregateBandwidthUsage / 100.0) *
(2.0 / (float)ulStreamCount));
pASMStreamInfo->SelectBw(streamItr.Source()->IsPerfectPlay(),
ulAltOffer);
}
ulTakenBandwidth += pASMStreamInfo->CurrentBw();
}
lAggregateBandwidthUsage = lCorrectAggregateBandwidthUsage;
BOOL bDone = FALSE;
while (!bDone && (lAggregateBandwidthUsage < (INT32)ulTakenBandwidth))
{
/* Resistance is Futile. You will be Real(tm)lyAssimilated */
UINT32 ulLowestResistance = 0xffffffff;
ASMStreamInfo2* pLowestResistanceStream = 0;
// Find the stream with the lowest resistence
for (streamItr.Reset(); streamItr.More(); streamItr.Next())
{
pASMStreamInfo = streamItr.Stream();
if (pASMStreamInfo->ResistanceToLower() < ulLowestResistance)
{
ulLowestResistance = pASMStreamInfo->ResistanceToLower();
pLowestResistanceStream = pASMStreamInfo;
}
}
if (ulLowestResistance == 0xffffffff)
{
bDone = TRUE;
}
else
{
ulTakenBandwidth -= (UINT32)
pLowestResistanceStream->CurrentBw();
pLowestResistanceStream->SelectNextLowerBw();
ulTakenBandwidth += (UINT32)
pLowestResistanceStream->CurrentBw();
}
}
UINT32 ulLeftOverForDropByN = lAggregateBandwidthUsage - ulTakenBandwidth;
BOOL bForce = FALSE;
for (streamItr.Reset(); streamItr.More(); streamItr.Next())
{
pASMStreamInfo = streamItr.Stream();
UINT32 ulBw = pASMStreamInfo->CurrentBw();
if (ulBw == 1)
{
// Hack Alert for DropByN. XXXSMP
ulBw = ulLeftOverForDropByN;
}
if ((ulBw != pASMStreamInfo->GetLastBw()) &&
(pASMStreamInfo->IsFixedBw()))
{
bForce = TRUE;
}
CHXSimpleList* pSubsChanges =
streamItr.Source()->SubsChanges();
pASMStreamInfo->SubscribeToNewBw(ulBw, pSubsChanges);
}
for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
{
pASMSourceInfo = (ASMSourceInfo2*)(*i);
pASMSourceInfo->SubscribeToChanges();
pASMSourceInfo->SetDeliveryBw(m_ulSustainableBitRate);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -