fbbufctl.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:26k
源码类别:

Symbian

开发平台:

Visual C++

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