fbbufctl.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:25k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: RCSL 1.0/RPSL 1.0
  3.  *
  4.  * Portions Copyright (c) 1995-2003 RealNetworks, Inc. All Rights Reserved.
  5.  *
  6.  * The contents of this file, and the files included with this file, are
  7.  * subject to the current version of the RealNetworks Public Source License
  8.  * Version 1.0 (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the RealNetworks Community Source License Version 1.0
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
  12.  * in which case the RCSL will apply. You may also obtain the license terms
  13.  * directly from RealNetworks.  You may not use this file except in
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or
  16.  * RCSL for the rights, obligations and limitations governing use of the
  17.  * contents of the file.
  18.  *
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the
  20.  * developer of the Original Code and owns the copyrights in the portions
  21.  * it created.
  22.  *
  23.  * This file, and the files included with this file, is distributed and made
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  28.  *
  29.  * Technology Compatibility Kit Test Suite(s) Location:
  30.  *    http://www.helixcommunity.org/content/tck
  31.  *
  32.  * Contributor(s):
  33.  *
  34.  * ***** END LICENSE BLOCK ***** */
  35. #include "hxtypes.h"
  36. #include "hxcom.h"
  37. #include "fbbufctl.h"
  38. #include "hlxclib/math.h"
  39. #include "hxprefutil.h"
  40. //#define HELIX_FEATURE_DBG_LOG
  41. //#define BUFFER_CONTROL_TESTING
  42. #include "hxtick.h"
  43. #include "errdbg.h"
  44. #include "hxstring.h"
  45. #include "hxurl.h"
  46. #include "ihxpckts.h" // IHXValues
  47. #include "hxfiles.h" // IHXRequest
  48. HXFeedbackControl::HXFeedbackControl() :
  49.     m_delt(0),
  50.     m_a1(0),
  51.     m_a2(0),
  52.     m_b1(0),
  53.     m_b2(0),
  54.     m_ulSetPoint(0),
  55.     m_ulMin(0),
  56.     m_ulMax(0xffffffff),
  57.     m_e1(0),
  58.     m_e2(0),
  59.     m_c1(0),
  60.     m_c2(0)
  61. {}
  62. void HXFeedbackControl::Init(double c, double wn, double Kv, double delt)
  63. {
  64.     // calculate coefficients
  65.     double d = exp(-wn * c);
  66.     double wd = wn * sqrt(1.0 - c *c);
  67.     double pReal = d * cos(wd);
  68.     double pImag = d * sin(wd);
  69.     m_b1 = -2.0 * pReal;
  70.     m_b2 = pReal * pReal + pImag * pImag;
  71.     m_a1 = 2.0 + m_b1 - (1.0 + m_b1 + m_b2)/(Kv * delt);
  72.     m_a2 = 1.0 + m_b1 + m_b2 - m_a1;
  73.     m_delt = delt;
  74. }
  75.     
  76. void HXFeedbackControl::Reset(UINT32 ulSetPoint, 
  77.                               INT32 e1, INT32 e2,
  78.                               UINT32 c1, UINT32 c2)
  79. {
  80.     m_ulSetPoint = ulSetPoint;
  81.     m_e1 = e1;
  82.     m_e2 = e2;
  83.     m_c1 = c1;
  84.     m_c2 = c2;
  85. }
  86. void HXFeedbackControl::SetLimits(UINT32 ulMin, UINT32 ulMax)
  87. {
  88.     m_ulMin = ulMin;
  89.     m_ulMax = ulMax;
  90. }
  91. UINT32 HXFeedbackControl::Control(UINT32 ulCurrentBits)
  92. {
  93.     INT32 error =  (INT32)m_ulSetPoint - (INT32)ulCurrentBits;
  94.     UINT32 ulControlBw = 0;
  95.     
  96.     double u1 = (m_a1 * (double)error + 
  97.                  (m_a2 - m_a1) * (double)m_e1 -
  98.                  m_a2 * (double)m_e2) / m_delt;
  99.     
  100.     double u2 = -((m_b1 - m_a1) * (double)m_c1 +
  101.                   (m_b2 - m_a2) * (double)m_c2);
  102.     
  103.     ulControlBw = RoundAndClip(u1 + u2);
  104.     Enqueue(error, ulControlBw);
  105.     return ulControlBw;
  106. }
  107. UINT32 HXFeedbackControl::RoundAndClip(double value) const
  108. {
  109.     UINT32 ulRet = m_ulMin;
  110.     if (value > m_ulMax)
  111.     {
  112.         // Saturate to max
  113.         ulRet = m_ulMax;
  114.     }
  115.     else if (value > m_ulMin)
  116.     {
  117.         // Value within range.
  118.         // Round to nearest integer
  119.         ulRet = (UINT32)(value + 0.5);
  120.     }
  121.     return ulRet;
  122. }
  123. void HXFeedbackControl::Enqueue(INT32 error, UINT32 ulBandwidth)
  124. {
  125.     m_e2 = m_e1;
  126.     m_e1 = error;
  127.     m_c2 = m_c1;
  128.     m_c1 = ulBandwidth;
  129. }
  130. HXFeedbackBufferControl::HXFeedbackBufferControl() :
  131.     m_lRefCount(0),
  132.     m_pScheduler(NULL),
  133.     m_callbackHandle(0),
  134.     m_pSource(NULL),
  135.     m_pBufferStats(NULL),
  136.     m_pThin(NULL),
  137.     m_pPrefs(NULL),
  138.     m_pStatus(NULL),
  139.     m_pErrMsg(NULL),
  140.     m_ulClipBw(0),
  141.     m_nControlStream(0),
  142.     m_ulControlBw(0),
  143.     m_bControlTotal(FALSE),
  144.     m_bPaused(TRUE),
  145.     m_state(csNotInitialized)
  146. {
  147.     m_control.Init(0.7, 1.25664, 0.2, 5.0);
  148. }
  149. HXFeedbackBufferControl::~HXFeedbackBufferControl()
  150. {
  151.     Close();
  152. }
  153. /*
  154.  *      IUnknown methods
  155.  */
  156. STDMETHODIMP HXFeedbackBufferControl::QueryInterface(THIS_
  157.                                                      REFIID riid,
  158.                                                      void** ppvObj)
  159. {
  160.     QInterfaceList qiList[] =
  161.     {
  162.         { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXBufferControl*)this }, 
  163.         { GET_IIDHANDLE(IID_IHXBufferControl), (IHXBufferControl*)this },
  164.         { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
  165.     };
  166.     
  167.     return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
  168. }
  169. STDMETHODIMP_(ULONG32) HXFeedbackBufferControl::AddRef(THIS)
  170. {
  171.     return InterlockedIncrement(&m_lRefCount);
  172. }
  173. STDMETHODIMP_(ULONG32) HXFeedbackBufferControl::Release(THIS)
  174. {
  175.     if (InterlockedDecrement(&m_lRefCount) > 0)
  176.     {
  177.         return m_lRefCount;
  178.     }
  179.     delete this;
  180.     return 0;
  181. }
  182. /*
  183.  * IHXBufferControl method
  184.  */
  185. /************************************************************************
  186.  *      Method:
  187.  *          IHXBufferControl::Init
  188.  *      Purpose:
  189.  *      Initialize the buffer control object with a context
  190.  *      so it can find the interfaces it needs to do buffer
  191.  *      control
  192.  */
  193. STDMETHODIMP HXFeedbackBufferControl::Init(THIS_ IUnknown* pContext)
  194. {
  195.     HX_RESULT res = HXR_FAILED;
  196.     
  197.     Close();
  198.     if (pContext)
  199.     {
  200.         pContext->QueryInterface(IID_IHXErrorMessages, (void**)&m_pErrMsg);
  201.         if ((HXR_OK == pContext->QueryInterface(IID_IHXScheduler, 
  202.                                                 (void**)&m_pScheduler)) &&
  203.             (HXR_OK == pContext->QueryInterface(IID_IHXStreamSource, 
  204.                                                 (void**)&m_pSource)) &&
  205.             (m_pSource) && 
  206.             (HXR_OK == m_pSource->QueryInterface(IID_IHXThinnableSource, 
  207.                                                  (void**)&m_pThin)) &&
  208.             (HXR_OK == pContext->QueryInterface(IID_IHXSourceBufferingStats2,
  209.                                                 (void**)&m_pBufferStats)) &&
  210.             (HXR_OK == pContext->QueryInterface(IID_IHXPendingStatus, 
  211.                                                 (void**)&m_pStatus)) &&
  212.             (HXR_OK == pContext->QueryInterface(IID_IHXPreferences, 
  213.                                                 (void**)&m_pPrefs)) &&
  214.             (HXR_OK == ReadPrefSettings()))
  215.         {
  216. #ifdef BUFFER_CONTROL_TESTING
  217.             res = InitTesting(pContext);
  218. #endif
  219.             res = HXR_OK;
  220.         }
  221.         else
  222.         {
  223.             ChangeState(csError);
  224.         }
  225.     }
  226.     return res;
  227. }
  228. /************************************************************************
  229.  *      Method:
  230.  *          IHXBufferControl::OnBuffering
  231.  *      Purpose:
  232.  *          Called while buffering
  233.  */
  234. STDMETHODIMP HXFeedbackBufferControl::OnBuffering(UINT32 ulRemainingInMs,
  235.                                                   UINT32 ulRemainingInBytes)
  236. {
  237.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnBuffering(%d, %d)",
  238.                                              ulRemainingInMs, ulRemainingInBytes));
  239.     
  240.     if (Initialized() &&
  241.         (csBuffering != m_state))
  242.     {
  243.         ChangeState(csBuffering);
  244.         SetBandwidth(m_ulClipBw);
  245.     }
  246.     
  247.     return HXR_OK;
  248. }
  249. /************************************************************************
  250.  *      Method:
  251.  *          IHXBufferControl::OnBufferingDone
  252.  *      Purpose:
  253.  *      Called when buffering is done
  254.  */
  255. STDMETHODIMP HXFeedbackBufferControl::OnBufferingDone(THIS)
  256. {
  257.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnBufferingDone"));
  258.     if (Initialized())
  259.     {
  260.         HX_ASSERT(csBuffering == m_state);
  261.         UINT32 ulTotalBits = 0;
  262.         UINT32 ulControlBits = 0;
  263.         GetControlData(ulTotalBits, ulControlBits);
  264.         DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  265.                   (s, "FBBC::OnBufferingDone() %d %d",
  266.                    ulTotalBits,
  267.                    ulControlBits));
  268.         UINT32 ulSetPoint = ulControlBits;
  269.         if (ulSetPoint < m_control.SetPoint())
  270.         {
  271.             // If the new setpoint is less than a 
  272.             // previous value, ignore it and use
  273.             // the old setpoint.
  274.             ulSetPoint = m_control.SetPoint();
  275.         }
  276.         DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, 
  277.                   (s, "FBBC::OBD reset control %lu",
  278.                    ulSetPoint));
  279.         m_control.Reset(ulSetPoint,
  280.                         0, 0,                          // Error state
  281.                         m_ulControlBw, m_ulControlBw); // control state
  282.         if (m_bPaused)
  283.         {
  284.             ChangeState(csPaused);
  285.         }
  286.         else
  287.         {
  288.             ChangeState(csPlaying);
  289.         }
  290.     }
  291.     return HXR_OK;
  292. }
  293. /************************************************************************
  294.  *      Method:
  295.  *          IHXBufferControl::OnResume
  296.  *      Purpose:
  297.  *          Called when playback is resumed
  298.  */
  299. STDMETHODIMP HXFeedbackBufferControl::OnResume()
  300. {
  301.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,(s, "FBBC::OnResume"));
  302.     m_bPaused = FALSE;
  303.     if (csError != m_state)
  304.     {
  305.         if (HXR_OK == GetBwInfo(m_ulClipBw, m_nControlStream, m_ulControlBw))
  306.         {
  307.             DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  308.                       (s, "FBBC::OnResume : clipBw %lu ctlStr %u ctlBw %lu", 
  309.                        m_ulClipBw,
  310.                        m_nControlStream,
  311.                        m_ulControlBw));
  312.             
  313.             SetTransportByteLimits(m_ulClipBw);
  314.             if (m_pSource && !m_pSource->IsLive() && 
  315.                 m_ulClipBw && m_ulControlBw)
  316.             {
  317.                 /* Only activate the algorithm for on-demand clips that
  318.                  * have bitrate information
  319.                  */
  320.                 if (csNotInitialized == m_state)
  321.                 {
  322.                     StartCallback();
  323.                 }
  324.             
  325.                 ChangeState(csPlaying);
  326.             }
  327.             SetBandwidth(m_ulClipBw);
  328.         }
  329.     }
  330.     return HXR_OK;
  331. }
  332.     
  333. /************************************************************************
  334.  *      Method:
  335.  *          IHXBufferControl::OnPause
  336.  *      Purpose:
  337.  *          Called when playback is paused
  338.  */
  339. STDMETHODIMP HXFeedbackBufferControl::OnPause()
  340. {
  341.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnPause"));
  342.     
  343.     m_bPaused = TRUE;
  344.     if (Initialized())
  345.     {
  346.         ChangeState(csPaused);
  347.     }
  348.     return HXR_OK;
  349. }
  350. /************************************************************************
  351.  *      Method:
  352.  *          IHXBufferControl::OnSeek
  353.  *      Purpose:
  354.  *          Called when a seek occurs
  355.  */
  356. STDMETHODIMP HXFeedbackBufferControl::OnSeek(THIS)
  357. {
  358.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnSeek"));
  359.     if (Initialized())
  360.     {
  361.         ChangeState(csSeeking);
  362.     }
  363.     return HXR_OK;
  364. }
  365. /************************************************************************
  366.  *      Method:
  367.  *          IHXBufferControl::OnClipEnd
  368.  *      Purpose:
  369.  *          Called when we get the last packet in the clip
  370.  */
  371. STDMETHODIMP HXFeedbackBufferControl::OnClipEnd(THIS)
  372. {
  373.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::OnClipEnd"));
  374.     if (Initialized())
  375.     {
  376.         ChangeState(csClipEnd);
  377.     }
  378.     return HXR_OK;
  379. }
  380. /************************************************************************
  381.  *      Method:
  382.  *          IHXBufferControl::Close()
  383.  *      Purpose:
  384.  *      Called when the owner of this object wishes to shutdown
  385.  *      and destroy this object. This call causes the buffer control
  386.  *      object to release all it's interfaces references.
  387.  */
  388. STDMETHODIMP HXFeedbackBufferControl::Close(THIS)
  389. {
  390.     HX_RELEASE(m_pErrMsg);
  391.     StopCallback();
  392.     HX_RELEASE(m_pScheduler);
  393.     HX_RELEASE(m_pBufferStats);
  394.     HX_RELEASE(m_pSource);
  395.     HX_RELEASE(m_pThin);
  396.     HX_RELEASE(m_pPrefs);
  397.     HX_RELEASE(m_pStatus);
  398.     ChangeState(csNotInitialized);
  399.     return HXR_OK;
  400. }
  401. /************************************************************************
  402.  *      Method:
  403.  *          IHXCallback::Func
  404.  *      Purpose:
  405.  *          This is the function that will be called when a callback is
  406.  *          to be executed.
  407.  */
  408. STDMETHODIMP HXFeedbackBufferControl::Func(THIS)
  409. {
  410.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, (s, "FBBC::Func"));
  411.     if (Initialized())
  412.     {
  413.         UINT32 ulNewBandwidth = 0;
  414.         if (csPlaying == m_state)
  415.         {
  416.             UINT32 ulTotalBits = 0;
  417.             UINT32 ulControlBits = 0;
  418.             UINT32 ulNewBandwidth = 0;
  419.             
  420.             GetControlData(ulTotalBits, ulControlBits);
  421.             
  422.             if (HXR_OK == Control(ulControlBits, ulNewBandwidth))
  423.             {
  424.                 SetBandwidth(ulNewBandwidth);
  425.             }
  426.         }
  427.         else if (csBuffering == m_state)
  428.         {
  429.             // Bandwidth used during buffering and seeking
  430.             SetBandwidth(m_ulClipBw);
  431.         }
  432.         ScheduleCallback();
  433.     }
  434.     return HXR_OK;
  435. }
  436. void HXFeedbackBufferControl::ChangeState(ControlState newState)
  437. {
  438.     if (csError != m_state)
  439.     {
  440.         DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  441.                   (s, "FBBC::CS : %lu %d -> %d", 
  442.                    HX_GET_TICKCOUNT(), m_state, newState));
  443.         m_state = newState;
  444.     }
  445.     else
  446.     {
  447.         DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  448.                   (s, "FBBC::CS : Tried to leave error state"));
  449.         HX_ASSERT(csError == m_state);
  450.     }
  451. }
  452. void HXFeedbackBufferControl::ScheduleCallback()
  453. {
  454.     if (m_pScheduler)
  455.     {
  456.         UINT32 uDelayInMs = (UINT32)(m_control.SamplePeriod() * 1000);
  457.         m_lastTime.tv_sec += uDelayInMs / 1000;
  458.         m_lastTime.tv_usec += (uDelayInMs * 1000) * 1000;
  459.         
  460.         m_callbackHandle = m_pScheduler->AbsoluteEnter(this, m_lastTime);
  461.     }
  462. }
  463. void HXFeedbackBufferControl::StartCallback()
  464. {
  465.     if (m_pScheduler)
  466.     {
  467.         m_lastTime = m_pScheduler->GetCurrentSchedulerTime();
  468.         
  469.         ScheduleCallback();
  470.     }
  471. }
  472. void HXFeedbackBufferControl::StopCallback()
  473. {
  474.     if (m_pScheduler && m_callbackHandle)
  475.     {
  476.         m_pScheduler->Remove(m_callbackHandle);
  477.         m_callbackHandle = 0;
  478.     }
  479. }
  480. HX_RESULT HXFeedbackBufferControl::GetBwInfo(REF(UINT32) ulClipBw,
  481.                                              REF(UINT16) nControlStream, 
  482.                                              REF(UINT32) ulControlBw)
  483. {
  484.     HX_RESULT res = HXR_OK;
  485.     if (!m_pSource)
  486.     {
  487.         res = HXR_FAILED;
  488.     }
  489.     else if (m_pSource->GetStreamCount() == 0)
  490.     {
  491.         res = HXR_NO_DATA;
  492.     }
  493.     else
  494.     {
  495.         ulClipBw = 0;
  496.         nControlStream = 0;
  497.         ulControlBw = 0;
  498.         
  499.         UINT32 ulHighestBw = 0;
  500.         UINT16 nHighestBwStream = 0;
  501.         BOOL bFoundAudio = FALSE;
  502.         UINT32 ulLowAudioBw = 0;
  503.         UINT16 nLowestBwAudioStream = 0;
  504.         for (UINT16 i = 0; (HXR_OK == res) && (i < m_pSource->GetStreamCount()); i++)
  505.         {
  506.             UINT32 ulStreamBw = 0;
  507.             if (HXR_OK == GetStreamBw(i, ulStreamBw))
  508.             {
  509.                 if (ulStreamBw > ulHighestBw)
  510.                 {
  511.                     ulHighestBw = ulStreamBw;
  512.                     nHighestBwStream = i;
  513.                 }
  514.                 if (IsAudioStream(i) &&
  515.                     (!bFoundAudio || (ulStreamBw < ulLowAudioBw)))
  516.                 {
  517.                     bFoundAudio = TRUE;
  518.                     ulLowAudioBw = ulStreamBw;
  519.                     nLowestBwAudioStream = i;
  520.                 }
  521.                 ulClipBw += ulStreamBw;
  522.             }
  523.         }
  524.         if (bFoundAudio)
  525.         {
  526.             nControlStream = nLowestBwAudioStream;
  527.             ulControlBw = ulLowAudioBw;
  528.         }
  529.         else
  530.         {
  531.             nControlStream = nHighestBwStream;
  532.             ulControlBw = ulHighestBw;
  533.         }
  534.     }
  535.     return res;
  536. }
  537. HX_RESULT 
  538. HXFeedbackBufferControl::GetStreamBw(UINT16 uStreamNumber, 
  539.                                      REF(UINT32) ulBandwidth)
  540. {
  541.     HX_RESULT res = HXR_FAILED;
  542.     if (m_pSource)
  543.     {
  544.         IUnknown* pUnk = NULL;
  545.         res = m_pSource->GetStream(uStreamNumber, pUnk);
  546.         
  547.         if (HXR_OK == res)
  548.         {
  549.             IHXASMProps* pProps = NULL;
  550.             
  551.             res = pUnk->QueryInterface(IID_IHXASMProps, (void**)&pProps);
  552.             if (HXR_OK == res)
  553.             {
  554.                 res = pProps->GetBandwidth(ulBandwidth);
  555.                 
  556.                 pProps->Release();
  557.             }
  558.             pUnk->Release();
  559.         }
  560.     }
  561.     return res;
  562. }
  563. BOOL HXFeedbackBufferControl::IsAudioStream(UINT16 uStreamNumber)
  564. {
  565.     BOOL bRet = FALSE;
  566.     if (m_pSource)
  567.     {
  568.         IUnknown* pUnk = NULL;
  569.         IHXStream* pStream = NULL;
  570.         IHXValues* pHeader = NULL;
  571.         IHXBuffer* pMimetype = NULL;
  572.         if ((HXR_OK == m_pSource->GetStream(uStreamNumber, pUnk)) &&
  573.             (HXR_OK == pUnk->QueryInterface(IID_IHXStream, (void**)&pStream))&&
  574.             (NULL != (pHeader = pStream->GetHeader())) &&
  575.             (HXR_OK == pHeader->GetPropertyCString("MimeType", pMimetype)) &&
  576.             (!strncasecmp("audio", (char*)pMimetype->GetBuffer(), 5)))
  577.         {
  578.             bRet = TRUE;
  579.         }
  580.         HX_RELEASE(pMimetype);
  581.         HX_RELEASE(pHeader);
  582.         HX_RELEASE(pStream);
  583.         HX_RELEASE(pUnk);
  584.     }
  585.     return bRet;
  586. }
  587. void HXFeedbackBufferControl::GetControlData(REF(UINT32) ulTotalBits,
  588.                                              REF(UINT32) ulControlBits)
  589. {
  590.     ulTotalBits = 0;
  591.     ulControlBits = 0;
  592.     
  593.     for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
  594.     {
  595.         UINT32 ulBytes;
  596.         
  597.         HX_RESULT res = HXR_FAILED;
  598.         INT64 llLowTS;
  599.         INT64 llHighTS;
  600.         BOOL bDone;
  601.         res = m_pBufferStats->GetTotalBuffering(i, 
  602.                                                 llLowTS, llHighTS,
  603.                                                 ulBytes,
  604.                                                 bDone);
  605.         if (HXR_OK == res)
  606.         {
  607.             ulTotalBits += 8 * ulBytes;
  608.             
  609.             if (i == m_nControlStream)
  610.             {
  611.                 ulControlBits = 8 * ulBytes;
  612.             }
  613.         }
  614.     }
  615. }
  616. HX_RESULT HXFeedbackBufferControl::Control(UINT32 ulControlBits, 
  617.                                            REF(UINT32) ulNewBandwidth)
  618. {
  619.     UINT32 ulSetPoint = m_control.SetPoint();
  620.     INT32 error = (INT32)ulSetPoint - (INT32)ulControlBits;
  621.     
  622.     double errorFactor = error;
  623.     ulNewBandwidth = m_control.Control(ulControlBits);
  624.     ulNewBandwidth = ControlToTotal(ulNewBandwidth);
  625.     if (ulSetPoint)
  626.     {
  627.         errorFactor = (double)error / (double)ulSetPoint;
  628.     }
  629.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, 
  630.               (s, "FBBC::CTL %lu %d %lu %lu %2.4f",
  631.                HX_GET_TICKCOUNT(),
  632.                error, 
  633.                ulNewBandwidth, 
  634.                ulControlBits,
  635.                errorFactor));
  636.     
  637.     return HXR_OK;
  638. }
  639. void HXFeedbackBufferControl::SetBandwidth(UINT32 ulBandwidth)
  640. {
  641.     DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL, 
  642.               (s, "FBBC::SB %lu %lu ", 
  643.                HX_GET_TICKCOUNT(), ulBandwidth));
  644.     if (m_pThin)
  645.     {
  646.         m_pThin->SetDeliveryBandwidth(ulBandwidth, 0);
  647.     }
  648. }
  649. HX_RESULT HXFeedbackBufferControl::ReadPrefSettings()
  650. {
  651.     HX_RESULT res = HXR_FAILED;
  652.     
  653.     UINT32 ulMin = 1000;
  654.     UINT32 ulMax = 0;
  655.     ReadPrefINT32(m_pPrefs, "MinDelBandwidth", ulMin);
  656.     /* Get initial bandwidth guess from Prefs */
  657.     if (HXR_OK == ReadPrefINT32(m_pPrefs, "Bandwidth", ulMax))
  658.     {
  659.         UINT32 ulSustainFactor = 0;
  660.         /* See if we have a sustainable bandwidth factor */
  661.         if (HXR_OK == ReadPrefINT32(m_pPrefs, "SustainableBwFactor", 
  662.                                     ulSustainFactor))
  663.         {
  664.             /* clamp value to 0 <= ulTemp <= 100 range */
  665.             if (ulSustainFactor > 100)
  666.             {
  667.                 ulSustainFactor = 100;
  668.             }
  669.             
  670.             /* Apply factor */
  671.             ulMax = (((ulMax / 100) * ulSustainFactor) + 
  672.                      (((ulMax % 100) * ulSustainFactor) / 100));
  673.         }
  674.         if (ulMax > 0)
  675.         {
  676.             if (ulMin > ulMax)
  677.             {
  678.                 // Make the minimum bandwidh 1% of the max
  679.                 // rounded up to the next bit/second
  680.                 ulMin = (ulMax + 99) / 100;
  681.             }
  682.             
  683.             m_control.SetLimits(ulMin, ulMax);
  684.             
  685.             res = HXR_OK;
  686.         }
  687.     }
  688.     return res;
  689. }
  690. void HXFeedbackBufferControl::SetTransportByteLimits(UINT32 ulClipBw)
  691. {
  692.     UINT32 ulTotalByteLimit = 0;
  693.     IHXTransportBufferLimit* pBufLimit = NULL;
  694.     ReadPrefINT32(m_pPrefs, "TransportByteLimit", ulTotalByteLimit);
  695.     if (m_pSource && 
  696.         (HXR_OK == m_pSource->QueryInterface(IID_IHXTransportBufferLimit,
  697.                                              (void**)&pBufLimit)))
  698.     {
  699.         // Divide the byte limit amoung the streams
  700.         for (UINT16 i = 0; i < m_pSource->GetStreamCount(); i++)
  701.         {
  702.             UINT32 ulStreamBw = 0;
  703.             if (HXR_OK == GetStreamBw(i, ulStreamBw))
  704.             {
  705.                 // Byte limit for this stream is
  706.                 // (ulTotalByteLimit * ulStreamBw) / ulClipBw
  707.                 UINT32 ulByteLimit = MulDiv(ulTotalByteLimit,
  708.                                             ulStreamBw, ulClipBw);
  709.                 
  710.                 if ((ulByteLimit == 0) &&
  711.                     (ulTotalByteLimit != 0))
  712.                 {
  713.                     // Make sure all streams have a byte limit
  714.                     // if ulTotalByteLimit is non-zero. This is done
  715.                     // because a byte limit of 0 means unlimited
  716.                     // buffering is allowed
  717.                     ulByteLimit = 1;
  718.                 }
  719.                 pBufLimit->SetByteLimit(i, ulByteLimit);
  720.             }
  721.         }
  722.     }
  723.     HX_RELEASE(pBufLimit);
  724. }
  725. HX_RESULT HXFeedbackBufferControl::InitTesting(IUnknown* pContext)
  726. {
  727.     HX_RESULT res = HXR_OK;
  728.     IHXRequest* pRequest = NULL;
  729.     const char* pURL = 0;
  730.     if (HXR_OK == pContext->QueryInterface(IID_IHXRequest, 
  731.                                            (void**)&pRequest) &&
  732.         HXR_OK == pRequest->GetURL(pURL))
  733.     {
  734.         CHXURL url(pURL, pContext);
  735.         
  736.         DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  737.                   (s, "FBBC : url %s", pURL));
  738.         
  739.         IHXValues* pOptions = url.GetOptions();
  740.         ULONG32 ulTmp;
  741.         
  742.         if (pOptions)
  743.         {
  744.             if (HXR_OK == pOptions->GetPropertyULONG32("FBBC-total_control",
  745.                                                        ulTmp))
  746.             {
  747.                 DEBUG_OUT(m_pErrMsg, DOL_BUFFER_CONTROL,
  748.                           (s, "FBBC : total control %lu", ulTmp));
  749.                 m_bControlTotal = (ulTmp > 0) ? TRUE : FALSE;
  750.             }
  751.         }
  752.         
  753.         HX_RELEASE(pOptions);
  754.         HX_RELEASE(pRequest);
  755.     }
  756.     return res;
  757. }
  758. BOOL HXFeedbackBufferControl::IsBuffering()
  759. {
  760.     BOOL bRet = FALSE;
  761.     IHXBuffer* pStatusDesc = NULL;
  762.     UINT16 unStatusCode    = 0;
  763.     UINT16 unPercentDone   = 0;
  764.     if (m_pStatus &&
  765.         (HXR_OK == m_pStatus->GetStatus(unStatusCode, 
  766.                                         pStatusDesc, unPercentDone)) &&
  767.         (unStatusCode == HX_STATUS_BUFFERING))
  768.     {
  769.         bRet = TRUE;
  770.     }
  771.     HX_RELEASE(pStatusDesc);
  772.     return bRet;
  773. }
  774. UINT32 HXFeedbackBufferControl::ClampBandwidth(UINT32 ulBandwidth) const
  775. {
  776.     UINT32 ulRet = ulBandwidth;
  777.     if (ulRet < m_control.Min())
  778.     {
  779.         ulRet = m_control.Min();
  780.     }
  781.     else if (ulRet > m_control.Max())
  782.     {
  783.         ulRet = m_control.Max();
  784.     }
  785.     return ulRet;
  786. }
  787. UINT32 HXFeedbackBufferControl::ControlToTotal(UINT32 ulValue)
  788. {
  789.     return MulDiv(ulValue, m_ulClipBw, m_ulControlBw);
  790. }
  791. UINT32 HXFeedbackBufferControl::TotalToControl(UINT32 ulValue)
  792. {
  793.     return MulDiv(ulValue, m_ulControlBw, m_ulClipBw);
  794. }
  795. UINT32 HXFeedbackBufferControl::MulDiv(UINT32 ulValue, 
  796.                                        UINT32 ulMult, UINT32 ulDiv)
  797. {
  798.     return (((ulValue / ulDiv) * ulMult) +
  799.             ((ulValue % ulDiv) * ulMult) / ulDiv);
  800. }