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

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 "hxbufstate.h"
  36. #include "hxassert.h"
  37. class HXBufferedPktInfo
  38. {
  39. public:
  40.     HXBufferedPktInfo(INT64 llTimestamp, UINT32 ulSize);
  41.     INT64 Timestamp() const { return m_llTimestamp;}
  42.     UINT32 Size() const { return m_ulSize;}
  43. private:
  44.     INT64 m_llTimestamp;
  45.     UINT32 m_ulSize;
  46. };
  47. inline
  48. HXBufferedPktInfo::HXBufferedPktInfo(INT64 llTimestamp, 
  49.      UINT32 ulSize) :
  50.     m_llTimestamp(llTimestamp),
  51.     m_ulSize(ulSize)
  52. {}
  53. HXBufferingState::HXBufferingState() :
  54.     m_ulPreroll(0)
  55.     , m_ulPredata(0)
  56.     , m_ulMinimumPrerollInMs(0)
  57.     , m_ulMinimumPreroll(0)
  58.     , m_ulMinimumBufferingInMs(0)
  59.     , m_ulMinimumBuffering(0)
  60.     , m_ulRemainingToBufferInMs(0)
  61.     , m_ulRemainingToBuffer(0)
  62.     , m_ulCurrentBufferingInMs(0)
  63.     , m_ulCurrentBuffering(0)
  64.     , m_bIsFirstPacket(TRUE)
  65.     , m_preDataAtStart(FALSE)
  66.     , m_prerollAtStart(FALSE)
  67.     , m_preDataAfterSeek(FALSE)
  68.     , m_prerollAfterSeek(FALSE)
  69.     , m_llLowestTimeStamp(0)
  70.     , m_llHighestTimeStamp(0)
  71.     , m_llLowestTimestampAtTransport(0)
  72.     , m_llHighestTimestampAtTransport(0)
  73.     , m_ulNumBytesAtTransport(0)
  74.     , m_bDoneAtTransport(FALSE)
  75.     , m_ulTSRollOver(0)
  76.     , m_ulLastPacketTimeStamp(0)
  77.     , m_ulAvgBandwidth(0)
  78.     , m_pASMProps(NULL)
  79.     , m_llCurrentPlaybackTime(0)
  80.     , m_ulBufferedData(0)
  81.     , m_ulLastTimeSync(0)
  82.     , m_llFirstLivePacketTimestamp(0)
  83.     , m_ulTimeSyncRollOver(0)
  84. {}
  85. HXBufferingState::~HXBufferingState()
  86. {
  87.     HX_RELEASE(m_pASMProps);
  88.     ClearPktInfo();
  89. }
  90. void HXBufferingState::OnStreamHeader(UINT32 ulPreroll,
  91.       UINT32 ulPredata,
  92.       BOOL preDataAtStart,
  93.       BOOL preDataAfterSeek,
  94.       BOOL prerollAtStart,
  95.       BOOL prerollAfterSeek,
  96.       ULONG32 ulAvgBitRate)
  97. {
  98.     m_ulPreroll = ulPreroll;
  99.     m_ulPredata = ulPredata;
  100.     m_preDataAtStart = preDataAtStart;
  101.     m_preDataAfterSeek = preDataAfterSeek;
  102.     m_prerollAtStart = prerollAtStart;
  103.     m_prerollAfterSeek = prerollAfterSeek;
  104.     m_ulAvgBandwidth = ulAvgBitRate;
  105. }
  106. void HXBufferingState::OnStream(IUnknown* pStream)
  107. {
  108.     HX_RELEASE(m_pASMProps);
  109.     if (pStream)
  110.     {
  111. pStream->QueryInterface(IID_IHXASMProps, (void**) &m_pASMProps);
  112.     }
  113. }
  114. void HXBufferingState::Init(ULONG32 ulPerfectPlayTime)
  115. {
  116.     SetMinPrerollInMs(m_ulPreroll, m_ulPreroll + ulPerfectPlayTime);
  117.     SetMinPreroll();
  118. }
  119. void HXBufferingState::SetMinimumPreroll(UINT32 ulSourcePreroll, 
  120.  UINT32 ulInitialAudioPreroll,
  121.  UINT32 ulPerfectPlayTime,
  122.  BOOL   bIsRebuffering)
  123. {
  124.     UINT32 ulMinimumPreroll = m_ulPreroll;
  125.     
  126.     ulMinimumPreroll += ulInitialAudioPreroll;
  127.     
  128.     if (ulMinimumPreroll < ulSourcePreroll)
  129.     {
  130. ulMinimumPreroll = ulSourcePreroll;
  131.     }
  132.     
  133.     SetMinPrerollInMs(ulMinimumPreroll, 
  134.       ulMinimumPreroll + ulPerfectPlayTime);
  135.     m_ulCurrentBufferingInMs = 0;
  136.     /* If we have received at lest one packet for this stream,
  137.      * mark the lowest timestamp to be the
  138.      * last packet timstamp to reset buffering calculations
  139.      */
  140.     if (bIsRebuffering && !m_bIsFirstPacket)
  141.     {
  142. m_bIsFirstPacket = TRUE;
  143. m_llLowestTimeStamp = 
  144.     CAST_TO_INT64 (m_ulTSRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 (m_ulLastPacketTimeStamp);
  145.     }
  146.     
  147.     UpdateMinPredata();
  148. }
  149. void HXBufferingState::Stop()
  150. {
  151.     m_ulRemainingToBufferInMs = 0;
  152.     m_ulRemainingToBuffer = 0;
  153. }
  154. void HXBufferingState::Reset(BOOL bIsSeeking, UINT32 ulSeekTime)
  155. {
  156.     m_ulRemainingToBufferInMs = m_ulMinimumBufferingInMs;
  157.     m_ulRemainingToBuffer = m_ulMinimumBuffering;
  158.     m_ulCurrentBufferingInMs = 0;
  159.     m_ulCurrentBuffering = 0;
  160.     m_ulTSRollOver = 0;
  161.     m_ulLastPacketTimeStamp = 0;
  162.     m_bIsFirstPacket = TRUE;
  163.     ClearPktInfo();
  164.     if (bIsSeeking)
  165.     {
  166. m_llLowestTimeStamp = CAST_TO_INT64 ulSeekTime;
  167. m_llHighestTimeStamp = CAST_TO_INT64 ulSeekTime;
  168.     }
  169. }
  170. void HXBufferingState::GetRemainToBuffer(REF(UINT32) ulRemainToBufferInMs,
  171.  REF(UINT32) ulRemainToBuffer)
  172. {
  173.     ulRemainToBufferInMs = m_ulRemainingToBufferInMs;
  174.     ulRemainToBuffer = m_ulRemainingToBuffer;
  175. }
  176. UINT16 HXBufferingState::GetPercentDone(BOOL bIsSeekPerformed)
  177. {
  178.     UINT16  uTotalPercentDone = 100;
  179.     UINT16  uPreDataPercentDone = 100;
  180.     UINT16  uPrerollPercentDone = 100;
  181.     BOOL bHasPreroll;
  182.     BOOL bHasPredata;
  183.     BOOL bNeedsData = FALSE;
  184.     if (!bIsSeekPerformed)
  185.     {
  186. // start/rebuffer mode
  187. bHasPreroll = m_prerollAtStart;
  188. bHasPredata = m_preDataAtStart;
  189.     }
  190.     else
  191.     {
  192. // seek mode
  193. bHasPreroll = m_prerollAfterSeek;
  194. bHasPredata = m_preDataAfterSeek;
  195.     }
  196.     // satisfy the preroll (by default + pre-set)
  197.     if (!bHasPredata || bHasPreroll)
  198.     {
  199. // percent done on preroll
  200. if (m_ulMinimumBufferingInMs)
  201. {
  202.     uPrerollPercentDone =
  203. ((m_ulMinimumBufferingInMs-m_ulRemainingToBufferInMs ) * 100) /
  204. m_ulMinimumBufferingInMs;
  205. }
  206. uTotalPercentDone = uPrerollPercentDone;
  207. bNeedsData = (m_ulRemainingToBufferInMs > 0);
  208.     }
  209.     // satisfy the predata
  210.     if (bHasPredata)
  211.     {
  212. // percent done on predata
  213. if (m_ulMinimumBuffering)
  214. {
  215.     uPreDataPercentDone = 
  216. ((m_ulMinimumBuffering - m_ulRemainingToBuffer ) * 100) /
  217. m_ulMinimumBuffering;
  218. }
  219. uTotalPercentDone = uPreDataPercentDone;
  220. bNeedsData = (m_ulRemainingToBuffer > 0);
  221.     }
  222.     if (bHasPredata && bHasPreroll)
  223.     {
  224. uTotalPercentDone = (uPrerollPercentDone + uPreDataPercentDone) / 2;
  225.     }
  226.     else if ((bIsSeekPerformed) &&
  227.      (uTotalPercentDone == 100) &&
  228.      (bNeedsData))
  229.     {
  230. uTotalPercentDone = 99;
  231.     }
  232.     return uTotalPercentDone;
  233. }
  234. void HXBufferingState::UpdatePreroll(ULONG32 ulPreroll)
  235. {
  236.     UINT32 ulExtraPrerollInMs   = m_ulMinimumPrerollInMs - m_ulPreroll;
  237.     UINT32 ulExtraBufferingInMs = m_ulMinimumBufferingInMs - m_ulPreroll;
  238.     
  239.     SetPreroll(ulPreroll);
  240.     SetMinPrerollInMs(ulPreroll + ulExtraPrerollInMs,
  241.       ulPreroll + ulExtraBufferingInMs);
  242.     SetMinPreroll();
  243.     // Notice that we don't call ClearCurrentBufferingInMs()
  244.     // or ClearCurrentBuffering(). This allows us to count
  245.     // any data we have already received as part of the
  246.     // new preroll
  247.     CalcRemainingToBufferInMs();
  248.     CalcRemainingToBuffer();
  249. }
  250. INT64 HXBufferingState::CreateINT64Timestamp(UINT32 ulTime)
  251. {
  252.     return CAST_TO_INT64 (m_ulTSRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 ulTime;
  253. }
  254. INT64 HXBufferingState::CreateINT64Timesync(UINT32 ulTime)
  255. {
  256.     return CAST_TO_INT64 (m_ulTimeSyncRollOver) * CAST_TO_INT64 MAX_UINT32 + CAST_TO_INT64 ulTime;
  257. }
  258. void HXBufferingState::OnPacket(UINT32 ulTimestamp, UINT32 ulPacketSize,
  259. UINT32 ulElapsedTime,
  260. BOOL bIsLive, BOOL bIsBufferedPlayMode)
  261. {
  262.     //  0xFA .. 0xFF [roll over] (0x01)
  263.     if (m_ulLastPacketTimeStamp > ulTimestamp &&
  264. ((m_ulLastPacketTimeStamp - ulTimestamp) > MAX_TIMESTAMP_GAP))
  265.     {
  266. m_ulTSRollOver++;
  267.     }
  268.     
  269.     INT64 llActualTimeStamp = CreateINT64Timestamp(ulTimestamp);
  270.     m_ulLastPacketTimeStamp = ulTimestamp;
  271.     if (m_bIsFirstPacket)
  272.     {
  273. /* Only if we are live,  store the first packet timestemp
  274.  * as the lowest timestamp. In any other case, we consider
  275.  * the lowest ts to be 0 OR the Seek time.
  276.  * This is to fix the post-seek buffering where we should not
  277.  * account any packets < seek ts towards buffering completion.
  278.  */
  279. if (bIsLive)
  280. {
  281.     m_llLowestTimeStamp = CAST_TO_INT64 ulTimestamp;
  282.             m_llFirstLivePacketTimestamp = m_llLowestTimeStamp;
  283.         }
  284. m_llHighestTimeStamp = CAST_TO_INT64 ulTimestamp;
  285. m_bIsFirstPacket = FALSE;
  286.     }
  287.     // Add this packet to our packet info statistics
  288.     AddPktInfo(llActualTimeStamp, ulPacketSize);
  289.     // data based preroll
  290.     if (DataBasedPreroll())
  291.     {
  292. m_ulCurrentBuffering += ulPacketSize;
  293.     
  294. if (bIsBufferedPlayMode)
  295. {
  296.     /* 
  297.      * We wait to have at least 1 second worth of data
  298.      * before doing any calculations. This may need some
  299.      * tweaking.
  300.      */
  301.     if ((m_ulRemainingToBuffer != 0) &&
  302. (m_ulCurrentBuffering >= m_ulAvgBandwidth / 8))
  303.     {
  304. /* 
  305.  * Highly unlikely, but may happen from a server on the 
  306.  * local machine.
  307.  */
  308. if (ulElapsedTime == 0)
  309. {
  310.     if (m_ulCurrentBuffering >= m_ulMinimumPreroll)
  311.     {
  312. m_ulRemainingToBuffer = 0;
  313.     }
  314. }
  315. else
  316. {
  317.     UINT32 ulDenom = ulElapsedTime * m_ulAvgBandwidth / 8000;
  318.     
  319.     /* Sanity check - may be 0 only when bandwidth
  320.      * is really low 
  321.      */
  322.     ulDenom = ulDenom > 0 ? ulDenom : 1;
  323.     
  324.     CalcRemainingToBuffer(ulDenom);
  325. }
  326.     }
  327. }
  328. else
  329. {
  330.     /* bIsBufferedPlayMode == FALSE */
  331.     if (m_ulRemainingToBuffer)
  332.     {
  333. CalcRemainingToBuffer();
  334.     }
  335. }
  336.     }
  337.     if (llActualTimeStamp >= m_llHighestTimeStamp)
  338.     {
  339. m_llHighestTimeStamp = llActualTimeStamp;
  340.     } 
  341. }
  342. void HXBufferingState::UpdateBufferingInMs(INT64 llRefLowTimestamp,
  343.    INT64 llHighTimestamp, 
  344.    BOOL bIsBufferedPlayMode,
  345.    BOOL bIsTimestampDelivery,
  346.    UINT32 ulElapsedTime)
  347. {
  348.     UpdateCurrentBufferingInMs(llRefLowTimestamp, llHighTimestamp);
  349.     if (bIsBufferedPlayMode)
  350.     {
  351. /* We handle time stamp delivered streams differently
  352.  * in case of BUffered/PerfectPlay. This is because
  353.  * server sends timestamp delivered stream based
  354.  * on the timestamps on the packet and pretty
  355.  * much streams in realtime. 
  356.  * So even if we are on LAN and streaming a RealText
  357.  * file, we will get packets in realtime even though
  358.  * we have enough bandwidth available
  359.  * 
  360.  * For timestamp delivered streams, we just fulfill 
  361.  * preroll.
  362.  */
  363. if (bIsTimestampDelivery &&
  364.     m_ulCurrentBufferingInMs > m_ulMinimumPrerollInMs)
  365. {
  366.     m_ulRemainingToBufferInMs = 0;
  367. }
  368. else if ((m_ulRemainingToBufferInMs != 0) &&
  369.  (m_ulCurrentBufferingInMs >= 1000))
  370. {
  371.     /* 
  372.      * Highly unlikely, but may happen from a 
  373.      * server on the local machine.
  374.      */
  375.     if (ulElapsedTime == 0)
  376.     {
  377. if (m_ulCurrentBufferingInMs >= m_ulMinimumPrerollInMs)
  378. {
  379.     m_ulRemainingToBufferInMs = 0;
  380. }
  381.     }
  382.     else
  383.     {
  384. CalcRemainingToBufferInMs(ulElapsedTime);
  385.     }
  386. }
  387.     }
  388.     else
  389.     {
  390. /* bIsBufferedPlayMode == FALSE */
  391. if (m_ulRemainingToBufferInMs)
  392. {
  393.     CalcRemainingToBufferInMs();
  394. }
  395.     }
  396. }
  397. void HXBufferingState::UpdateTransportStats(INT64 llLowTSAtTransport,
  398.     INT64 llHighTSAtTransport,
  399.     ULONG32 ulBytesAtTransport,
  400.     BOOL bDoneAtTransport)
  401. {
  402.     m_llLowestTimestampAtTransport = llLowTSAtTransport; 
  403.     m_llHighestTimestampAtTransport = llHighTSAtTransport; 
  404.     m_ulNumBytesAtTransport = ulBytesAtTransport;
  405.     m_bDoneAtTransport = bDoneAtTransport;
  406. }
  407. HX_RESULT HXBufferingState::GetBufferingStats(REF(INT64) llLowTimestamp, 
  408.       REF(INT64) llHighTimestamp,
  409.       REF(UINT32) ulBytesBuffered,
  410.       BOOL bUseTransportStats)
  411. {
  412.     HX_RESULT res = HXR_NO_DATA;
  413.     if (!m_bIsFirstPacket)
  414.     {
  415. if (!m_pktInfo.IsEmpty())
  416. {
  417.     HXBufferedPktInfo* pPktInfo = 
  418. (HXBufferedPktInfo*)m_pktInfo.GetHead();
  419.     llLowTimestamp = pPktInfo->Timestamp();
  420. }
  421. else
  422. {
  423.     llLowTimestamp = m_llHighestTimeStamp;
  424. }
  425. llHighTimestamp = m_llHighestTimeStamp;
  426. ulBytesBuffered = GetBufferedData();
  427. if (bUseTransportStats)
  428. {
  429.     if (m_llHighestTimestampAtTransport > llHighTimestamp)
  430.     {
  431. llHighTimestamp = m_llHighestTimestampAtTransport;
  432.     }
  433.     ulBytesBuffered += m_ulNumBytesAtTransport;
  434. }
  435. res = HXR_OK;
  436.     }
  437.     return res;
  438. }
  439. void HXBufferingState::GetExcessBufferInfo(INT64 llTheLowestTS,
  440.    INT64 llTheHighestTS,
  441.    BOOL bIsSeekPerformed,
  442.    REF(UINT32) ulRemainToBufferInMs,
  443.    REF(UINT32) ulRemainToBuffer,
  444.    REF(UINT32) ulExcessBufferInMs,
  445.    REF(UINT32) ulExcessBuffer,
  446.    REF(UINT32) ulExcessForThisStreamInMs,
  447.    REF(UINT32) ulExcessForThisStream)
  448. {
  449.     UINT32 ulCurBufInMs     = 0;
  450.     UINT32 ulRemainForThisStreamInMs = 0;
  451.     UINT32 ulRemainForThisStream     = 0;
  452.     
  453.     ulExcessForThisStreamInMs = 0;
  454.     ulExcessForThisStream     = 0;
  455.     
  456.     if (m_ulNumBytesAtTransport > 0)
  457.     {
  458. HX_ASSERT((llTheHighestTS - m_llLowestTimestampAtTransport) < MAX_TIMESTAMP_GAP);
  459. ulCurBufInMs = INT64_TO_UINT32(llTheHighestTS - 
  460.        m_llLowestTimestampAtTransport);
  461.     }
  462.     else
  463.     {
  464. HX_ASSERT((llTheHighestTS - llTheLowestTS) < MAX_TIMESTAMP_GAP);
  465. ulCurBufInMs = INT64_TO_UINT32(llTheHighestTS - llTheLowestTS);
  466.     }
  467.     if (ulCurBufInMs <= m_ulMinimumBufferingInMs)
  468.     {
  469. ulRemainForThisStreamInMs = m_ulMinimumBufferingInMs - ulCurBufInMs;
  470.     }
  471.     else
  472.     {
  473. ulExcessForThisStreamInMs = ulCurBufInMs - m_ulMinimumBufferingInMs;
  474.     }
  475.     if (m_ulNumBytesAtTransport <= m_ulMinimumBuffering)
  476.     {
  477. ulRemainForThisStream = 
  478.     m_ulMinimumBuffering - m_ulNumBytesAtTransport;
  479.     }
  480.     else
  481.     {
  482. ulExcessForThisStream = m_ulNumBytesAtTransport - m_ulMinimumBuffering;
  483.     }
  484.     
  485.     BOOL bHasPreroll = HasPreroll(bIsSeekPerformed);
  486.     BOOL bHasPredata = HasPredata(bIsSeekPerformed);
  487.     // satisfy the preroll (by default + pre-set)
  488.     if (!bHasPredata || bHasPreroll)
  489.     {
  490. if (ulRemainToBufferInMs < ulRemainForThisStreamInMs)
  491. {
  492.     ulRemainToBufferInMs = ulRemainForThisStreamInMs;
  493. }
  494. if (ulExcessBufferInMs < ulExcessForThisStreamInMs)
  495. {
  496.     ulExcessBufferInMs = ulExcessForThisStreamInMs;
  497. }
  498.     }
  499.     // satisfy the predata
  500.     if (bHasPredata)
  501.     {
  502. ulRemainToBuffer += ulRemainForThisStream;
  503. ulExcessBuffer   += ulExcessForThisStream;
  504.     }
  505. }
  506. void HXBufferingState::OnTimeSync(UINT32 ulCurrentTime)
  507. {
  508.     //  0xFA .. 0xFF [roll over] (0x01)
  509.     if (m_ulLastTimeSync > ulCurrentTime &&
  510.        ((m_ulLastTimeSync - ulCurrentTime) > MAX_TIMESTAMP_GAP))
  511.     {
  512.        m_ulTimeSyncRollOver++;
  513.     }
  514.     m_ulLastTimeSync = ulCurrentTime;
  515.     m_llCurrentPlaybackTime = CreateINT64Timesync(ulCurrentTime);
  516. }
  517. void HXBufferingState::SetMinPrerollInMs(ULONG32 ulMinPrerollInMs, 
  518.  ULONG32 ulMinBufferingInMs)
  519. {
  520.     m_ulMinimumPrerollInMs    = ulMinPrerollInMs;
  521.     m_ulMinimumBufferingInMs  = ulMinBufferingInMs;
  522.     m_ulRemainingToBufferInMs = m_ulMinimumBufferingInMs;
  523. }
  524. void HXBufferingState::SetMinPreroll()
  525. {
  526.     SetMinPreroll(MsToBytes(m_ulMinimumPrerollInMs,
  527.     m_ulAvgBandwidth),
  528.   m_ulAvgBandwidth);
  529. }
  530. void HXBufferingState::SetMinPreroll(UINT32 ulMinimumPredata,
  531.      UINT32 ulBandwidth)
  532. {
  533.     HX_ASSERT(m_ulMinimumPrerollInMs >= m_ulPreroll);
  534.     UINT32 ulExtraBufferingInMs = m_ulMinimumPrerollInMs - m_ulPreroll;
  535.     /* Get current bandiwidth from asm */
  536.     m_ulMinimumPreroll = (ulMinimumPredata + 
  537.    MsToBytes(ulExtraBufferingInMs, 
  538.      ulBandwidth));
  539.     // There is no buffered or perfect play with MIN_HEAP on.
  540. #if defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
  541.     m_ulMinimumBuffering  = m_ulMinimumPreroll;
  542. #else
  543.     ulExtraBufferingInMs = m_ulMinimumBufferingInMs - m_ulPreroll;
  544.     m_ulMinimumBuffering  = (ulMinimumPredata + 
  545.      MsToBytes(ulExtraBufferingInMs, 
  546.        ulBandwidth));
  547. #endif
  548.     m_ulRemainingToBuffer  = m_ulMinimumBuffering;
  549.     m_ulCurrentBuffering   = 0;
  550. }
  551. void HXBufferingState::UpdateMinPredata()
  552. {
  553.     UINT32     ulMinimumPredata = m_ulPredata;
  554.     UINT32     ulBandwidth      = m_ulAvgBandwidth;
  555.     
  556. #if defined(HELIX_FEATURE_ASM)
  557.     // no ASMProps in AutoConfig
  558.     HX_ASSERT(m_pASMProps);
  559.     
  560.     if (m_pASMProps)
  561.     {
  562. UINT32 ulTmp;
  563. if (HXR_OK == m_pASMProps->GetPreData(ulTmp))
  564. {
  565.     ulMinimumPredata = ulTmp;
  566. }
  567. if (HXR_OK == m_pASMProps->GetBandwidth(ulTmp))
  568. {
  569.     ulBandwidth = ulTmp;
  570. }
  571.     }
  572. #endif /* HELIX_FEATURE_ASM */
  573.     
  574.     SetMinPreroll(ulMinimumPredata, ulBandwidth);
  575. }
  576. void HXBufferingState::UpdateCurrentBufferingInMs(INT64 llLowestTimeStamp, 
  577.   INT64 llHighestTimeStamp)
  578. {
  579.     INT64 llLowTimestamp = m_llLowestTimeStamp;
  580.     
  581.     if (m_bIsFirstPacket)
  582.     {
  583. /* use the reference stream's lowest timestamp for calculation */
  584. llLowTimestamp = llLowestTimeStamp;
  585.     }
  586.     if (llHighestTimeStamp > llLowTimestamp)
  587.     {
  588. // if the stream has been continuesly playing for 49 days
  589. // we will set m_ulCurrentBufferingInMs to MAX_UINT32
  590. if (llHighestTimeStamp - llLowTimestamp > MAX_UINT32)
  591. {
  592.     m_ulCurrentBufferingInMs = MAX_UINT32;
  593. }
  594. else
  595. {
  596.     m_ulCurrentBufferingInMs = 
  597. INT64_TO_UINT32(llHighestTimeStamp - llLowTimestamp);
  598. }
  599.     }
  600. }
  601. ULONG32 HXBufferingState::MsToBytes(ULONG32 ulValueInMs, ULONG32 ulBw) const
  602. {
  603.     return (ulValueInMs * (ulBw / 8)) / 1000;
  604. }
  605. void HXBufferingState::CalcRemainingToBufferInMs()
  606. {
  607.     m_ulRemainingToBufferInMs = CalcRemaining(m_ulMinimumBufferingInMs,
  608.       m_ulCurrentBufferingInMs,
  609.       0,
  610.       0);
  611. }
  612. void HXBufferingState::CalcRemainingToBufferInMs(ULONG32 ulElapsedTime)
  613. {
  614.     m_ulRemainingToBufferInMs = CalcRemaining(m_ulMinimumBufferingInMs,
  615.       m_ulCurrentBufferingInMs,
  616.       m_ulMinimumPrerollInMs,
  617.       ulElapsedTime);
  618. }
  619. void HXBufferingState::CalcRemainingToBuffer()
  620. {
  621.     m_ulRemainingToBuffer = CalcRemaining(m_ulMinimumBuffering,
  622.   m_ulCurrentBuffering,
  623.   0,
  624.   0);
  625. }
  626. void HXBufferingState::CalcRemainingToBuffer(ULONG32 ulDenom)
  627. {
  628.     m_ulRemainingToBuffer = CalcRemaining(m_ulMinimumBuffering,
  629.   m_ulCurrentBuffering,
  630.   m_ulMinimumPreroll,
  631.   ulDenom);
  632. }
  633. UINT32 HXBufferingState::CalcRemaining(UINT32 ulMinimumBuffering,
  634.        UINT32 ulCurrentBuffering,
  635.        UINT32 ulMinimumPreroll,
  636.        UINT32 ulDenom) const
  637. {
  638.     UINT32 ulRemainingToBuffer = 0;
  639.     if (ulMinimumBuffering > ulCurrentBuffering)
  640.     {
  641. ulRemainingToBuffer = ulMinimumBuffering - ulCurrentBuffering;
  642.     }
  643.     if (ulDenom)
  644.     {
  645. UINT32 ulBufferWhilePlaying = ulRemainingToBuffer;
  646. /*
  647.  * Buffers during playback = X*X/Y + X*(X/Y)^2 + X*(X/Y)^3 + ....
  648.  *     = X*X/Y (1 + X/Y + (X/Y)^2 + ....)
  649.  *
  650.  *      = X*X/Y ( 1 / (1 - X/Y))  IFF X/Y < 1 i.e. X < Y
  651.  *
  652.  *       ELSE We have enough data... Satisfy preroll 
  653.  */
  654. /* Add a fudge factor of 10% */
  655. ulDenom = (UINT32) (ulDenom * 1.10);
  656. if (ulCurrentBuffering < ulDenom)
  657. {
  658.     double x = ulCurrentBuffering;
  659.     double y = ulDenom;
  660.     ulBufferWhilePlaying = (UINT32) (((x * x) / y) * (1. / (1. - x / y)));
  661. }
  662. if (ulBufferWhilePlaying < ulRemainingToBuffer)
  663. {
  664.     ulRemainingToBuffer -= ulBufferWhilePlaying;
  665. }
  666. else if (ulCurrentBuffering >= ulMinimumPreroll)
  667. {
  668.     ulRemainingToBuffer = 0;
  669. }
  670.     }
  671.     return ulRemainingToBuffer;
  672. }
  673. void HXBufferingState::SetAvgBWToASMBw()
  674. {
  675.     UINT32 ulBandwidth = 0;
  676.     if (m_pASMProps &&
  677. m_pASMProps->GetBandwidth(ulBandwidth) == HXR_OK)
  678.     {
  679. m_ulAvgBandwidth = ulBandwidth;
  680.     }
  681. }
  682. void HXBufferingState::ClearPktInfo()
  683. {
  684.     m_ulBufferedData = 0;
  685.     while(!m_pktInfo.IsEmpty())
  686.     {
  687. HXBufferedPktInfo* pInfo = (HXBufferedPktInfo*)m_pktInfo.RemoveHead();
  688. delete pInfo;
  689.     }
  690. }
  691. void HXBufferingState::AddPktInfo(INT64 llTimestamp, UINT32 ulPacketSize)
  692. {
  693.     // Subtract off the first live packet timestamp.
  694.     // If not live, then m_llFirstLivePacketTimeStamp is 0.
  695.     llTimestamp -= m_llFirstLivePacketTimestamp;
  696.     // Create the HXBufferedPktInfo class
  697.     HXBufferedPktInfo* pPktInfo = new HXBufferedPktInfo(llTimestamp, 
  698. ulPacketSize);
  699.     if (pPktInfo)
  700.     {
  701. m_pktInfo.AddTail(pPktInfo);
  702. m_ulBufferedData += ulPacketSize;
  703.     }
  704.     // purge the old packet info data
  705.     //  this keeps the list short and prevents the Symbian
  706.     //  allocator from freaking out
  707.     (void)GetBufferedData();
  708. }
  709. UINT32 HXBufferingState::GetBufferedData()
  710. {
  711.     BOOL bDone = m_pktInfo.IsEmpty();
  712.     
  713.     // Remove all packet info that is past due
  714.     // and subtract their sizes from our buffering total
  715.     while(!bDone)
  716.     {
  717. HXBufferedPktInfo* pPktInfo = (HXBufferedPktInfo*)m_pktInfo.GetHead();
  718. if (pPktInfo->Timestamp() <= m_llCurrentPlaybackTime)
  719. {
  720.     m_ulBufferedData -= pPktInfo->Size();
  721.     
  722.     m_pktInfo.RemoveHead();
  723.     delete pPktInfo;
  724.     
  725.     bDone = m_pktInfo.IsEmpty();
  726. }
  727. else
  728. {
  729.     bDone = TRUE;
  730. }
  731.     }
  732.     return m_ulBufferedData;
  733. }