fbbufctl.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:25k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2003 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hxtypes.h"
- #include "hxcom.h"
- #include "fbbufctl.h"
- #include "hlxclib/math.h"
- #include "hxprefutil.h"
- //#define HELIX_FEATURE_DBG_LOG
- //#define BUFFER_CONTROL_TESTING
- #include "hxtick.h"
- #include "errdbg.h"
- #include "hxstring.h"
- #include "hxurl.h"
- #include "ihxpckts.h" // IHXValues
- #include "hxfiles.h" // IHXRequest
- HXFeedbackControl::HXFeedbackControl() :
- m_delt(0),
- m_a1(0),
- m_a2(0),
- m_b1(0),
- m_b2(0),
- m_ulSetPoint(0),
- m_ulMin(0),
- m_ulMax(0xffffffff),
- m_e1(0),
- m_e2(0),
- m_c1(0),
- m_c2(0)
- {}
- void HXFeedbackControl::Init(double c, double wn, double Kv, double delt)
- {
- // calculate coefficients
- double d = exp(-wn * c);
- double wd = wn * sqrt(1.0 - c *c);
- double pReal = d * cos(wd);
- double pImag = d * sin(wd);
- m_b1 = -2.0 * pReal;
- m_b2 = pReal * pReal + pImag * pImag;
- m_a1 = 2.0 + m_b1 - (1.0 + m_b1 + m_b2)/(Kv * delt);
- m_a2 = 1.0 + m_b1 + m_b2 - m_a1;
- m_delt = delt;
- }
-
- void HXFeedbackControl::Reset(UINT32 ulSetPoint,
- INT32 e1, INT32 e2,
- UINT32 c1, UINT32 c2)
- {
- m_ulSetPoint = ulSetPoint;
- m_e1 = e1;
- m_e2 = e2;
- m_c1 = c1;
- m_c2 = c2;
- }
- void HXFeedbackControl::SetLimits(UINT32 ulMin, UINT32 ulMax)
- {
- m_ulMin = ulMin;
- m_ulMax = ulMax;
- }
- UINT32 HXFeedbackControl::Control(UINT32 ulCurrentBits)
- {
- INT32 error = (INT32)m_ulSetPoint - (INT32)ulCurrentBits;
- UINT32 ulControlBw = 0;
-
- double u1 = (m_a1 * (double)error +
- (m_a2 - m_a1) * (double)m_e1 -
- m_a2 * (double)m_e2) / m_delt;
-
- double u2 = -((m_b1 - m_a1) * (double)m_c1 +
- (m_b2 - m_a2) * (double)m_c2);
-
- ulControlBw = RoundAndClip(u1 + u2);
- Enqueue(error, ulControlBw);
- return ulControlBw;
- }
- UINT32 HXFeedbackControl::RoundAndClip(double value) const
- {
- UINT32 ulRet = m_ulMin;
- if (value > m_ulMax)
- {
- // Saturate to max
- ulRet = m_ulMax;
- }
- else if (value > m_ulMin)
- {
- // Value within range.
- // Round to nearest integer
- ulRet = (UINT32)(value + 0.5);
- }
- return ulRet;
- }
- void HXFeedbackControl::Enqueue(INT32 error, UINT32 ulBandwidth)
- {
- m_e2 = m_e1;
- m_e1 = error;
- m_c2 = m_c1;
- m_c1 = ulBandwidth;
- }
- HXFeedbackBufferControl::HXFeedbackBufferControl() :
- m_lRefCount(0),
- m_pScheduler(NULL),
- m_callbackHandle(0),
- m_pSource(NULL),
- m_pBufferStats(NULL),
- m_pThin(NULL),
- m_pPrefs(NULL),
- m_pStatus(NULL),
- m_pErrMsg(NULL),
- m_ulClipBw(0),
- m_nControlStream(0),
- m_ulControlBw(0),
- m_bControlTotal(FALSE),
- m_bPaused(TRUE),
- m_state(csNotInitialized)
- {
- m_control.Init(0.7, 1.25664, 0.2, 5.0);
- }
- HXFeedbackBufferControl::~HXFeedbackBufferControl()
- {
- Close();
- }
- /*
- * IUnknown methods
- */
- STDMETHODIMP HXFeedbackBufferControl::QueryInterface(THIS_
- REFIID riid,
- void** ppvObj)
- {
- QInterfaceList qiList[] =
- {
- { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXBufferControl*)this },
- { GET_IIDHANDLE(IID_IHXBufferControl), (IHXBufferControl*)this },
- { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
- };
-
- return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
- }
- STDMETHODIMP_(ULONG32) HXFeedbackBufferControl::AddRef(THIS)
- {
- return InterlockedIncrement(&m_lRefCount);
- }
- STDMETHODIMP_(ULONG32) HXFeedbackBufferControl::Release(THIS)
- {
- if (InterlockedDecrement(&m_lRefCount) > 0)
- {
- return m_lRefCount;
- }
- delete this;
- return 0;
- }
- /*
- * IHXBufferControl method
- */
- /************************************************************************
- * Method:
- * IHXBufferControl::Init
- * Purpose:
- * Initialize the buffer control object with a context
- * so it can find the interfaces it needs to do buffer
- * control
- */
- STDMETHODIMP HXFeedbackBufferControl::Init(THIS_ IUnknown* pContext)
- {
- HX_RESULT res = HXR_FAILED;
-
- Close();
- if (pContext)
- {
- pContext->QueryInterface(IID_IHXErrorMessages, (void**)&m_pErrMsg);
- if ((HXR_OK == pContext->QueryInterface(IID_IHXScheduler,
- (void**)&m_pScheduler)) &&
- (HXR_OK == pContext->QueryInterface(IID_IHXStreamSource,
- (void**)&m_pSource)) &&
- (m_pSource) &&
- (HXR_OK == m_pSource->QueryInterface(IID_IHXThinnableSource,
- (void**)&m_pThin)) &&
- (HXR_OK == pContext->QueryInterface(IID_IHXSourceBufferingStats2,
- (void**)&m_pBufferStats)) &&
- (HXR_OK == pContext->QueryInterface(IID_IHXPendingStatus,
- (void**)&m_pStatus)) &&
- (HXR_OK == pContext->QueryInterface(IID_IHXPreferences,
- (void**)&m_pPrefs)) &&
- (HXR_OK == ReadPrefSettings()))
- {
- #ifdef BUFFER_CONTROL_TESTING
- res = InitTesting(pContext);
- #endif
- res = HXR_OK;
- }
- else
- {
- ChangeState(csError);
- }
- }
- return res;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::OnBuffering
- * Purpose:
- * Called while buffering
- */
- STDMETHODIMP HXFeedbackBufferControl::OnBuffering(UINT32 ulRemainingInMs,
- UINT32 ulRemainingInBytes)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnBuffering(%d, %d)",
- ulRemainingInMs, ulRemainingInBytes));
-
- if (Initialized() &&
- (csBuffering != m_state))
- {
- ChangeState(csBuffering);
- SetBandwidth(m_ulClipBw);
- }
-
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::OnBufferingDone
- * Purpose:
- * Called when buffering is done
- */
- STDMETHODIMP HXFeedbackBufferControl::OnBufferingDone(THIS)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnBufferingDone"));
- if (Initialized())
- {
- HX_ASSERT(csBuffering == m_state);
- UINT32 ulTotalBits = 0;
- UINT32 ulControlBits = 0;
- GetControlData(ulTotalBits, ulControlBits);
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::OnBufferingDone() %d %d",
- ulTotalBits,
- ulControlBits));
- UINT32 ulSetPoint = ulControlBits;
- if (ulSetPoint < m_control.SetPoint())
- {
- // If the new setpoint is less than a
- // previous value, ignore it and use
- // the old setpoint.
- ulSetPoint = m_control.SetPoint();
- }
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::OBD reset control %lu",
- ulSetPoint));
- m_control.Reset(ulSetPoint,
- 0, 0, // Error state
- m_ulControlBw, m_ulControlBw); // control state
- if (m_bPaused)
- {
- ChangeState(csPaused);
- }
- else
- {
- ChangeState(csPlaying);
- }
- }
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::OnResume
- * Purpose:
- * Called when playback is resumed
- */
- STDMETHODIMP HXFeedbackBufferControl::OnResume()
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnResume"));
- m_bPaused = FALSE;
- if (csError != m_state)
- {
- if (HXR_OK == GetBwInfo(m_ulClipBw, m_nControlStream, m_ulControlBw))
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::OnResume : clipBw %lu ctlStr %u ctlBw %lu",
- m_ulClipBw,
- m_nControlStream,
- m_ulControlBw));
-
- SetTransportByteLimits(m_ulClipBw);
- if (m_pSource && !m_pSource->IsLive() &&
- m_ulClipBw && m_ulControlBw)
- {
- /* Only activate the algorithm for on-demand clips that
- * have bitrate information
- */
- if (csNotInitialized == m_state)
- {
- StartCallback();
- }
-
- ChangeState(csPlaying);
- }
- SetBandwidth(m_ulClipBw);
- }
- }
- return HXR_OK;
- }
-
- /************************************************************************
- * Method:
- * IHXBufferControl::OnPause
- * Purpose:
- * Called when playback is paused
- */
- STDMETHODIMP HXFeedbackBufferControl::OnPause()
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnPause"));
-
- m_bPaused = TRUE;
- if (Initialized())
- {
- ChangeState(csPaused);
- }
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::OnSeek
- * Purpose:
- * Called when a seek occurs
- */
- STDMETHODIMP HXFeedbackBufferControl::OnSeek(THIS)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnSeek"));
- if (Initialized())
- {
- ChangeState(csSeeking);
- }
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::OnClipEnd
- * Purpose:
- * Called when we get the last packet in the clip
- */
- STDMETHODIMP HXFeedbackBufferControl::OnClipEnd(THIS)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnClipEnd"));
- if (Initialized())
- {
- ChangeState(csClipEnd);
- }
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXBufferControl::Close()
- * Purpose:
- * Called when the owner of this object wishes to shutdown
- * and destroy this object. This call causes the buffer control
- * object to release all it's interfaces references.
- */
- STDMETHODIMP HXFeedbackBufferControl::Close(THIS)
- {
- HX_RELEASE(m_pErrMsg);
- StopCallback();
- HX_RELEASE(m_pScheduler);
- HX_RELEASE(m_pBufferStats);
- HX_RELEASE(m_pSource);
- HX_RELEASE(m_pThin);
- HX_RELEASE(m_pPrefs);
- HX_RELEASE(m_pStatus);
- ChangeState(csNotInitialized);
- return HXR_OK;
- }
- /************************************************************************
- * Method:
- * IHXCallback::Func
- * Purpose:
- * This is the function that will be called when a callback is
- * to be executed.
- */
- STDMETHODIMP HXFeedbackBufferControl::Func(THIS)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::Func"));
- if (Initialized())
- {
- UINT32 ulNewBandwidth = 0;
- if (csPlaying == m_state)
- {
- UINT32 ulTotalBits = 0;
- UINT32 ulControlBits = 0;
- UINT32 ulNewBandwidth = 0;
-
- GetControlData(ulTotalBits, ulControlBits);
-
- if (HXR_OK == Control(ulControlBits, ulNewBandwidth))
- {
- SetBandwidth(ulNewBandwidth);
- }
- }
- else if (csBuffering == m_state)
- {
- // Bandwidth used during buffering and seeking
- SetBandwidth(m_ulClipBw);
- }
- ScheduleCallback();
- }
- return HXR_OK;
- }
- void HXFeedbackBufferControl::ChangeState(ControlState newState)
- {
- if (csError != m_state)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::CS : %lu %d -> %d",
- HX_GET_TICKCOUNT(), m_state, newState));
- m_state = newState;
- }
- else
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::CS : Tried to leave error state"));
- HX_ASSERT(csError == m_state);
- }
- }
- void HXFeedbackBufferControl::ScheduleCallback()
- {
- if (m_pScheduler)
- {
- UINT32 uDelayInMs = (UINT32)(m_control.SamplePeriod() * 1000);
- m_lastTime.tv_sec += uDelayInMs / 1000;
- m_lastTime.tv_usec += (uDelayInMs * 1000) * 1000;
-
- m_callbackHandle = m_pScheduler->AbsoluteEnter(this, m_lastTime);
- }
- }
- void HXFeedbackBufferControl::StartCallback()
- {
- if (m_pScheduler)
- {
- m_lastTime = m_pScheduler->GetCurrentSchedulerTime();
-
- ScheduleCallback();
- }
- }
- void HXFeedbackBufferControl::StopCallback()
- {
- if (m_pScheduler && m_callbackHandle)
- {
- m_pScheduler->Remove(m_callbackHandle);
- m_callbackHandle = 0;
- }
- }
- HX_RESULT HXFeedbackBufferControl::GetBwInfo(REF(UINT32) ulClipBw,
- REF(UINT16) nControlStream,
- REF(UINT32) ulControlBw)
- {
- HX_RESULT res = HXR_OK;
- if (!m_pSource)
- {
- res = HXR_FAILED;
- }
- else if (m_pSource->GetStreamCount() == 0)
- {
- res = HXR_NO_DATA;
- }
- else
- {
- ulClipBw = 0;
- nControlStream = 0;
- ulControlBw = 0;
-
- UINT32 ulHighestBw = 0;
- UINT16 nHighestBwStream = 0;
- BOOL bFoundAudio = FALSE;
- UINT32 ulLowAudioBw = 0;
- UINT16 nLowestBwAudioStream = 0;
- for (UINT16 i = 0; (HXR_OK == res) && (i < m_pSource->GetStreamCount()); i++)
- {
- UINT32 ulStreamBw = 0;
- if (HXR_OK == GetStreamBw(i, ulStreamBw))
- {
- if (ulStreamBw > ulHighestBw)
- {
- ulHighestBw = ulStreamBw;
- nHighestBwStream = i;
- }
- if (IsAudioStream(i) &&
- (!bFoundAudio || (ulStreamBw < ulLowAudioBw)))
- {
- bFoundAudio = TRUE;
- ulLowAudioBw = ulStreamBw;
- nLowestBwAudioStream = i;
- }
- ulClipBw += ulStreamBw;
- }
- }
- if (bFoundAudio)
- {
- nControlStream = nLowestBwAudioStream;
- ulControlBw = ulLowAudioBw;
- }
- else
- {
- nControlStream = nHighestBwStream;
- ulControlBw = ulHighestBw;
- }
- }
- return res;
- }
- HX_RESULT
- HXFeedbackBufferControl::GetStreamBw(UINT16 uStreamNumber,
- REF(UINT32) ulBandwidth)
- {
- HX_RESULT res = HXR_FAILED;
- if (m_pSource)
- {
- IUnknown* pUnk = NULL;
- res = m_pSource->GetStream(uStreamNumber, pUnk);
-
- if (HXR_OK == res)
- {
- IHXASMProps* pProps = NULL;
-
- res = pUnk->QueryInterface(IID_IHXASMProps, (void**)&pProps);
- if (HXR_OK == res)
- {
- res = pProps->GetBandwidth(ulBandwidth);
-
- pProps->Release();
- }
- pUnk->Release();
- }
- }
- return res;
- }
- BOOL HXFeedbackBufferControl::IsAudioStream(UINT16 uStreamNumber)
- {
- BOOL bRet = FALSE;
- if (m_pSource)
- {
- IUnknown* pUnk = NULL;
- IHXStream* pStream = NULL;
- IHXValues* pHeader = NULL;
- IHXBuffer* pMimetype = NULL;
- if ((HXR_OK == m_pSource->GetStream(uStreamNumber, pUnk)) &&
- (HXR_OK == pUnk->QueryInterface(IID_IHXStream, (void**)&pStream))&&
- (NULL != (pHeader = pStream->GetHeader())) &&
- (HXR_OK == pHeader->GetPropertyCString("MimeType", pMimetype)) &&
- (!strncasecmp("audio", (char*)pMimetype->GetBuffer(), 5)))
- {
- bRet = TRUE;
- }
- HX_RELEASE(pMimetype);
- HX_RELEASE(pHeader);
- HX_RELEASE(pStream);
- HX_RELEASE(pUnk);
- }
- return bRet;
- }
- void HXFeedbackBufferControl::GetControlData(REF(UINT32) ulTotalBits,
- REF(UINT32) ulControlBits)
- {
- ulTotalBits = 0;
- ulControlBits = 0;
-
- for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
- {
- UINT32 ulBytes;
-
- HX_RESULT res = HXR_FAILED;
- INT64 llLowTS;
- INT64 llHighTS;
- BOOL bDone;
- res = m_pBufferStats->GetTotalBuffering(i,
- llLowTS, llHighTS,
- ulBytes,
- bDone);
- if (HXR_OK == res)
- {
- ulTotalBits += 8 * ulBytes;
-
- if (i == m_nControlStream)
- {
- ulControlBits = 8 * ulBytes;
- }
- }
- }
- }
- HX_RESULT HXFeedbackBufferControl::Control(UINT32 ulControlBits,
- REF(UINT32) ulNewBandwidth)
- {
- UINT32 ulSetPoint = m_control.SetPoint();
- INT32 error = (INT32)ulSetPoint - (INT32)ulControlBits;
-
- double errorFactor = error;
- ulNewBandwidth = m_control.Control(ulControlBits);
- ulNewBandwidth = ControlToTotal(ulNewBandwidth);
- if (ulSetPoint)
- {
- errorFactor = (double)error / (double)ulSetPoint;
- }
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::CTL %lu %d %lu %lu %2.4f",
- HX_GET_TICKCOUNT(),
- error,
- ulNewBandwidth,
- ulControlBits,
- errorFactor));
-
- return HXR_OK;
- }
- void HXFeedbackBufferControl::SetBandwidth(UINT32 ulBandwidth)
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC::SB %lu %lu ",
- HX_GET_TICKCOUNT(), ulBandwidth));
- if (m_pThin)
- {
- m_pThin->SetDeliveryBandwidth(ulBandwidth, 0);
- }
- }
- HX_RESULT HXFeedbackBufferControl::ReadPrefSettings()
- {
- HX_RESULT res = HXR_FAILED;
-
- UINT32 ulMin = 1000;
- UINT32 ulMax = 0;
- ReadPrefINT32(m_pPrefs, "MinDelBandwidth", ulMin);
- /* Get initial bandwidth guess from Prefs */
- if (HXR_OK == ReadPrefINT32(m_pPrefs, "Bandwidth", ulMax))
- {
- UINT32 ulSustainFactor = 0;
- /* See if we have a sustainable bandwidth factor */
- if (HXR_OK == ReadPrefINT32(m_pPrefs, "SustainableBwFactor",
- ulSustainFactor))
- {
- /* clamp value to 0 <= ulTemp <= 100 range */
- if (ulSustainFactor > 100)
- {
- ulSustainFactor = 100;
- }
-
- /* Apply factor */
- ulMax = (((ulMax / 100) * ulSustainFactor) +
- (((ulMax % 100) * ulSustainFactor) / 100));
- }
- if (ulMax > 0)
- {
- if (ulMin > ulMax)
- {
- // Make the minimum bandwidh 1% of the max
- // rounded up to the next bit/second
- ulMin = (ulMax + 99) / 100;
- }
-
- m_control.SetLimits(ulMin, ulMax);
-
- res = HXR_OK;
- }
- }
- return res;
- }
- void HXFeedbackBufferControl::SetTransportByteLimits(UINT32 ulClipBw)
- {
- UINT32 ulTotalByteLimit = 0;
- IHXTransportBufferLimit* pBufLimit = NULL;
- ReadPrefINT32(m_pPrefs, "TransportByteLimit", ulTotalByteLimit);
- if (m_pSource &&
- (HXR_OK == m_pSource->QueryInterface(IID_IHXTransportBufferLimit,
- (void**)&pBufLimit)))
- {
- // Divide the byte limit amoung the streams
- for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
- {
- UINT32 ulStreamBw = 0;
- if (HXR_OK == GetStreamBw(i, ulStreamBw))
- {
- // Byte limit for this stream is
- // (ulTotalByteLimit * ulStreamBw) / ulClipBw
- UINT32 ulByteLimit = MulDiv(ulTotalByteLimit,
- ulStreamBw, ulClipBw);
-
- if ((ulByteLimit == 0) &&
- (ulTotalByteLimit != 0))
- {
- // Make sure all streams have a byte limit
- // if ulTotalByteLimit is non-zero. This is done
- // because a byte limit of 0 means unlimited
- // buffering is allowed
- ulByteLimit = 1;
- }
- pBufLimit->SetByteLimit(i, ulByteLimit);
- }
- }
- }
- HX_RELEASE(pBufLimit);
- }
- HX_RESULT HXFeedbackBufferControl::InitTesting(IUnknown* pContext)
- {
- HX_RESULT res = HXR_OK;
- IHXRequest* pRequest = NULL;
- const char* pURL = 0;
- if (HXR_OK == pContext->QueryInterface(IID_IHXRequest,
- (void**)&pRequest) &&
- HXR_OK == pRequest->GetURL(pURL))
- {
- CHXURL url(pURL, pContext);
-
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC : url %s", pURL));
-
- IHXValues* pOptions = url.GetOptions();
- ULONG32 ulTmp;
-
- if (pOptions)
- {
- if (HXR_OK == pOptions->GetPropertyULONG32("FBBC-total_control",
- ulTmp))
- {
- DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
- (s, "FBBC : total control %lu", ulTmp));
- m_bControlTotal = (ulTmp > 0) ? TRUE : FALSE;
- }
- }
-
- HX_RELEASE(pOptions);
- HX_RELEASE(pRequest);
- }
- return res;
- }
- BOOL HXFeedbackBufferControl::IsBuffering()
- {
- BOOL bRet = FALSE;
- IHXBuffer* pStatusDesc = NULL;
- UINT16 unStatusCode = 0;
- UINT16 unPercentDone = 0;
- if (m_pStatus &&
- (HXR_OK == m_pStatus->GetStatus(unStatusCode,
- pStatusDesc, unPercentDone)) &&
- (unStatusCode == HX_STATUS_BUFFERING))
- {
- bRet = TRUE;
- }
- HX_RELEASE(pStatusDesc);
- return bRet;
- }
- UINT32 HXFeedbackBufferControl::ClampBandwidth(UINT32 ulBandwidth) const
- {
- UINT32 ulRet = ulBandwidth;
- if (ulRet < m_control.Min())
- {
- ulRet = m_control.Min();
- }
- else if (ulRet > m_control.Max())
- {
- ulRet = m_control.Max();
- }
- return ulRet;
- }
- UINT32 HXFeedbackBufferControl::ControlToTotal(UINT32 ulValue)
- {
- return MulDiv(ulValue, m_ulClipBw, m_ulControlBw);
- }
- UINT32 HXFeedbackBufferControl::TotalToControl(UINT32 ulValue)
- {
- return MulDiv(ulValue, m_ulControlBw, m_ulClipBw);
- }
- UINT32 HXFeedbackBufferControl::MulDiv(UINT32 ulValue,
- UINT32 ulMult, UINT32 ulDiv)
- {
- return (((ulValue / ulDiv) * ulMult) +
- ((ulValue % ulDiv) * ulMult) / ulDiv);
- }