Logo Search packages:      
Sourcecode: helix-player version File versions

hxsm.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxsm.cpp,v 1.17.2.1 2004/07/09 02:05:30 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 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 (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (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.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * 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 ***** */

/*
 *  
 *  ASM Manager for all streams in all Players.
 *
 *  This class will manage the bandwidth requirements
 *  of multiple streams.
 */

#include "hlxclib/stdio.h"      /* printf */
#include "hlxclib/stdlib.h"     /* atoi on Mac */
#include "hxtypes.h"    /* Basic Types */
#include "hxcom.h"      /* IUnknown */
#include "hxslist.h"
#include "hxerror.h"
#include "hxsmbw.h"
#include "hxsm.h"      /* HXSM */
#include "hxsmutil.h"
#include "hxpref.h"
#include "ihxpckts.h"
#include "hxcore.h"
#include "asmrulep.h"
#include "hxbuffer.h"
#include "chxpckts.h"
#include "hxbsrc.h"
#include "hxsrc.h"
#include "errdbg.h"
#include "rtspif.h"
#include "hxurl.h"
#include "hxtick.h"
#include "hxstrutl.h"
#include "hxbufctl.h"

#include "hxheap.h"

#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif

#ifndef MIN
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif

HXSM::HXSM()
    : m_State(HX_NONE)
    , m_lRefCount(0)
    , m_pSubscriptionVariables(0)
    , m_ulOriginalHighestBandwidthAvail(0)
    , m_ulHighestBandwidthAvail(0)
    , m_ulPeakUsedBandwidth(0)
    , m_ulUpShiftRingPos(0)
    , m_ulUpShiftBandwidthAvail(0)
    , m_ulNumSources(0)
    , m_ulMaxAccelBitRate(0xffffffff)
    , m_ulNumReportsSinceUpShift(2)
    , m_ulLastStableBandwidth(0)
    , m_ulUpShiftTestPointScaleFactor(4000)
    , m_ulOfferToRecalc(0)
    , m_ulNextPacketWindow(0)
    , m_lPacketCounter(0)
    , m_ulUpShiftPastResistanceCount(0)
    , m_lLoss(0)
    , m_bInitialHighBwAvail(TRUE)
    , m_bPipeFull(FALSE)
    , m_bUpShiftInfoReady(FALSE)
    , m_bDidOfferUpShiftToRecalc(FALSE)
    , m_bLoadTest(FALSE)
    , m_bDoAccel(TRUE)
    , m_bDoDecel(TRUE)
    , m_bDisableBothAccelDecel(FALSE)
    , m_fAccelerationFactor(4.0)
    , m_bEnableSDB(TRUE)
#ifndef GOLD
    , m_pEM(0)
#endif
{
    m_pASMSourceInfo = new CHXSimpleList;
    m_pASMStreamInfo = new CHXSimpleList;
}

HXSM::~HXSM()
{
#ifndef GOLD
    HX_RELEASE(m_pEM);
#endif
    CHXSimpleList::Iterator     i;
    ASMSourceInfo*                 pASMSourceInfo;
    ASMStreamInfo*                 pASMStreamInfo;

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);
      pASMSourceInfo->Release();
    }

    for (i = m_pASMStreamInfo->Begin(); i != m_pASMStreamInfo->End(); ++i)
    {
      pASMStreamInfo = (ASMStreamInfo*)(*i);
      delete pASMStreamInfo;
    }

    delete m_pASMSourceInfo;
    delete m_pASMStreamInfo;
    HX_RELEASE(m_pSubscriptionVariables);
}

STDMETHODIMP_(UINT32)
HXSM::AddRef(void)
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(UINT32)
HXSM::Release(void)
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
      return m_lRefCount;
    }

    delete this;
    return 0;
}

STDMETHODIMP
HXSM::QueryInterface
(
    REFIID interfaceID,
    void** ppInterfaceObj
)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)this },
            { GET_IIDHANDLE(IID_IHXBandwidthManager), (IHXBandwidthManager*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), interfaceID, ppInterfaceObj);
}

STDMETHODIMP
HXSM::RegisterSource(HXSource* pSource, IUnknown* pUnknown)
{
    IHXSourceBandwidthInfo* pSBI;
    IHXPreferences* pPreferences = NULL;
    ASMSourceInfo* pASMSourceInfo = NULL;
    UINT16 i;

#ifndef GOLD
    HX_RELEASE(m_pEM);
    pUnknown->QueryInterface(IID_IHXErrorMessages, (void **)&m_pEM);
#endif

    DEBUG_OUT(m_pEM, DOL_BWMGR, (s, "Register Source %p %s", pSource, pSource->GetURL()));

    if (HXR_OK == pSource->QueryInterface(IID_IHXSourceBandwidthInfo, 
          (void **)&pSBI))
    {
      pASMSourceInfo = new ASMSourceInfo(pSource, this);
      pASMSourceInfo->AddRef();

      pASMSourceInfo->m_pSBI = pSBI;
      /* Local source is always considered in perfect play mode UNLESS we are
       * in simulated network playback mode (used Preview mode in the Encoder)
       */
      pASMSourceInfo->m_bPerfectPlay = pSource->IsPerfectPlay() && !pSource->IsSimulatedNetworkPlayback();

      m_ulNumSources++;
      m_pASMSourceInfo->AddTail((void *)pASMSourceInfo);
      pSBI->InitBw(pASMSourceInfo);
    }
    else
    {
      return HXR_OK;
    }

    /*
     * This variable tells us the highest amount of bandwidth that we
     * believe is useable.  If we stream thin, then the highest value
     * that the pipe can support would be the aggregate bandwidth of
     * the sources.  Barring any thinning, this would be the bandwidth
     * from prefs (unless we can determine it through fast buffering or
     * another transport feature).  This value is used when starting sources
     * as a initial guess for bandwidth (to set subscriptions).
     */
    if (m_ulHighestBandwidthAvail == 0)
    {
      pUnknown->QueryInterface(IID_IHXPreferences, (void **)&pPreferences);

        UINT32 ulTemp = 0;
      /* Get initial bandwidth guess from Prefs */
        if (HXR_OK == ReadPrefINT32(pPreferences, "Bandwidth", ulTemp))
        {
          m_bInitialHighBwAvail = TRUE;

          /* Translate the bandwidth from prefs into a starting point */
               if (ulTemp == 14400)    m_ulHighestBandwidthAvail = 11000;
          else if (ulTemp == 19200)    m_ulHighestBandwidthAvail = 14400;
          else if (ulTemp == 28800)    m_ulHighestBandwidthAvail = 21600;
          else if (ulTemp == 33600)    m_ulHighestBandwidthAvail = 25000;
          else if (ulTemp == 34400)    m_ulHighestBandwidthAvail = 34400;
          else if (ulTemp == 57600)    m_ulHighestBandwidthAvail = 50000;
          else if (ulTemp == 65536)  m_ulHighestBandwidthAvail = 56360;
          else if (ulTemp == 115200)   m_ulHighestBandwidthAvail = 100000;
          else if (ulTemp >  150000)   m_ulHighestBandwidthAvail = (UINT32)(ulTemp * 0.90);
          else
          {
            m_ulHighestBandwidthAvail = (UINT32)(ulTemp * 0.85);
          }

          /* Translate the bandwidth from prefs into a starting point */
               if (ulTemp == 14400)    m_ulPeakUsedBandwidth = 12240;
          else if (ulTemp == 19200)    m_ulPeakUsedBandwidth = 16320;
          else if (ulTemp == 28800)    m_ulPeakUsedBandwidth = 24480;
          else if (ulTemp == 33600)    m_ulPeakUsedBandwidth = 28560;
          else if (ulTemp == 34400)    m_ulPeakUsedBandwidth = 34400;
          else if (ulTemp == 57600)    m_ulPeakUsedBandwidth = 51840;
          else if (ulTemp == 65536)  m_ulPeakUsedBandwidth = 58980;
          else if (ulTemp == 115200)   m_ulPeakUsedBandwidth = 104000;
          else if (ulTemp >  150000)   m_ulPeakUsedBandwidth = (UINT32)(ulTemp * 0.91);
          else
          {
            m_ulPeakUsedBandwidth = (UINT32)(ulTemp * 0.90);
          }

          /*
           * Figure out the resistance bitrate for upshifting.
           * Modems get 65k.
           * DSL / Low BW LANs get their pref value.
           * High bandwidth devices cap at 600k
           *    (unless the presentation is more)
           */
          if (ulTemp < 65000)
          {
            m_ulResistanceBitRate = 65000;
          }
          else if (ulTemp < 600000)
          {
            m_ulResistanceBitRate = m_ulPeakUsedBandwidth;
          }
          else
          {
            m_ulResistanceBitRate = 600000;
          }

          m_ulOriginalResistanceBitRate = m_ulResistanceBitRate;
      }
      else
      {
          /* Wild Guess */
          m_ulHighestBandwidthAvail = 40000;
          m_ulPeakUsedBandwidth = 40000;
      }



      //           LOAD TEST ONLY OPTIONS
      // Read in the preferences for enabling/disabling Accel and 
      // Decel for load tests.
      //
        ReadPrefBOOL(pPreferences, "LoadTest", m_bLoadTest);
        ReadPrefBOOL(pPreferences, "DoAccel", m_bDoAccel);
        ReadPrefBOOL(pPreferences, "DoDecel", m_bDoDecel);
        ReadPrefBOOL(pPreferences, "DisableBothAccelDecel", m_bDisableBothAccelDecel);
        ReadPrefFLOAT(pPreferences, "AccelerationFactor", m_fAccelerationFactor);

      // DisableBothAccelDecel override all other preferences.
      // If it is true, set both DoAccel and DoDecel to false.
      // If DisableBothAccelDecel is FALSE do nothing at all.
      if (TRUE == m_bDisableBothAccelDecel)
      {
          m_bDoAccel = FALSE;
          m_bDoDecel = FALSE;
      }
      
      /////////////// END LOAD TEST ONLY SECTION

      /* Get MaxBandwidth from Prefs */
        ReadPrefINT32(pPreferences, "MaxBandwidth", m_ulMaxAccelBitRate); 

      HX_RELEASE(pPreferences);
      m_ulOriginalHighestBandwidthAvail = m_ulHighestBandwidthAvail;
    }

    /* This is ONLY used for load testing */
    if (m_bLoadTest)
    {
      const char* pSourceURL         = NULL;
      CHXURL*         pURL           = NULL;
      UINT32          ulTemp         = 0;
      IHXValues*  pOptions           = NULL;

      pSourceURL = pSource->GetURL();
      HX_ASSERT(pSourceURL);
      pURL = new CHXURL(pSourceURL);
      HX_ASSERT(pURL);
      pOptions = pURL->GetOptions();
      
      // Check for the DoAccel and DoDecel URL options. If they are
      // there set the sources properties to reflect them.  Also,
      // each option is overriden, in the 'off' state by the global
      // preferences DoAccel and DoDecel. Remember, both the
      // preferences values can be made false by setting the global
      // preference DisableBothAccelDecel to TRUE. Truth Table:
      //
      // Resulting ASM functionality = Option ^ Preference
      //
      // or,
      //
      // m_bSourceAccelAllowed = m_bSourceAccelAllowed^m_bDoAccel
      // m_bSourceDecelAllowed = m_bSourceDecelAllowed^m_bDoDecel
      //
      //                                           Resulting
      //   Preferences     URL Option String   ASM Functionality
      // DoAccel  DoDecel   DoAccel  DoDecel    Accel   Decel
      //   0        0         0        0          0       0
      //   0        0         0        1          0       0
      //   0        0         1        0          0       0
      //   0        0         1        1          0       0
      //   ...      ...       ...      ...        ...     ...
      //   0        1         0        0          0       0
      //   1        1         1        1          1       1
      // You get the idea. :-)
      
      //First, get any option strings. They default to FALSE in
      //the constructors.
      if( NULL != pOptions )
      {
          if( pOptions->GetPropertyULONG32("DoAccel", ulTemp) == HXR_OK)
          {
            pASMSourceInfo->m_bSourceAccelAllowed = (ulTemp == 1);
          }
          if( pOptions->GetPropertyULONG32("DoDecel", ulTemp) == HXR_OK)
          {
            pASMSourceInfo->m_bSourceDecelAllowed = (ulTemp == 1);
          }
      }//NULL != pOptions

      //Now, do the global preference overrides.
      pASMSourceInfo->m_bSourceAccelAllowed =
          pASMSourceInfo->m_bSourceAccelAllowed && m_bDoAccel;
      pASMSourceInfo->m_bSourceDecelAllowed =
          pASMSourceInfo->m_bSourceDecelAllowed && m_bDoDecel;


      HX_RELEASE(pOptions);
      HX_DELETE(pURL);


    }//m_bLoadTest

    //Report status of load test vars.
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "LoadTest %d", m_bLoadTest));
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "    DoAccel %u",  (UINT16)m_bDoAccel));
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "    DoDecel %u", (UINT16)m_bDoDecel));
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "    DisableBothAccelDecel %d",
//                      m_bDisableBothAccelDecel));
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "    m_bSourceAccelAllowed %d",
//              pASMSourceInfo->m_bSourceAccelAllowed));
//      DEBUG_OUT( m_pEM, DOL_ASM, (s, "    m_bSourceDecelAllowed %d",
//          pASMSourceInfo->m_bSourceDecelAllowed));
    

    UINT32 unStreamCount = pSource->GetStreamCount();     
    pASMSourceInfo->m_pStreams = new ASMStreamInfo*[unStreamCount];;

    BOOL bEnableSDB = FALSE;
    bEnableSDB = (unStreamCount == 0);

    pASMSourceInfo->m_ulLowestBandwidthBeforeTimeStamp = 0;
    for (i = 0; i < unStreamCount; i++)
    {
      IUnknown* pStream = 0;
        IHXStream* pHXStream = NULL;
      ASMStreamInfo* pInfo = new ASMStreamInfo;

      HX_VERIFY(HXR_OK == pSource->GetStream(i, pStream));
      HX_VERIFY(HXR_OK == pStream->QueryInterface
          (IID_IHXStreamBandwidthNegotiator,
          (void **)&pInfo->m_pNegotiator));
      HX_VERIFY(HXR_OK == pStream->QueryInterface
          (IID_IHXStreamBandwidthBias,
          (void **)&pInfo->m_pBias));
      HX_VERIFY(HXR_OK == pStream->QueryInterface
          (IID_IHXAtomicRuleGather,
          (void **)&pInfo->m_pRuleGather));

        pStream->QueryInterface(IID_IHXStream, (void**)&pHXStream);

        if (pHXStream)
        {
            pInfo->m_ulStreamNumber = pHXStream->GetStreamNumber();
            pHXStream->Release();
        }

      pInfo->m_pNegotiator->GetFixedBandwidth(pInfo->m_ulFixedBandwidth);

        if (pInfo->m_ulFixedBandwidth != 1)
        {
            bEnableSDB = TRUE;
        }

      pInfo->m_pASMSourceInfo = pASMSourceInfo;
      pASMSourceInfo->m_pStreams[i] = pInfo;
      m_pASMStreamInfo->AddTail((void *)pInfo);

      UINT32 ulLowestBandwidthBeforeTimeStamp = 0;
      if (pInfo->m_ulFixedBandwidth != 0)
      {
          ulLowestBandwidthBeforeTimeStamp = pInfo->m_ulFixedBandwidth;
      }
      else
      {
          // XXXNH: 6/7/99
          // We make this threshold array once and create it to be as large
          // as we will ever possibly need.  Each subsequent call to
          // GetThresholdInfo() should never need more than GetNumThresholds
          // returns.  UNLESS the ASMStreamInfo's m_pNegotiator were to 
          // change, but I don't think that's a feature we support.

          UINT32 ulNumThresholds = 
            pInfo->m_pNegotiator->GetNumThresholds();
          pInfo->m_pThreshold = new float[ulNumThresholds];
          pInfo->m_pNegotiator->GetThresholdInfo(
            (float*)pInfo->m_pThreshold, 
            pInfo->m_ulNumThresholds);
          pInfo->m_ulMaxEffectiveThreshold = pInfo->m_ulNumThresholds - 1;
          ulNumThresholds = pInfo->m_ulNumThresholds;

          ulLowestBandwidthBeforeTimeStamp = (UINT32) pInfo->m_pThreshold[ulNumThresholds-1];
          for (UINT32 i = ulNumThresholds-1; i > 0 ; i--)
          {
            UINT32 ulCurBand = (UINT32) pInfo->m_pThreshold[i];
            // used for timestamp rules
            if (ulCurBand == 0 || ulCurBand == 1)
            {
                break;
            }
            else 
            {
                ulLowestBandwidthBeforeTimeStamp = ulCurBand;
            }
          }
      }

      HX_ASSERT(ulLowestBandwidthBeforeTimeStamp != 0);

      pASMSourceInfo->m_ulLowestBandwidthBeforeTimeStamp += ulLowestBandwidthBeforeTimeStamp;

      HX_RELEASE(pStream);
    }

    // Rule for determining if SetDeliveryBandwidth is used.
    //
    // HXASMStream::bFixed   bEnabledSDB  m_bEnableSDB
    // ------------------------------------------
    //     FALSE             FALSE       TRUE  // no fbw means bw > 1
    //     FALSE             TRUE        TRUE  // at least one rule is fbw==1
    //     TRUE              FALSE       FALSE // all bw are fbw==1
    //     TRUE              TRUE        TRUE  // no streamcount, SDB true


    m_bEnableSDB = bEnableSDB;




    return HXR_OK;
}

STDMETHODIMP
HXSM::RegisterSourcesDone()
{
    if (m_pASMSourceInfo->GetCount() > 0 &&
      m_pASMStreamInfo->GetCount() > 0)
    {
        CHXSimpleList::Iterator     i;
        ASMSourceInfo*            pASMSourceInfo;

        for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
        {
          pASMSourceInfo = (ASMSourceInfo*)(*i);

            if (pASMSourceInfo && pASMSourceInfo->m_pSource)
            {
              DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s, "(%p)RegisterSourcesDone AccelFactor:%f", pASMSourceInfo->m_pSource, m_fAccelerationFactor));

                if (pASMSourceInfo->m_pSource->m_bFastStart)
                {
                     pASMSourceInfo->m_ulLastSetDelivery = 0;
                }
            }
        }

      m_State = INIT;
      RecalcAccel();
    }

    return HXR_OK;    
}


BOOL
HXSM::NotEnoughBandwidth()
{
    CHXSimpleList::Iterator i;
    ASMSourceInfo*          pASMSourceInfo;
    UINT32            ulTotal     = 0;
    BOOL              bIsLive     = FALSE;

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

      ulTotal += pASMSourceInfo->m_ulSubscribedBw;

      if (pASMSourceInfo->m_pSource &&
          pASMSourceInfo->m_pSource->IsLive())
      {
          bIsLive = TRUE;
      }
    }

    if (bIsLive && ulTotal > m_ulHighestBandwidthAvail)
    {
      return TRUE;
    }
    else
    {
      return FALSE;
    }
}

STDMETHODIMP
HXSM::UnRegisterSource(HXSource* pSource)
{
    LISTPOSITION        lPos;
    ASMSourceInfo*                 pASMSourceInfo = 0;
    ASMStreamInfo*                 pASMStreamInfo;
    BOOL                bFound = FALSE;

    lPos = m_pASMSourceInfo->GetHeadPosition();

    DEBUG_OUT(m_pEM, DOL_BWMGR, (s, "UnRegister Source %p %s", pSource, pSource->GetURL()));

    while (lPos)
    {
      pASMSourceInfo = (ASMSourceInfo *)m_pASMSourceInfo->GetAt(lPos);
      if (pASMSourceInfo->m_pSource == pSource)
      {
          m_pASMSourceInfo->RemoveAt(lPos);
          pASMSourceInfo->Done();
          bFound  = TRUE;
          break;
      }
      m_pASMSourceInfo->GetNext(lPos);
    }
    
    if (!bFound)
    {
      return HXR_OK;
    }

    lPos = m_pASMStreamInfo->GetHeadPosition();

    while (lPos)
    {
      pASMStreamInfo = (ASMStreamInfo*) m_pASMStreamInfo->GetAt(lPos);
      if (pASMStreamInfo->m_pASMSourceInfo == pASMSourceInfo)
      {
          /* RemoveAt returns the next position in the list.
           * DO NOT use GetNext if you remove a node.
           */
          lPos = m_pASMStreamInfo->RemoveAt(lPos);

          if (pASMStreamInfo->m_pNegotiator)
          {
            pASMStreamInfo->m_pNegotiator->UnRegister();
          }

          delete pASMStreamInfo;
      }
      else
      {
          m_pASMStreamInfo->GetNext(lPos);
      }
    }
    
    HX_RELEASE(pASMSourceInfo);
    
    m_ulNumSources--;

    if (m_ulNumSources > 0)
    {
      m_State = REDIST;
      RecalcAccel();
    }

    return HXR_OK;
}


/* Called by HXPlayer at end of each presentation */
STDMETHODIMP
HXSM::PresentationDone(void)
{
    if (m_ulNumSources == 0)
    {
      m_ulHighestBandwidthAvail = 0;
      m_ulPeakUsedBandwidth = 0;
      m_bInitialHighBwAvail = TRUE;
      m_bPipeFull = FALSE;
      m_bUpShiftInfoReady = FALSE;
      m_ulUpShiftRingPos = 0;
      m_ulUpShiftBandwidthAvail = 0;
      m_ulNumReportsSinceUpShift = 2;
      m_ulOfferToRecalc = 0;
      m_State = HX_NONE;
      m_bDidOfferUpShiftToRecalc = FALSE;
      m_lLoss = 0;
      m_ulNextPacketWindow = 0;
      m_lPacketCounter = 0;
      m_ulUpShiftPastResistanceCount = 0;
      m_ulUpShiftTestPointScaleFactor = 4000;
    }

    return HXR_OK;
}

/* If the source has enough data, it may tell the bandwidth
 * manager to cut down on accelerated buffering.
 */
STDMETHODIMP
HXSM::ChangeAccelerationStatus(HXSource* pSource,
                          BOOL         bMayBeAccelerated,
                        BOOL     bUseAccelerationFactor,
                        UINT32         ulAccelerationFactor)
{
    LISTPOSITION        lPos;
    ASMSourceInfo*              pASMSourceInfo = 0;
    BOOL                bFound = FALSE;

    lPos = m_pASMSourceInfo->GetHeadPosition();

    while (lPos)
    {
      pASMSourceInfo = (ASMSourceInfo *)m_pASMSourceInfo->GetAt(lPos);
      if (pASMSourceInfo->m_pSource == pSource)
      {
          bFound  = TRUE;
          break;
      }
      m_pASMSourceInfo->GetNext(lPos);
    }

    /* This assert may happen if you are in PNA and are in the debugger
     * accumulating tons of data at the networking layer
     */
//    HX_ASSERT(bFound);

    if (bFound)
    {
      pASMSourceInfo->ChangeAccelerationStatus(bMayBeAccelerated,
          bUseAccelerationFactor, ulAccelerationFactor);
    }
    else
    {
      /* Hmmm... ASM cannot help us here */
      /* Must be PNA. This may happen in case of TCP where the server sends 
       * data 300% faster than the content bandwidth.
       * Do the old style flow control by Pausing/Resuming the server
       */
      if (!bMayBeAccelerated)
      {
          pSource->DoPause();
      }
      else
      {
          pSource->DoResume();
      }
    }

    return HXR_OK;
}

//ChangeBW() allows setting the maximum bandwidth limit on a source. Called by 
//RTSPProtocol::HandleSetParameterRequest()

STDMETHODIMP
HXSM::ChangeBW(UINT32 newBW, HXSource* pSource)
{
    CHXSimpleList::Iterator     ii;
    ASMSourceInfo*                 pASMSourceInfo;  
    BOOL bSourceFound = FALSE;     
    DEBUG_OUT(m_pEM, DOL_BWMGR, (s,"(%p)Request to change BW to %ld", pSource, newBW));
    for(ii = m_pASMSourceInfo->Begin(); ii != m_pASMSourceInfo->End(); ++ii)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*ii);
      if (pASMSourceInfo->m_pSource == pSource) //Comparing Pointers
      {
          bSourceFound = TRUE;
          ASMRuleBook* pRuleBook = pASMSourceInfo->m_pMasterRuleBook;
          BOOL bDownShift = FALSE;
          if (pRuleBook)
          {
            UINT32 ulNumStreamsForThisSource = 
                pASMSourceInfo->m_pSource->GetStreamCount();

            BOOL* pCurrentSubInfo = new BOOL[pRuleBook->GetNumRules()];

            HXSMUpdateSubscriptionVars(m_pSubscriptionVariables, 
                                 newBW, FALSE, 0);

            HX_RESULT lResult =
                pRuleBook->GetSubscription(pCurrentSubInfo, m_pSubscriptionVariables);
            HX_ASSERT(lResult == HXR_OK);
            for (UINT16 idxRule = 0; idxRule < pRuleBook->GetNumRules(); 
            idxRule++)
            {     
                if (pCurrentSubInfo[idxRule])
                {
                  IHXValues* pProps = 0;
                  // Set Distribution
                  pRuleBook->GetProperties(idxRule, pProps);
                  for (UINT32 j = 0; j < ulNumStreamsForThisSource; j++)
                  {               
                      UINT8 pTemp[128];
                      IHXBuffer* pBw = NULL;

                      // Don't assume that streamid == index in pASMSourceInfo->m_pStreams[j]
                      SafeSprintf((char *)pTemp, 128, "Stream%ldBandwidth", pASMSourceInfo->m_pStreams[j]->m_ulStreamNumber); /* Flawfinder: ignore */

                      /*
                      * if this tripps either there's a bug in here or
                      * the content is messed up
                      *
                      */ 
                      HX_VERIFY(HXR_OK==
                        pProps->GetPropertyCString((char*)pTemp, pBw));
                      if (pBw)
                      {
                        BOOL bFoundMax=FALSE;
                        UINT32 newMaxBW = (UINT32) 
                            (atoi((char*)pBw->GetBuffer()));
                        for(int cnt =0; 
                        cnt < (int)pASMSourceInfo->m_pStreams[j]->
                            m_ulNumThresholds; cnt++)
                        {
                            if (newMaxBW == 
                              pASMSourceInfo->m_pStreams[j]->m_pThreshold[cnt])
                            {
                              bFoundMax = TRUE;
                              pASMSourceInfo->m_pStreams[j]->
                                  m_ulMaxEffectiveThreshold = cnt;
                              // We are downshifting!!
                              if ((int)pASMSourceInfo->m_pStreams[j]->
                                  m_ulThresholdPosition > cnt) 
                              {
                                  bDownShift = TRUE;
                                  pASMSourceInfo->m_pStreams[j]->
                                    m_ulThresholdPosition = cnt;
                              }
                              // We will try to upshift
                              else if ((int)pASMSourceInfo->m_pStreams[j]->
                                  m_ulThresholdPosition < cnt)  
                                  pASMSourceInfo->m_bTryToUpShift = TRUE;
                              break;
                            }
                        }
                        HX_ASSERT(bFoundMax);
                        if (bDownShift || pASMSourceInfo->m_bTryToUpShift)
                            pASMSourceInfo->m_bAdjustBandwidth = TRUE;
                        pBw->Release();
                        pBw = NULL;
                      } 
                  } 
                  HX_RELEASE(pProps);
                } 
            } 
          }
          //Assume a single stream source, or a fixedbw source .. 
          //for live, we have more than 1 streams ??
          else        
          {
            BOOL bFoundMax = FALSE;
            UINT32 numStreams = pASMSourceInfo->m_pSource->GetStreamCount();
            //for(int j = 0; j < numStreams; j++)
            //    {
            for(int cnt =0; 
            cnt < (int)pASMSourceInfo->m_pStreams[0]->m_ulNumThresholds; cnt++)
            {
                if (newBW == pASMSourceInfo->m_pStreams[0]->m_pThreshold[cnt])
                {
                  bFoundMax = TRUE;
                  // We are downshifting!!
                  if ((int)pASMSourceInfo->m_pStreams[0]->m_ulThresholdPosition > cnt) 
                  {
                      bDownShift = TRUE;
                      pASMSourceInfo->m_pStreams[0]->m_ulThresholdPosition = cnt;
                  }
                  // We are upshifting
                  else if ((int)pASMSourceInfo->m_pStreams[0]->m_ulThresholdPosition < cnt) 
                      pASMSourceInfo->m_bTryToUpShift = TRUE;
                  pASMSourceInfo->m_pStreams[0]->m_ulMaxEffectiveThreshold = cnt;
                  break;
                }
            }
            if (bDownShift || pASMSourceInfo->m_bTryToUpShift)
                pASMSourceInfo->m_bAdjustBandwidth = TRUE;
          }
          m_State = REDIST;
          RecalcAccel();
      } 
    } 
    HX_ASSERT(bSourceFound);

    return HXR_OK; 
}


void
HXSM::Recalc()
{
    CHXSimpleList::Iterator     i, j;
    ASMSourceInfo*                 pASMSourceInfo;
    ASMStreamInfo*                 pASMStreamInfo;
    INT32               lAggregateBandwidthUsage = 0;
    INT32               lAggregateBandwidthSent = 0;
    UINT32              ulSourceCount;
    UINT32              ulStreamCount;
    float               fBiasMean = (float) 0.;

    ulSourceCount = m_pASMSourceInfo->GetCount();
    ulStreamCount = m_pASMStreamInfo->GetCount();

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

        /* Init these for later */
      pASMSourceInfo->m_ulMasterOffer = 0;
      pASMSourceInfo->m_bTimeStampDelivery = FALSE;
    }

    lAggregateBandwidthUsage = m_ulOfferToRecalc;

    INT32 lCorrectAggregateBandwidthUsage = lAggregateBandwidthUsage;

    /*
     * For each stream that is at a fixed bitrate, remove that bitrate
     * from our available bandwidth.
     */
    for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
    {
        INT32 lBias;

      pASMStreamInfo = (ASMStreamInfo*)(*j);

      HX_VERIFY(HXR_OK == pASMStreamInfo->m_pBias->GetBiasFactor(lBias));
      fBiasMean += lBias;

      if (pASMStreamInfo->m_ulFixedBandwidth)
      {
          lAggregateBandwidthUsage -= pASMStreamInfo->m_ulFixedBandwidth;
          ulStreamCount--;
      }

      /* Init this for later */
      pASMStreamInfo->m_ulMasterRuleBookSetOffer = 0;
    }

    /* fBiasMean is not needed if everything has a fixed bandwidth */
    if (ulStreamCount != 0)
    {
      fBiasMean /= (float)ulStreamCount;
    }

    /*
     * Calculate the offer for each source that has a master rulebook
     * defining it's bandwidth division.
     */
    INT32 lNewAggregateBandwidthUsage = lAggregateBandwidthUsage;

    for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
    {
      INT32 lBias;

      pASMStreamInfo = (ASMStreamInfo*)(*j);

      HX_VERIFY(HXR_OK == pASMStreamInfo->m_pBias->GetBiasFactor(lBias));

      if (pASMStreamInfo->m_pASMSourceInfo->m_pMasterRuleBook)
      {
          UINT32 ulOffer = 
            (UINT32)(lAggregateBandwidthUsage / (float)ulStreamCount);

          ulOffer += 
            (UINT32)(((float)lBias - fBiasMean) *
            ((float)lAggregateBandwidthUsage / 100.0) *
            (2.0 / (float)ulStreamCount));

          pASMStreamInfo->m_pASMSourceInfo->m_ulMasterOffer += ulOffer;
          lNewAggregateBandwidthUsage -= ulOffer;
      }
    }

    lAggregateBandwidthUsage = lNewAggregateBandwidthUsage;

    /*
     * For each source that has a master rule book, evaluate it to find
     * out how much to distribute to each stream.
     */
    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);
      ASMRuleBook* pRuleBook = pASMSourceInfo->m_pMasterRuleBook;

      if (pRuleBook)
      {
          UINT32 ulNumStreamsForThisSource = 
            pASMSourceInfo->m_pSource->GetStreamCount();

          BOOL* pCurrentSubInfo = new BOOL[pRuleBook->GetNumRules()];

          HXSMUpdateSubscriptionVars(m_pSubscriptionVariables, 
                               pASMSourceInfo->m_ulMasterOffer,
                               FALSE, 0);

          HX_RESULT lResult =
            pRuleBook->GetSubscription(pCurrentSubInfo, m_pSubscriptionVariables);
          HX_ASSERT(lResult == HXR_OK);

          for (UINT16 idxRule = 0; idxRule < pRuleBook->GetNumRules();
            idxRule++)
          {
            if (pCurrentSubInfo[idxRule])
            {
                IHXValues* pProps = 0;
                // Set Distribution
                pRuleBook->GetProperties(idxRule, pProps);

                for (UINT32 j = 0; j < ulNumStreamsForThisSource; j++)
                {
                  UINT8       pTemp[128];
                  IHXBuffer* pBw = NULL;
                  HX_RESULT   hxResult;
                  
                  // Don't assume that streamid == index in pASMSourceInfo->m_pStreams[j]
                        SafeSprintf((char *)pTemp, 128, "Stream%ldBandwidth", pASMSourceInfo->m_pStreams[j]->m_ulStreamNumber); /* Flawfinder: ignore */

                  /*
                   * if this tripps either there's a bug in here or
                   * the content is messed up
                   *
                   */
                  //If the Stream?Bandwidth property isn't found for
                  //all streams don't worry about it. Not all streams
                  //may have rule books.
                  hxResult = pProps->GetPropertyCString((char *)pTemp, pBw);
                  if(HXR_OK==hxResult && pBw)
                  {
                      pASMSourceInfo->m_pStreams[j]->
                        m_ulMasterRuleBookSetOffer =
                        atoi((char*)pBw->GetBuffer());

                      pBw->Release();
                      pBw = NULL;
                  }
                  else
                  {
                      pASMSourceInfo
                        ->m_pStreams[j]
                        ->m_ulMasterRuleBookSetOffer = 0;
                  }//HXR_OK==hxResult && pBw
                }

                HX_RELEASE(pProps);
                break;
            }
          }

          delete [] pCurrentSubInfo;
      }
    }

    /*
     *  Now go through each of the streams that are not at a
     *  fixed bitrate and try to distribute the rest of the bandwidth.
     */
    UINT32 ulTakenBandwidth = 0;

    for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
    {
      INT32 lBias;

      pASMStreamInfo = (ASMStreamInfo*)(*j);

      if (pASMStreamInfo->m_ulFixedBandwidth != 0)
      {
          ulTakenBandwidth += pASMStreamInfo->m_ulFixedBandwidth;
          pASMStreamInfo->m_ulResistanceToLower = 0xffffffff;
          continue;
      }

      HX_VERIFY(HXR_OK == pASMStreamInfo->m_pBias->GetBiasFactor(lBias));

      HX_ASSERT(pASMStreamInfo->m_pThreshold != NULL);

      UINT32 ulOffer = 0;

      if (pASMStreamInfo->m_pASMSourceInfo->m_bPerfectPlay)
      {
          UINT32 i = pASMStreamInfo->m_ulMaxEffectiveThreshold;
          ulTakenBandwidth += (UINT32)pASMStreamInfo->m_pThreshold[i];
          pASMStreamInfo->m_ulResistanceToLower = 0xffffffff;
          pASMStreamInfo->m_ulOffer = (UINT32)pASMStreamInfo->m_pThreshold[i];
          pASMStreamInfo->m_ulThresholdPosition = i;

          /*
           * If we are in perfect play mode, just select the highest bandwidth rule
           * and don't negotiate any further.
           */
          continue;
      }

      if (pASMStreamInfo->m_ulMasterRuleBookSetOffer)
      {
          ulOffer = pASMStreamInfo->m_ulMasterRuleBookSetOffer - 1;
      }
      else
      {
          ulOffer =
            (UINT32)(lAggregateBandwidthUsage / (float)ulStreamCount);

          ulOffer += 
            (UINT32)(((float)lBias - fBiasMean) *
            ((float)lAggregateBandwidthUsage / 100.0) *
            (2.0 / (float)ulStreamCount));
      }

      HX_ASSERT(pASMStreamInfo->m_ulMaxEffectiveThreshold >= 0);
      if (pASMStreamInfo->m_ulMaxEffectiveThreshold == 0)
      {
          HX_ASSERT(pASMStreamInfo->m_pThreshold[0] == 0);

          ulTakenBandwidth += (UINT32)pASMStreamInfo->m_pThreshold[0];
          pASMStreamInfo->m_ulResistanceToLower = 0xffffffff;
      }
      else
      {
          for (UINT32 i = 1; i <= pASMStreamInfo->m_ulMaxEffectiveThreshold; i++)
          {
            if ((ulOffer <= pASMStreamInfo->m_pThreshold[i]) ||
                  (i == (pASMStreamInfo->m_ulMaxEffectiveThreshold)))
            {
                ulTakenBandwidth += (UINT32)pASMStreamInfo->m_pThreshold[i];

                if (i == 1)
                {
                  pASMStreamInfo->m_ulResistanceToLower = 0xffffffff;
                }
                else
                {
                  pASMStreamInfo->m_ulResistanceToLower = (ulOffer -
                      (UINT32)pASMStreamInfo->m_pThreshold[i - 1]) * ulOffer;
                }

                pASMStreamInfo->
                  m_ulOffer = ulOffer;
                pASMStreamInfo->m_ulThresholdPosition = i;

                break;
            }
          }
      }
    }

    lAggregateBandwidthUsage = lCorrectAggregateBandwidthUsage;

tryagain:

    if (lAggregateBandwidthUsage < (INT32)ulTakenBandwidth)
    {
      /* Resistance is Futile.  You will be Real(tm)lyAssimilated */
      UINT32 ulLowestResistance = 0xffffffff;
      ASMStreamInfo* pLowestResistanceStream  = 0;

      for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
      {
          pASMStreamInfo = (ASMStreamInfo*)(*j);

          if (pASMStreamInfo->m_ulResistanceToLower < ulLowestResistance)
          {
            ulLowestResistance = pASMStreamInfo->m_ulResistanceToLower;
            pLowestResistanceStream = pASMStreamInfo;
          }
      }

      if (ulLowestResistance == 0xffffffff)
      {
      }
      else
      {
          ulTakenBandwidth -= (UINT32)
            pLowestResistanceStream->m_pThreshold[pLowestResistanceStream->m_ulThresholdPosition];

          pLowestResistanceStream->m_ulThresholdPosition--;

          ulTakenBandwidth += (UINT32)
            pLowestResistanceStream->m_pThreshold[pLowestResistanceStream->m_ulThresholdPosition];

          if (pLowestResistanceStream->m_ulThresholdPosition == 1)
          {
            pLowestResistanceStream->m_ulResistanceToLower = 0xffffffff;
          }
          else
          {
            pLowestResistanceStream->m_ulResistanceToLower = (pLowestResistanceStream->m_ulOffer -
                (UINT32)pLowestResistanceStream->m_pThreshold[
                pLowestResistanceStream->m_ulThresholdPosition - 1]) *
                pLowestResistanceStream->m_ulOffer;
          }

          goto tryagain;
      }
    }

    UINT32 ulLeftOverForDropByN = lAggregateBandwidthUsage - ulTakenBandwidth;
    BOOL bForce = FALSE;

    for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
    {
      pASMStreamInfo = (ASMStreamInfo*)(*j);

      UINT32 ulBw = 1;

      if (pASMStreamInfo->m_ulFixedBandwidth)
      {
          ulBw = pASMStreamInfo->m_ulFixedBandwidth;
      }
      else
      {
          ulBw = (UINT32)
                pASMStreamInfo->m_pThreshold[pASMStreamInfo->m_ulThresholdPosition];
      }

      UINT32 ulBwOffered = ulBw;

      if (ulBw == 1)
      {
          // Hack Alert for DropByN. XXXSMP
          ulBwOffered = ulBw = ulLeftOverForDropByN;
      }

      if ((ulBw != pASMStreamInfo->m_ulLastBandwidth) &&
          (!pASMStreamInfo->m_ulFixedBandwidth))
      {
          bForce = TRUE;
      }
      pASMStreamInfo->m_pRuleGather->
          RuleGather(&pASMStreamInfo->m_pASMSourceInfo->
          m_SubscriptionChanges);

      pASMStreamInfo->SetLastBandwidth(ulBw);
      HX_ASSERT(ulBw == ulBwOffered);

      //update the HXASMStream with our new bandwidth
      pASMStreamInfo->NotifyNewBandwidth();

      //update the source's knowledge of tsd
      pASMStreamInfo->NotifyTimeStampDelivery();

      //if the stream is behind, tell the server to chill
      pASMStreamInfo->NotifyLimitBandwidth(ulBwOffered);

      pASMStreamInfo->m_pRuleGather->RuleGather(0);
    }

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

      if (!pASMSourceInfo->m_SubscriptionChanges.IsEmpty())
      {
          pASMSourceInfo->m_pStreams[0]->m_pRuleGather->
            RuleFlush(&pASMSourceInfo->m_SubscriptionChanges);

          for (j = pASMSourceInfo->m_SubscriptionChanges.Begin();
             j != pASMSourceInfo->m_SubscriptionChanges.End(); ++j)
          {
            RTSPSubscription* pSub = (RTSPSubscription*)(*j);
            delete pSub;
          }
          pASMSourceInfo->m_SubscriptionChanges.RemoveAll();
      }
    }

    if (m_State == REDO_ACCEL)
    {
      RecalcAccel();
      return;
    }
    if (m_State == CONGESTION)
    {
      RecalcAccel();
      return;
    }
    if (m_State == INIT)
    {
      m_State = INIT_REDIST;
      RecalcAccel();
      return;
    }
    if (bForce)
    {
      m_State = REDO_ACCEL;
      RecalcAccel();
      return;
    }
}

void
HXSM::RecalcAccel()
{
    CHXSimpleList::Iterator     i, j;
    ASMSourceInfo*                 pASMSourceInfo;
    ASMStreamInfo*                 pASMStreamInfo;
    UINT32 ulAggregateUsed = 0;
    UINT32 ulTotalMaxSubscribedBw = 0;

    if (m_State == INIT)
    {
      m_ulOfferToRecalc = m_ulHighestBandwidthAvail;

      if (m_ulOfferToRecalc > m_ulMaxAccelBitRate)
      {
          m_ulOfferToRecalc = m_ulMaxAccelBitRate;
      }
#ifdef MOREDEBUG
      DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                  "INIT Offer to Recalc() %d", m_ulOfferToRecalc));
#endif

      Recalc();
      return;
    }

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

      pASMSourceInfo->m_ulSubscribedBw = 0;
      pASMSourceInfo->m_ulMaxSubscribedBw = 0;
    }

    for (j = m_pASMStreamInfo->Begin(); j != m_pASMStreamInfo->End(); ++j)
    {
      pASMStreamInfo = (ASMStreamInfo*)(*j);

      if (pASMStreamInfo->m_ulFixedBandwidth)
      {
          pASMStreamInfo->m_pASMSourceInfo->m_ulSubscribedBw += 
            pASMStreamInfo->m_ulFixedBandwidth;
          pASMStreamInfo->m_pASMSourceInfo->m_ulMaxSubscribedBw += 
            pASMStreamInfo->m_ulFixedBandwidth;
          ulTotalMaxSubscribedBw += pASMStreamInfo->m_ulFixedBandwidth;
          ulAggregateUsed += pASMStreamInfo->m_ulFixedBandwidth;
      }
      else
      {
          pASMStreamInfo->m_pASMSourceInfo->m_ulSubscribedBw += (UINT32)
            pASMStreamInfo->m_pThreshold[
                pASMStreamInfo->m_ulThresholdPosition];
          HX_ASSERT(pASMStreamInfo->m_pASMSourceInfo->m_ulSubscribedBw < 0x7fffffff);

          pASMStreamInfo->m_pASMSourceInfo->m_ulMaxSubscribedBw += (UINT32)
            pASMStreamInfo->m_pThreshold[
                pASMStreamInfo->m_ulMaxEffectiveThreshold];

          ulTotalMaxSubscribedBw += (UINT32)pASMStreamInfo->m_pThreshold[
                pASMStreamInfo->m_ulMaxEffectiveThreshold];

          ulAggregateUsed += (UINT32)
            pASMStreamInfo->m_pThreshold[
                pASMStreamInfo->m_ulThresholdPosition];
      }
    }

    UINT32 ulNumBehindSources       = 0;
    UINT32 ulNumSlightlyBehindSources     = 0;
    INT32  lAggregateBandwidthUsage = 0;
    INT32  ulMaxNeededBW                = 0;
    BOOL   bAllZeroBw               = TRUE;
    BOOL   bFastStart                   = FALSE;
    
    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

      if (pASMSourceInfo->m_ulLastSetDelivery == 0xffffffff)
      {
          pASMSourceInfo->m_ulLastSetDelivery = pASMSourceInfo->m_ulSubscribedBw;
      }

        // if ANY of the sources are fast start then we are in 
        // fast start mode. We may wish to re-visit this decision!
        // this comment is for you Rahul!

        if (pASMSourceInfo && pASMSourceInfo->m_pSource)
        {
            bFastStart = bFastStart | pASMSourceInfo->m_pSource->m_bFastStart;
        }

      ulNumBehindSources += pASMSourceInfo->m_bBehind ? 1 : 0;
      ulNumSlightlyBehindSources += pASMSourceInfo->m_bSlightlyBehind ? 1 : 0;

      lAggregateBandwidthUsage += pASMSourceInfo->GetBandwidth();
      if (!pASMSourceInfo->GetBandwidth())
          lAggregateBandwidthUsage += pASMSourceInfo->m_ulSubscribedBw;
      else
          bAllZeroBw = FALSE;

        ulMaxNeededBW += pASMSourceInfo->m_ulMaxSubscribedBw;
    }

    // so if we are in fast start, let's check to see if we don't want to be in
    // fast start!
    double maxPossibleAccelRatio = 0.;
    if (ulMaxNeededBW > 0.)
    {
        maxPossibleAccelRatio = (double) m_ulOriginalHighestBandwidthAvail / (double) ulMaxNeededBW;
    }

    for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
    {
      pASMSourceInfo = (ASMSourceInfo*)(*i);

        // I could check here for pASMSourceInfo->m_pSource->m_bFastStart, but really
        // does it matter?

        if (pASMSourceInfo && pASMSourceInfo->m_pSource)
        {
            pASMSourceInfo->m_pSource->SetMaxPossibleAccelRatio(maxPossibleAccelRatio);
        }

        // turn this stuff of if we are on modem. *sigh* It probably sort of works on 
        // modems too. This value makes it work on ISDN, that's ok by me, but if people
        // don't like it, I can change it.         
        if (maxPossibleAccelRatio < 1.5 || 
            (m_ulOriginalHighestBandwidthAvail < 110000)) // it now works on DSL or higher
        {
          bFastStart = FALSE;
            if (pASMSourceInfo->m_pSource->m_bFastStart)
          {
                DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,"(%p)ASM %d - Leaving TurboPlay", pASMSourceInfo->m_pSource, __LINE__));
            pASMSourceInfo->m_pSource->LeaveFastStart(TP_OFF_BY_NOTENOUGHBW);
          }
        }

        // Are we currently asking for less than max? Is so Disable!
      //
      // XXX HP I am not sure the following logic is valid, it's possible 
      //      pASMSourceInfo->m_ulSubscribedBw < pASMSourceInfo->m_ulMaxSubscribedBw because the
      //      master rulebook defines so even though we have plenty of bandwidth(i.e. maxPossibleAccelRatio > 1.5)
      //      If it's really the case that the source doesn't subscribe to its max. bandwidth because
      //      we don't have enough bandwidth, then maxPossibleAccelRatio < 1.5 and we should left faststart
      //      already
      /*
        if (pASMSourceInfo && pASMSourceInfo->GetBandwidth() && pASMSourceInfo->m_ulMaxSubscribedBw != pASMSourceInfo->m_ulSubscribedBw
            &&  pASMSourceInfo->m_pSource->m_bFastStart)
        {
            DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,"ASM %d - Leaving TurboPlay", __LINE__));
            DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,"%d %d %d", pASMSourceInfo->m_ulMaxSubscribedBw, pASMSourceInfo->GetBandwidth(),pASMSourceInfo->m_ulSubscribedBw));
            pASMSourceInfo->m_pSource->LeaveFastStart();
        }
      */
    }

    if (m_bPipeFull == TRUE)
    {
      /*
       * Adjust the highest available bandwidth because we have found
       * the maximum bandwidth that the pipe can handle.  We do this
       * so that sources that get added in the future will have
       * some information about the max. bandwidth that exists.  This
       * value is aggresive because a source will want to consume everything
       * it can and fall back if it goes over the top.
       */
      HX_ASSERT(lAggregateBandwidthUsage >= 100);
      if (lAggregateBandwidthUsage < 100)
      {
          /*
           * Please have at *least* 100bps before attempting to
           * run the RealPlayer.
           */
          lAggregateBandwidthUsage = 100;
      }
      m_ulHighestBandwidthAvail = (UINT32)(lAggregateBandwidthUsage);
      m_ulPeakUsedBandwidth = (UINT32)(lAggregateBandwidthUsage);
      m_bInitialHighBwAvail = FALSE;
      m_bPipeFull = FALSE;
    }

    if (m_State == REDIST)
    {
        m_State = REDO_ACCEL;
        m_ulOfferToRecalc = m_ulHighestBandwidthAvail;
        Recalc();
      return;
    }

    if ((m_State == REDO_ACCEL) || (m_State == INIT_REDIST))
    {
      UINT32 ulBigValue;

      if ((m_bInitialHighBwAvail) || (m_State == REDO_ACCEL))
      {
          ulBigValue = m_ulPeakUsedBandwidth;

          if (bFastStart && (m_State == INIT_REDIST))
          {
            ulBigValue = m_ulMaxAccelBitRate;
          } 
          else if ((INT32)ulBigValue > lAggregateBandwidthUsage)
          {
            ulBigValue = lAggregateBandwidthUsage;
          }
      }
      else
      {
          /*
           * If your state is REDO_ACCEL & we have an imperical value
           * then maybe we should use this (ABU) instead of the above,
           * but this value may not be completely up to date?
           */
          ulBigValue = lAggregateBandwidthUsage;
      }

      HX_ASSERT(ulBigValue > 0); // Rahul's Crazy, This won't ever happen!

      for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
      {
          pASMSourceInfo = (ASMSourceInfo*)(*i);

          IHXThinnableSource* pThin = 0;
          UINT32 ulSourceBandwidth = pASMSourceInfo->m_ulSubscribedBw;

          UINT32 ulNewValue = 
                (UINT32)(
                ((float)ulSourceBandwidth /
                (float)ulAggregateUsed) *
                (float)(ulBigValue));

          if ((HXR_OK == pASMSourceInfo->m_pSource->
            QueryInterface(IID_IHXThinnableSource, (void **)&pThin)))
          {
            if ((ulNewValue > (pASMSourceInfo->m_ulLastSetDelivery * 1.02)) ||
                (ulNewValue < (pASMSourceInfo->m_ulLastSetDelivery * 0.98)) ||
                (pASMSourceInfo->m_bAdjustBandwidth && pASMSourceInfo->m_pSource->IsLive()))
            {
                    BOOL bFastStart = FALSE;
                    
                    if (pASMSourceInfo && pASMSourceInfo->m_pSource)
                    {
                        bFastStart = pASMSourceInfo->m_pSource->m_bFastStart;
                    }

                    if (bFastStart)
                    {
                    if (ulNewValue > (pASMSourceInfo->m_ulMaxSubscribedBw * m_fAccelerationFactor))
                    {
                      ulNewValue = (UINT32) 
                          (pASMSourceInfo->m_ulMaxSubscribedBw * m_fAccelerationFactor);
                    }
                
                        // if the server says to cap the value, we cap the value!
                        if (pASMSourceInfo && pASMSourceInfo->m_pSource && ulNewValue  > pASMSourceInfo->m_pSource->m_ulMaxBandwidth * 1000 )
                        {
                            ulNewValue = pASMSourceInfo->m_pSource->m_ulMaxBandwidth * 1000;
                        }
                        // if the value is greater is than the pipe set it to a 
                        // little less than the pipe!
                        if (ulNewValue  > m_ulOriginalHighestBandwidthAvail)
                        {
                            ulNewValue = m_ulOriginalHighestBandwidthAvail;
                        }
                    }
                    else
                    {
                    if (ulNewValue > (pASMSourceInfo->m_ulMaxSubscribedBw * 4))
                    {
                      ulNewValue = (UINT32) 
                          (pASMSourceInfo->m_ulMaxSubscribedBw * 4);
                    }

                  /*
                   * Live streams get capped at 107% of Max to prevent 
                   * unneeded bandwidht modulation.
                   */
                  if ((pASMSourceInfo->m_pSource->IsLive()) &&
                     (ulNewValue >
                        (pASMSourceInfo->m_ulMaxSubscribedBw * 1.07)))
                  {
                      ulNewValue = (UINT32)
                        (pASMSourceInfo->m_ulMaxSubscribedBw * 1.07);
                  }
                }
                pASMSourceInfo->m_bAdjustBandwidth = FALSE;

                if ((ulNewValue > (pASMSourceInfo->m_ulMaxSubscribedBw)) &&
                  (ulNewValue > (ulSourceBandwidth * 3)) &&
                  (pASMSourceInfo->m_ulLastSetDelivery >
                      pASMSourceInfo->m_ulMaxSubscribedBw))
                {
                  /*
                   * If we are already accelerating 3x subscribed bandwidth
                   * and we are about to upshift beyond the max possible
                   * bandwidth, then let's stop and take a breather just
                   * above the max subscription.  This prevents us from
                   * buffering huge amounts of the crappy low bw stream.
                   */
                  UINT32 ulTemp;
                  ulTemp = (UINT32) 
                      (pASMSourceInfo->m_ulMaxSubscribedBw * 1.10);
                  ulNewValue = MIN(ulTemp, ulNewValue);
                }

                if ((ulNewValue < ulSourceBandwidth) && (ulSourceBandwidth > 10))
                {
                  pASMSourceInfo->m_pSource->EnterBufferedPlay();
                } 
                if (ulNewValue >= ulSourceBandwidth)
                {
                  pASMSourceInfo->m_pSource->LeaveBufferedPlay();
                }

                if ((ulNewValue >= pASMSourceInfo->m_ulLastSetDelivery) &&
                  (!pASMSourceInfo->m_bMayBeAccelerated) && 
                  (!pASMSourceInfo->m_bTryToUpShift))
                {
                  goto dont_actually_set_the_rate;
                }

                if (ulNewValue > m_ulResistanceBitRate && !bFastStart)
                {
                  UINT32 ulActualResistanceBitRate = m_ulResistanceBitRate;

                  if (ulActualResistanceBitRate < ulAggregateUsed)
                  {
                      ulActualResistanceBitRate = (UINT32)
                          (ulAggregateUsed * 1.05);
                  }

                  if (ulNewValue > ulActualResistanceBitRate)
                  {
                      ulNewValue = ulActualResistanceBitRate;
                  }
                }
 
                if(pASMSourceInfo->m_bTryToUpShift)
                {
                  pASMSourceInfo->m_bTryToUpShift=FALSE;

                  //XXXRA why not check for ulNewValue < ((UINT32)(ulSourceBandwidth * 1.15)
                  // before assignment.  
                  ulNewValue = (UINT32)(ulSourceBandwidth * 1.15);
                }
                
                pASMSourceInfo->m_ulLastSetDelivery = ulNewValue;

                UINT32 ulActualRate = ulNewValue;

                /*
                 * Always keep TCP traffic faster then needed
                 * (but keep it quiet so the rest of the algorithm doesn't
                 * find out :-)
                 */
                if (pASMSourceInfo->m_TransportType == TNG_TCP)
                {
                  ulActualRate = MAX(ulActualRate,
                      (UINT32)(ulSourceBandwidth * 1.10));
                }

                DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s, "(%p)Redist: Tranmission Rate to %d", pASMSourceInfo->m_pSource, ulActualRate));


                    if (m_bEnableSDB)
                    {
                        pThin->SetDeliveryBandwidth(ulActualRate, 0);
                    }

                if (bFastStart)
                {
                  pASMSourceInfo->m_pSource->m_turboPlayStats.ulAcceleratedBW = ulActualRate;
                }
            }
          }
dont_actually_set_the_rate:
          HX_RELEASE(pThin);
      }
      m_State = HX_NONE;
      return;
    }

    if (m_State == CHILL_BUFFERING)
    {
      m_ulOfferToRecalc = lAggregateBandwidthUsage;
#ifdef MOREDEBUG
      DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                  "CHILL to Recalc() %d", m_ulOfferToRecalc));
#endif
      m_State = HX_NONE;

      Recalc();
    }

    if ((ulNumBehindSources) ||
      ((lAggregateBandwidthUsage > ((INT32)m_ulMaxAccelBitRate + 100)) &&
          (bAllZeroBw)))
    {
      if ((lAggregateBandwidthUsage > (INT32)m_ulMaxAccelBitRate) &&
          (bAllZeroBw))
      {
          lAggregateBandwidthUsage = m_ulMaxAccelBitRate;
      }

      // XXXRA change m_ulNumReportsSinceUpShift to m_lNumReportsSinceUpShift
      m_ulNumReportsSinceUpShift = -2;
      UINT32 ulLow  = (UINT32)(m_ulLastStableBandwidth * 0.90);
      UINT32 ulHigh = (UINT32)(m_ulLastStableBandwidth * 1.10);
      /*
       * XXXSMP Maybe we don't want to use stable point when the aggregate
       * detected is more then the stable point?
       */
      if ((lAggregateBandwidthUsage > (INT32)ulLow) && 
          (lAggregateBandwidthUsage < (INT32)ulHigh))
      {
          /*
           * If we are close to the last stable bandwidth, then let's
           * try that one again.
           */
          lAggregateBandwidthUsage = m_ulLastStableBandwidth;
#ifdef MOREDEBUG
          DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                  "Used Stable Point %d", m_ulLastStableBandwidth));
#endif

          m_ulLastStableBandwidth = 0;

          m_ulUpShiftTestPointScaleFactor = MAX(1500, 
            (UINT32)(m_ulUpShiftTestPointScaleFactor * 0.85));
      }
      if (m_State != CONGESTION)
      {
          for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
          {
            pASMSourceInfo = (ASMSourceInfo*)(*i);

            UINT32 ulSourceBandwidth = pASMSourceInfo->m_ulSubscribedBw;
            UINT32 ulNewValue = 
                  (UINT32)(
                  (float)ulSourceBandwidth /
                  (float)ulAggregateUsed *
                  (float)lAggregateBandwidthUsage * 0.97);

            if (ulNewValue < (pASMSourceInfo->m_ulSubscribedBw))
            {
                // Attempt ASM Switching to reduce bandwidth usage.
                m_State = CONGESTION;
                m_ulOfferToRecalc = (UINT32)
                    (lAggregateBandwidthUsage * 0.97);

#ifdef MOREDEBUG
                DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                  "CONGESTION to Recalc() %d", m_ulOfferToRecalc));
#endif

                    // once again, if we are in start start mode we need to 
                    // turn it off. It may be off already, but I just want to 
                    // make sure.

                    if (pASMSourceInfo->m_pSource->m_bFastStart)
                    {
                        DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,"(%p)ASM %d - Leaving TurboPlay", pASMSourceInfo->m_pSource, __LINE__));
                        pASMSourceInfo->m_pSource->LeaveFastStart(TP_OFF_BY_NETCONGESTION);
                    }

                Recalc();
                return;
            }
          }
          m_State = CONGESTION;
          RecalcAccel();
          return;
      } //m_State != CONGESTION
      else
      {
          BOOL bLossBehind = FALSE;
          m_State = HX_NONE;
          UINT32 ulTotalBandwidth = 0;
          for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
          {
            pASMSourceInfo = (ASMSourceInfo*)(*i);

            IHXThinnableSource* pThin = 0;
            UINT32 ulSourceBandwidth = pASMSourceInfo->m_ulSubscribedBw;

            UINT32 ulNewValue = 
                  (UINT32)(
                  (float)ulSourceBandwidth /
                  (float)ulAggregateUsed *
                  (float)lAggregateBandwidthUsage * 0.70);

            if (ulNewValue < ulSourceBandwidth)
            {
                /* Can't be conservative, so go use what we need */
                ulNewValue = 
                      (UINT32)(
                      (float)ulSourceBandwidth /
                      (float)ulAggregateUsed *
                      (float)lAggregateBandwidthUsage * 0.97);

                    // once again, if we are in start start mode we need to 
                    // turn it off. It may be off already, but I just want to 
                    // make sure.

                    if (pASMSourceInfo->m_pSource->m_bFastStart)
                    {
                        DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,"(%p)ASM %d - Leaving TurboPlay", pASMSourceInfo->m_pSource, __LINE__));
                        pASMSourceInfo->m_pSource->LeaveFastStart(TP_OFF_BY_NETCONGESTION);
                    }
            }

            if (pASMSourceInfo->m_bLossBehind &&
                  (ulNewValue < ulSourceBandwidth))
            {
                DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                      "(%p)No Loss Reduce: Will Force BP", pASMSourceInfo->m_pSource));
                ulNewValue = ulSourceBandwidth;
            }

            if ((HXR_OK == pASMSourceInfo->m_pSource->
                QueryInterface(IID_IHXThinnableSource, (void **)&pThin)))
            {
                if (ulNewValue < (pASMSourceInfo->m_ulLastSetDelivery))
                {
                  DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                      "(%p)Congestion: Slow Tranmission Rate to %d %p", pASMSourceInfo->m_pSource,
                      ulNewValue, pASMSourceInfo));

                  if (pASMSourceInfo->m_bLossBehind)
                  {
                      pASMSourceInfo->m_ulIncomingBandwidth = ulNewValue;
                      bLossBehind = TRUE;
                  }

                  if (pASMSourceInfo->m_ulRateBeforeDeAccel)
                  {
                      pASMSourceInfo->m_ulRateBeforeDeAccel = ulNewValue;
                      /*
                       * Reset the core's acceleration status. 
                       */

                      IHXWatermarkBufferControl* pWMBufCtl = NULL;
                      
                      pASMSourceInfo->m_pSource->
                        QueryInterface(IID_IHXWatermarkBufferControl,
                                     (void**)&pWMBufCtl);

                      if (pWMBufCtl)
                      {
                        pWMBufCtl->ClearChillState();
                        pWMBufCtl->Release();
                        pWMBufCtl = NULL;
                      }
                      pASMSourceInfo->m_bMayBeAccelerated = TRUE;
                      pASMSourceInfo->m_bPendingChill = FALSE;
                  }

                  if ((ulNewValue < ulSourceBandwidth) && (ulSourceBandwidth > 10))
                  {
                      pASMSourceInfo->m_pSource->EnterBufferedPlay();
                  }

                  pASMSourceInfo->m_ulLastSetDelivery = ulNewValue;
                    ulTotalBandwidth += ulNewValue;
                  UINT32 ulActualRate = ulNewValue;

                  /*
                   * Always keep TCP traffic faster then needed
                   * (but keep it quiet so the rest of the algorithm doesn't
                   * find out :-)
                   */
                  if (pASMSourceInfo->m_TransportType == TNG_TCP)
                  {
                      ulActualRate = MAX(ulActualRate,
                        (UINT32)(ulSourceBandwidth * 1.10));
                  }
                        // In low heap mode, do not change the delivery bw.
                  // NOTE: There is concern that this is not 
                  // satisfactory as a truly long term solution since
                  // bw rate control is regarded by some as critical
                  // for limited resource platforms.

#if !defined(HELIX_CONFIG_LOW_HEAP_STREAMING)
                  pThin->SetDeliveryBandwidth(ulActualRate, 0);
#endif
                }
                else
                {
                    ulTotalBandwidth +=
                      pASMSourceInfo->m_ulLastSetDelivery;
                }
            }
            HX_RELEASE(pThin);
          }
          if (bLossBehind)
          {
            m_ulNumReportsSinceUpShift = -10;
            m_ulResistanceBitRate = MAX(15000, ulTotalBandwidth);
            DEBUG_OUT(m_pEM, DOL_TRANSPORT, 
                (s, "Resistance Move %d", m_ulResistanceBitRate));
          }
      }
    }
    else if (!ulNumSlightlyBehindSources)
    {
      INT32 lAccelTestPoint;
      double dRFactor = 1.05;

      if ((INT32)m_ulUpShiftBandwidthAvail > lAggregateBandwidthUsage)
      {
          lAccelTestPoint = (INT32) 
            ((m_ulUpShiftBandwidthAvail - lAggregateBandwidthUsage)
            * ((float)m_ulUpShiftTestPointScaleFactor / 10000.0)
                + lAggregateBandwidthUsage);
      }
      else
      {
          lAccelTestPoint = lAggregateBandwidthUsage;
      }

      UINT32 ulAccelTestPoint =
          (lAccelTestPoint > 0) ? (UINT32)lAccelTestPoint : 0;
      BOOL bResistanceLimited = FALSE;
      BOOL bWentHigherThanResistanceRate = FALSE;

      if (ulAccelTestPoint > m_ulMaxAccelBitRate)
      {
          ulAccelTestPoint = m_ulMaxAccelBitRate;
      }
      
      if (ulAccelTestPoint > m_ulResistanceBitRate)
      {
          UINT32 ulActualResistanceBitRate = m_ulResistanceBitRate;

          if (ulActualResistanceBitRate < ulAggregateUsed)
          {
            ulActualResistanceBitRate = (UINT32)(ulAggregateUsed * 1.05);
          }

          UINT32 ulOldAccelTestPoint = ulAccelTestPoint;
          if (ulAccelTestPoint > ulActualResistanceBitRate)
          {
            UINT32 bHowManyReports =
                (ulActualResistanceBitRate <
                  ulTotalMaxSubscribedBw) ? 5 : 10;

            if (m_ulUpShiftPastResistanceCount > bHowManyReports)
            {
                bWentHigherThanResistanceRate = TRUE;

                if ((m_ulOriginalResistanceBitRate >
                    ulActualResistanceBitRate) &&
                  (ulActualResistanceBitRate < ulTotalMaxSubscribedBw))
                {
                  dRFactor = (ulActualResistanceBitRate +
                      ((m_ulOriginalResistanceBitRate -
                      ulActualResistanceBitRate) * 0.10)) /
                      (double)ulActualResistanceBitRate;
                  if (dRFactor < 1.01)
                  {
                      dRFactor = 1.01;
                  }
#ifdef MOREDEBUG
                    DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                      "Resistance Accel Factor %0.2f", dRFactor));
#endif
                }
                else
                {
                  dRFactor = 1.01;
                }
                ulAccelTestPoint = (UINT32)(ulActualResistanceBitRate *
                    dRFactor);
            }
            else
            {
                ulAccelTestPoint = ulActualResistanceBitRate;
            }
            if (ulOldAccelTestPoint < ulAccelTestPoint)
            {
                ulAccelTestPoint = ulOldAccelTestPoint;
            }
            else
            {
                bResistanceLimited = TRUE;
            }
          }
      }

      if ((m_ulNumReportsSinceUpShift >= 2) &&
            ((INT32)m_ulHighestBandwidthAvail < lAggregateBandwidthUsage))
      {
          m_ulHighestBandwidthAvail = lAggregateBandwidthUsage;
          m_ulPeakUsedBandwidth = lAggregateBandwidthUsage;
          m_bInitialHighBwAvail = FALSE;
      }

      DEBUG_OUT(m_pEM, DOL_TRANSPORT_EXTENDED,
          (s, "UP Bw Report: Num=%d, Avail=%d, CurrentBw=%d, TestPoint=%d", 
          m_ulNumReportsSinceUpShift, m_ulUpShiftBandwidthAvail,
          lAggregateBandwidthUsage, ulAccelTestPoint));

      BOOL bDidChange = FALSE;
      BOOL bBrokeMax = FALSE;
      if ((m_ulNumReportsSinceUpShift >= 2) &&
          (INT32) (ulAccelTestPoint) > lAggregateBandwidthUsage)
      {
          m_ulLastStableBandwidth = lAggregateBandwidthUsage;
          for (i = m_pASMSourceInfo->Begin(); i != m_pASMSourceInfo->End(); ++i)
          {
            pASMSourceInfo = (ASMSourceInfo*)(*i);

            IHXThinnableSource* pThin = 0;
            UINT32 ulSourceBandwidth = pASMSourceInfo->m_ulSubscribedBw;

            UINT32 ulNewValue = 
                  (UINT32)(
                  (float)ulSourceBandwidth /
                  (float)ulAggregateUsed *
                  (float)ulAccelTestPoint);

            if (ulNewValue > (pASMSourceInfo->m_ulMaxSubscribedBw * 4))
            {
                ulNewValue = (UINT32) 
                  (pASMSourceInfo->m_ulMaxSubscribedBw * 4);
            }

            /*
             * Live streams get capped at 107% of Max to prevent 
             * unneeded bandwidht modulation.
             */
            if ((pASMSourceInfo->m_pSource->IsLive()) &&
               (ulNewValue >
                  (pASMSourceInfo->m_ulMaxSubscribedBw * 1.07)))
            {
                ulNewValue = (UINT32)
                  (pASMSourceInfo->m_ulMaxSubscribedBw * 1.07);
            }

            if ((ulNewValue > (pASMSourceInfo->m_ulMaxSubscribedBw)) &&
                (ulNewValue > (ulSourceBandwidth * 3)) &&
                (pASMSourceInfo->m_ulLastSetDelivery <
                  pASMSourceInfo->m_ulMaxSubscribedBw))
            {
                /*
                 * If we are already accelerating 3x subscribed bandwidth
                 * and we are about to upshift beyond the max possible
                 * bandwidth, then let's stop and take a breather just
                 * above the max subscription.  This prevents us from
                 * buffering huge amounts of the crappy low bw stream.
                 */
                UINT32 ulTemp;
                ulTemp = (UINT32) 
                  (pASMSourceInfo->m_ulMaxSubscribedBw * 1.10);
                ulNewValue = MIN(ulTemp, ulNewValue);
            }

            if (pASMSourceInfo->m_ulLastSetDelivery >
                  pASMSourceInfo->m_ulMaxSubscribedBw)
            {
                bBrokeMax = TRUE;
            }

            if (pASMSourceInfo->m_bMayBeAccelerated &&
               (HXR_OK == pASMSourceInfo->m_pSource->
                QueryInterface(IID_IHXThinnableSource, (void **)&pThin)))
            {
                double Factor;

                if (bResistanceLimited)
                {
                  Factor = 1.005;
                }
                else if (pASMSourceInfo->m_pSource->IsLive())
                {
                  Factor = 1.01;
                }
                else
                {
                  Factor = 1.05;
                }

                if ((ulNewValue > (pASMSourceInfo->m_ulLastSetDelivery * Factor)) && 
                  pASMSourceInfo->m_bSourceAccelAllowed)
                {
                  DEBUG_OUT(m_pEM, DOL_TRANSPORT, 
                  (s, "(%p)Accelerating: NewTransmissionRate=%d", pASMSourceInfo->m_pSource, ulNewValue));

                  m_ulUpShiftPastResistanceCount = 0;

                  if (ulNewValue > ulSourceBandwidth)
                  {
                      pASMSourceInfo->m_pSource->LeaveBufferedPlay();
                  }

                  bDidChange = TRUE;

                  /*
                   * WHOA!  If this is a timestamp delivered source
                   * i.e. 5.0 thinning, then the imperical Getbandwidth()
                   * will never reach the rate that we set, so we help
                   * it along a bit (just a bit of a nudge, eh?).
                   */
                  if (pASMSourceInfo->m_bTimeStampDelivery)
                  {
                      pASMSourceInfo->m_ulIncomingBandwidth = ulNewValue;
                  }
                  m_ulNumReportsSinceUpShift = 0;
                  pASMSourceInfo->m_bInvalidUpReport = TRUE;
                  m_bDidOfferUpShiftToRecalc = FALSE;
                  pThin->SetDeliveryBandwidth(
                      (pASMSourceInfo->m_ulLastSetDelivery = ulNewValue), 0);
                }
            }
            HX_RELEASE(pThin);
          }
      }
      if ((bDidChange == TRUE) && (bWentHigherThanResistanceRate))
      {
          m_ulResistanceBitRate = (UINT32)(m_ulResistanceBitRate * dRFactor);
          DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
              "Went over ResistanceBitRate %d", m_ulResistanceBitRate));
      }
      if (((bDidChange == FALSE) &&
          (m_ulNumReportsSinceUpShift > NUM_REPORTS_NEEDED_TO_UPSHIFT) ||
          (bBrokeMax == TRUE)) && (m_bDidOfferUpShiftToRecalc == FALSE))
      {
          m_State = HX_NONE;
          m_bDidOfferUpShiftToRecalc = TRUE;
          m_ulOfferToRecalc = lAggregateBandwidthUsage;

#ifdef MOREDEBUG
          DEBUG_OUT(m_pEM, DOL_TRANSPORT, (s,
                  "Upshift Offer to Recalc() %d", m_ulOfferToRecalc));
#endif


          Recalc();
          return;
      }
    }
}

void
ASMStreamInfo::NotifyNewBandwidth()
{
    m_pNegotiator->SetBandwidthUsage(m_ulLastBandwidth,
      m_bTimeStampDelivery);
}

void
ASMStreamInfo::NotifyTimeStampDelivery()
{
    if(m_bTimeStampDelivery)
    {
      m_pASMSourceInfo->m_bTimeStampDelivery = TRUE;
    }
}

UINT32
ASMSourceInfo::GetBandwidth()
{
    return m_ulIncomingBandwidth;
}


void
ASMStreamInfo::SetLastBandwidth(UINT32 ulOffer)
{
    m_ulLastBandwidth = ulOffer;
}

void
ASMStreamInfo::NotifyLimitBandwidth(UINT32 ulRecv)
{
    if(m_pASMSourceInfo->m_bBehind)
    {
      m_pNegotiator->HandleSlowSource(ulRecv);
    }
}

ASMSourceInfo::ASMSourceInfo(HXSource* pSource, HXSM* pHXASM)
    : m_ulLastReportTime(0)
    , m_ulIncomingBandwidth(0)
    , m_ulRateBeforeDeAccel(0)
    , m_lTimeDiffBase(0)
    , m_ulBytesBehind(0)
    , m_lLastBehindTime(0)
    , m_ulLastSetDelivery(0xffffffff)
    , m_ulSubscribedBw(0)
    , m_ulMaxSubscribedBw(0)
    , m_bBehind(FALSE)
    , m_bLossBehind(FALSE)
    , m_bSlightlyBehind(FALSE)
    , m_bTimeStampDelivery(FALSE)
    , m_bPendingChill(FALSE)
    , m_bInvalidUpReport(FALSE)
    , m_bPerfectPlay(FALSE)
    , m_bIsDone(FALSE)
    , m_bMayBeAccelerated(TRUE)
    , m_bTryToUpShift(FALSE)
    , m_bAdjustBandwidth(FALSE)
    , m_ulLowestBandwidthBeforeTimeStamp(0)
    , m_bSourceAccelAllowed(TRUE)
    , m_bSourceDecelAllowed (TRUE)
    , m_bSlidingBwWindowReady(FALSE)
    , m_pMasterRuleBook(0)
    , m_pStreams(0)
    , m_TransportType(TNG_UDP)
    , m_pSource(pSource)
    , m_pSBI(0)
    , THRESHOLD(1000)
    , m_lRefCount(0)
    , m_ulBwDetectionDataCount(0)
    , m_ulBwDetectionDataLen(0)
    , m_ulSlidingWindowLocation(0)
    , m_pBwDetectionData(NULL)
    , m_pHXASM(pHXASM)
{
    m_lOuterThreshold = THRESHOLD;
    IHXValues* pHeader = 0;

    pSource->AddRef();

    if (pSource->m_pFileHeader)
    {
      IHXBuffer* pMasterRuleBook = NULL;
      pSource->m_pFileHeader->
          GetPropertyCString("ASMRuleBook", pMasterRuleBook);

      if (pMasterRuleBook)
      {
          m_pMasterRuleBook = new ASMRuleBook
            ((const char *)pMasterRuleBook->GetBuffer());
      }

      HX_RELEASE(pMasterRuleBook);
    }
}

ASMSourceInfo::~ASMSourceInfo()
{
    HX_VECTOR_DELETE(m_pBwDetectionData);
    delete[] m_pStreams;
    delete m_pMasterRuleBook;
}


BOOL
ASMSourceInfo::AllocBWDetectionData(UINT32 ulReqSize)
{
    BOOL bOk = TRUE;

    // Our current array is too small
    if (ulReqSize > m_ulBwDetectionDataLen)
    {
      BwDetectionData* pTemp = new BwDetectionData[ulReqSize];
      if (!pTemp)
      {
          bOk = FALSE;
      }
      else
      {
          if (m_pBwDetectionData)
          {
            memcpy(pTemp, m_pBwDetectionData, m_ulBwDetectionDataLen * sizeof(BwDetectionData)); /* Flawfinder: ignore */
            HX_VECTOR_DELETE(m_pBwDetectionData);
          }
          m_pBwDetectionData = pTemp;
          m_ulBwDetectionDataLen = ulReqSize;
      }
    }

    return bOk;
}


void
ASMSourceInfo::Done()
{
    HX_RELEASE(m_pSBI);
    HX_RELEASE(m_pSource);
    m_bIsDone     = TRUE;
}

STDMETHODIMP_(UINT32)
ASMSourceInfo::AddRef(void)
{
    return InterlockedIncrement(&m_lRefCount);
}

STDMETHODIMP_(UINT32)
ASMSourceInfo::Release(void)
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
      return m_lRefCount;
    }

    delete this;
    return 0;
}

STDMETHODIMP
ASMSourceInfo::QueryInterface
(
    REFIID interfaceID,
    void** ppInterfaceObj
)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)this },
            { GET_IIDHANDLE(IID_IHXBandwidthManagerInput), (IHXBandwidthManagerInput*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), interfaceID, ppInterfaceObj);
}


STDMETHODIMP
ASMSourceInfo::ReportDataPacket
(
    UINT32 ulTimeStamp,
    UINT32 ulArrivedTimeStamp,
    UINT32 ulSize
)
{
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    UINT32 ulCurrentTime = HX_GET_TICKCOUNT();
    if (!m_pHXASM->m_ulNextPacketWindow)
    {
      m_pHXASM->m_ulNextPacketWindow = ulCurrentTime;
    }

    if (ulSize == REPORT_DATA_PACKET_LOST)
    {
        ULONG32 ulNumLost = ulArrivedTimeStamp-ulTimeStamp+1;
      //XXXgfw Don't allow Decel if this is a load test.....
      if (m_bSourceDecelAllowed)
      {
            m_pHXASM->m_lLoss += ulNumLost;    
      }
        m_pHXASM->m_lPacketCounter += ulNumLost;
      return HXR_OK;
    }

    m_pHXASM->m_lPacketCounter++;

    // Make sure we have a buffer for bandwidth detection!
    if (!m_pBwDetectionData)
    {
      //XXXNH: SMP pulled these numbers out of his hat, so let's
      // stick with them for now.
      UINT32 uEstSize = m_TransportType == TNG_TCP ? 300 : 20;
      
      if (!AllocBWDetectionData(uEstSize))
          return HXR_OUTOFMEMORY;
    }

    if (CALCULATE_ELAPSED_TICKS(m_pHXASM->m_ulNextPacketWindow,
      ulCurrentTime) > 3000)
    {
      m_pHXASM->m_ulNextPacketWindow = ulCurrentTime;

      UINT32 ulLossPercentage = (UINT32)(
          100 * (float)m_pHXASM->m_lLoss / (float)m_pHXASM->m_lPacketCounter);

#ifdef MOREDEBUG
      DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, (s, "(%p)Loss %d", m_pSource, ulLossPercentage));
#endif

      /* Don't do anything unless we have 4% Loss */
      BOOL bDeAccel = (ulLossPercentage >= 4);

      /* Cut down bandwidth usage ONLY if it won't cause a downshift */
      bDeAccel = bDeAccel &&
            (m_ulLastSetDelivery * 0.95 > m_ulSubscribedBw);

      /* Don't throttle back if we're in chill acc buffering */
      bDeAccel = bDeAccel && (m_ulRateBeforeDeAccel == 0);

      /* If Loss is over 20%, always throttle back */
      bDeAccel = bDeAccel || (ulLossPercentage >= 20);

      if (bDeAccel)
      {
          if (ulLossPercentage >= 20)
          {
            /* 
             * make sure to never go into timestamp delivery/keyframe mode
             * due to loss
             */
              m_ulIncomingBandwidth = (UINT32) MAX(m_ulLastSetDelivery * 0.85, 
                        m_ulLowestBandwidthBeforeTimeStamp * 1.05);
          }
          else
          {
            if (ulLossPercentage > 15)
            {
                ulLossPercentage = 15;
            }
              
            // do not change subscription due to "less than 20% loss"
            m_ulIncomingBandwidth = (UINT32) MAX(m_ulLastSetDelivery *
                (1 - (ulLossPercentage / (float)100)),
                m_ulSubscribedBw * 1.05);
          }

            if (m_pSource->m_bFastStart)
            {
                DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, (s,"(%p)ASM %d - Leaving TurboPlay", m_pSource, __LINE__));
                m_pSource->LeaveFastStart(TP_OFF_BY_NETCONGESTION);
                if (m_ulIncomingBandwidth > m_ulMaxSubscribedBw * 1.05)
                {
                    m_ulIncomingBandwidth = m_ulMaxSubscribedBw * 1.05;
                }
            }

          m_bLossBehind = TRUE;
          DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, (s, "(%p)Lower Loss %d", m_pSource, m_ulIncomingBandwidth));
          /* Signal Recalc to adjust the highest available bandwidth */
          m_pHXASM->m_bPipeFull = TRUE;
          m_bBehind = TRUE;

          m_pHXASM->RecalcAccel();
          m_bBehind = FALSE;
          m_bLossBehind = FALSE;
      }
      else if (ulLossPercentage <= 1)
      {
          m_pHXASM->m_ulUpShiftPastResistanceCount++;
      }

      if (ulLossPercentage > 2)
      {
          m_pHXASM->m_ulUpShiftPastResistanceCount = 0;
      }

      m_pHXASM->m_lLoss = 0;
      m_pHXASM->m_lPacketCounter = 0;
    }

    if (m_bSlidingBwWindowReady)
    {
      //INT32 i;
      UINT32 ulPrevLocation = m_ulSlidingWindowLocation;

      /*
       *  Set the data for the current packet
       */
      m_pBwDetectionData[m_ulSlidingWindowLocation].
          m_ulSize          = ulSize;
      m_pBwDetectionData[m_ulSlidingWindowLocation].
          m_ulTimeStamp     = ulTimeStamp;
      m_pBwDetectionData[m_ulSlidingWindowLocation].
          m_ulATime         = ulArrivedTimeStamp;

      m_ulSlidingWindowLocation++;

      /*
       * wrap around if at the end
       */
      if (m_ulSlidingWindowLocation == m_ulBwDetectionDataCount)
      {
          m_ulSlidingWindowLocation = 0;
      }

      /*
       * count up all data for the whole window
       */
      //UINT32 ulWindowSize = 0;
      //for (i = 0; i < m_ulBwDetectionDataCount; i++)
      //{
      //    ulWindowSize += m_pBwDetectionData[i].m_ulSize;
      //}

      /*
       *  m_ulSlidingWindowLocation now points to the very first
       *  info in the window.  Take the diff in time from the data
       *  that we just entered (ulPrevLocation) and the time of the
       *  first data.
       */
      //UINT32 ulWindowRealTime = m_pBwDetectionData[ulPrevLocation].m_ulATime
      //    - m_pBwDetectionData[m_ulSlidingWindowLocation].m_ulATime;

      /*
       *  Calculate bandwidth for the window in bytes * 8 / millis.
       *  I have no idea why it is bytes * 8. //XXXPM?
       *  If we are in constant bitrate mode, then this calculated
       *  bitrate will be compared to the constant bitrate.  If we
       *  are not in constant bitrate mode, then this calculated
       *  bitrate will be compared to the bitrate coming from the
       *  bandwidth reports.
       */
      //m_ulLastBandwidthReport = (UINT32) (ulWindowSize * 8 /
      //    ((ulWindowRealTime) / 1000.0));

      // This is the short-term bandwidth count (sans buffering fudge)
    }
    else
    {
      m_pBwDetectionData[m_ulBwDetectionDataCount].
          m_ulSize          = ulSize;
      m_pBwDetectionData[m_ulBwDetectionDataCount].
          m_ulTimeStamp     = ulTimeStamp;
      m_pBwDetectionData[m_ulBwDetectionDataCount].
          m_ulATime         = ulArrivedTimeStamp;

      if(m_TransportType == TNG_TCP)
      {
          if(((m_pBwDetectionData[m_ulBwDetectionDataCount].m_ulTimeStamp -
            m_pBwDetectionData[0].m_ulTimeStamp > 30000) &&
            m_ulBwDetectionDataCount > 300))
          {
            m_bSlidingBwWindowReady = TRUE;
          }
      }
      else if(m_TransportType == TNG_UDP)
      {
          if (((((m_pBwDetectionData[m_ulBwDetectionDataCount].m_ulTimeStamp -
              m_pBwDetectionData[0].m_ulTimeStamp) > 3000) &&
              (m_ulBwDetectionDataCount > 20)) ||
             (m_pBwDetectionData[m_ulBwDetectionDataCount].m_ulATime -
              m_pBwDetectionData[0].m_ulATime > 3000)))
          // XXXSMP Re-examine this formula later.
          {
              m_bSlidingBwWindowReady = TRUE;
          }
      }
      if(!m_bSlidingBwWindowReady)  
      {
          m_ulBwDetectionDataCount++;

          // do we not have a big enough buffer for calculating bandwidth?
          if (m_ulBwDetectionDataCount >= m_ulBwDetectionDataLen)
          {
            // if we already have at least 1024 data points or we are 
            // out of memory then we'll just have to make do
            UINT32 ulNewSize = m_ulBwDetectionDataLen * 2;
            UINT32 ulMaxSize = min(BW_DETECTION_DATA_POINTS, ulNewSize);
            if (m_ulBwDetectionDataLen >= BW_DETECTION_DATA_POINTS ||
                !AllocBWDetectionData(ulMaxSize))
            {
                m_ulBwDetectionDataCount--;
                m_bSlidingBwWindowReady = TRUE;
            }
          }
      }
    }

    return HXR_OK;
}

UINT32
ASMSourceInfo::GetBandwidthSince(UINT32 ulTime,
                             UINT32 ulNow)
{
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    /*
     *  If we have not seen enough yet to get an idea.
     */
    if(!m_bSlidingBwWindowReady)
    {
      //XXXPM Hack this in to make TCP do small window calcs
      if(m_pBwDetectionData && m_TransportType == TNG_TCP &&
      (m_pBwDetectionData[m_ulBwDetectionDataCount].m_ulTimeStamp -
      m_pBwDetectionData[0].m_ulTimeStamp > 1000))
      {
          /* XXXPM, Disgusting */
          goto tcphackedin;
      }
      return 0;
    }
tcphackedin:

    UINT32 i;
    UINT32 sane = m_ulSlidingWindowLocation;
    UINT32 ulCount = 0;

    if(m_ulSlidingWindowLocation == 0)
    {
      i = m_ulBwDetectionDataCount - 1;
    }
    else
    {
      i = m_ulSlidingWindowLocation - 1;
    }

    UINT32 ulLastTime = ulNow;
    /*
     * add up the data size for all packets since ulTime
     */
    while(m_pBwDetectionData[i].m_ulATime > ulTime)
    { 
      ulCount += m_pBwDetectionData[i].m_ulSize;
      /*
       * remember the time of this packet so that we can calculate duration
       */
      ulLastTime = m_pBwDetectionData[i].m_ulATime; 
      if(i == 0)
      {
          i = m_ulBwDetectionDataCount - 1;
      }
      else
      {
          i--;
      }
      if(i == sane)
      {
          //XXXPM we have travelled all the way around the window
          //and still don't have enough.
          break;
      }
    }
    if (ulNow == ulLastTime)
    {
      return 0;
    }
    return (UINT32)((ulCount * 8) / ((ulNow - ulLastTime) / 1000.0));
}


STDMETHODIMP
ASMSourceInfo::ReportUpshiftInfo(UINT32 ulTimeStamp,
                             UINT32 ulSize)
{
    // In low heap mode, skip this because it causes the server to alter the
    // transmission rate. NOTE: technically this is the similar change in
    // ReportLatency should disable surestream stream switching, but in
    // testing this is not born out.
#if defined(HELIX_CONFIG_LOW_HEAP_STREAMING)
    return HXR_OK;
#endif
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    if (m_TransportType == TNG_TCP)
      return HXR_OK;

    m_pHXASM->UpShiftInfo(ulTimeStamp, ulSize);

    return HXR_OK;
}

void
HXSM::UpShiftInfo(UINT32 ulTimeStamp, UINT32 ulSize)
{
    UINT32 ulT = 1;
    UINT32 ulS = 0;

    m_ulUpShiftTimes[m_ulUpShiftRingPos] = ulTimeStamp;
    m_ulUpShiftSizes[m_ulUpShiftRingPos] = ulSize;
    m_ulUpShiftRingPos++;

    if (m_ulUpShiftRingPos == 5)
    {
      m_ulUpShiftRingPos = 0;
      m_bUpShiftInfoReady = TRUE;
    }

    if (m_bUpShiftInfoReady)
    {
      for (int i = 0; i < 5; i++)
      {
          /*
           * XXXSMP We should:
           * Weight each BackToBack timing by the size of the packet
           * it timed, because timing larger packets is more accurate.
           */
          ulT += m_ulUpShiftTimes[i];
          ulS += m_ulUpShiftSizes[i];
      }
    }

    if (ulT < 50)
    {
      ulT = (UINT32) (ulT * 1.2); // The clock is not very accurate.

      if (ulT > 50)
          ulT = 50;
    }

    if (m_bUpShiftInfoReady)
    {
      /* Use 5ms padding for good luck */
      m_ulUpShiftBandwidthAvail = ulS * 8000 / (ulT + 5);
    }
    else
    {
      /* Use 40-60ms padding if we are counting on one info item only */
      if (ulSize > 500)
          m_ulUpShiftBandwidthAvail = ulSize * 8000 / (ulTimeStamp + 40);
      else
          m_ulUpShiftBandwidthAvail = ulSize * 8000 / (ulTimeStamp + 60);
    }

    RecalcAccel();
}


HX_RESULT
ASMSourceInfo::ReportLatency(UINT32 ulServerTime,
                       UINT32 ulClientTime)
{
    // In low heap mode, skip this because it causes the server to alter the
    // transmission rate. NOTE: technically this is the similar change in
    // ReportUpShiftInfo should disable surestream stream switching, but in
    // testing this is not born out.
#if defined(HELIX_CONFIG_LOW_HEAP_STREAMING)
    return HXR_OK;
#endif
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    INT32 lBackedUp;

    lBackedUp = CalcBackup(ulServerTime, ulClientTime);
    INT32 lDetectedBandwidth;

    if(m_TransportType == TNG_UDP)
    {
      UINT32 ulTemp = MAX(800, 4000 - m_lOuterThreshold);
      UINT32 ulStartWindow = ulClientTime - ulTemp;

      lDetectedBandwidth = GetBandwidthSince(ulStartWindow, ulClientTime);
    }
    else
    {
      lDetectedBandwidth = GetBandwidthSince(ulClientTime -
                        TCP_BANDWIDTH_WINDOW, ulClientTime);
    }

    /*
     *  The THRESHOLD window is from THRESHOLD to m_lOuterThreshold.
     *  Once we go over threshold, we recalc the bandwidth and will do
     *  something to slow things down in m_pHXASM->Recalc.  We don't
     *  want to recalc the bandwidth again until we catch up to THRESHOLD
     *  or get slower again.  This is so that when we send one LimitBandwidth
     *  message we don't send another just when we are catching up (because
     *  sometimes during this time we can receive less and less data.)
     */

    //XXXgfw Don't allow Decel if this is a load test.....
    if ((lBackedUp >= (INT32)THRESHOLD) && (m_bSourceDecelAllowed))
    {
      /*
       *  If we are backed up over our threshold window, then resize the
       *  window and recalc our bandwidth.
       */
      if ((lBackedUp > m_lOuterThreshold) &&
          ((lDetectedBandwidth < (INT32)m_ulIncomingBandwidth) || 
            (!m_ulIncomingBandwidth)))
      {
          m_ulIncomingBandwidth = lDetectedBandwidth;
          /* Signal Recalc to adjust the highest available bandwidth */
          m_pHXASM->m_bPipeFull = TRUE;
          m_lOuterThreshold = lBackedUp + 500;
      }
      /*
       * This can either grow or shrink the threshold window.
       */
      m_bBehind = TRUE;
      m_bSlightlyBehind = TRUE;
    }
    else 
    {
      m_lOuterThreshold = THRESHOLD;
      m_bBehind = FALSE;

      UINT ulNew = 0;

      //XXXgfw Don't allow Decel if this is a load test.....
      if ((lBackedUp > 400) && (m_bSourceDecelAllowed))
          m_bSlightlyBehind = TRUE;
      else
      {
          m_bSlightlyBehind = FALSE;
          if (m_TransportType == TNG_TCP)
          {
            DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT,
                (s, "(%p)TCP Shift up = %d", m_pSource,
                m_pHXASM->m_ulUpShiftBandwidthAvail));
            m_pHXASM->m_ulUpShiftBandwidthAvail = MAX(
                m_pHXASM->m_ulUpShiftBandwidthAvail,
                (UINT32)(lDetectedBandwidth * 1.5));
          }
      }

      if (m_bInvalidUpReport)
      {
          m_bInvalidUpReport = FALSE;
          m_ulLastReportTime = ulClientTime;
          return HXR_OK;
      }

      UINT32 ulTemp = MAX(m_ulRateBeforeDeAccel, m_ulLastSetDelivery);
      if ((lDetectedBandwidth > (INT32)ulTemp) ||
          (!m_ulIncomingBandwidth))
          ulNew = ulTemp + 1;
      else
          ulNew = lDetectedBandwidth;

      if (ulNew > m_ulIncomingBandwidth)
      {
          m_ulIncomingBandwidth = ulNew;
      }
    }
    m_ulLastReportTime = ulClientTime;
    m_pHXASM->m_ulNumReportsSinceUpShift++;

    if (m_bPendingChill)
    {
      m_bPendingChill = FALSE;
      m_pHXASM->m_State = HXSM::CHILL_BUFFERING;
      m_pHXASM->RecalcAccel();

      IHXThinnableSource* pThin = NULL;

      if ((HXR_OK == m_pSource->
          QueryInterface(IID_IHXThinnableSource, (void **)&pThin)))
      {
          HX_ASSERT(m_ulSubscribedBw > 0);

          m_ulRateBeforeDeAccel = m_ulLastSetDelivery;

          UINT32 ulSet;

          if (m_ulIncomingBandwidth > m_ulMaxSubscribedBw)
          {
            ulSet = m_ulMaxSubscribedBw;
          }
          else
          {
            ulSet = (UINT32)(m_ulSubscribedBw * 0.75);
          }

          DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, 
            (s, "(%p)Acceleration Buffer Full: NewTransmissionRate=%d %p", m_pSource,
                ulSet, this));

          pThin->SetDeliveryBandwidth((m_ulLastSetDelivery = ulSet), 0);
      }
      HX_RELEASE(pThin);
    }
    else
      m_pHXASM->RecalcAccel();

    return HXR_OK;
}

INT32
ASMSourceInfo::CalcBackup(UINT32 ulServerTime, UINT32 ulClientTime)
{

    INT32 lNewDiff = ulClientTime - ulServerTime;

    /* 
     *  If this is the first time we will have no idea of the base
     *  time diff.
     */
    if(!m_lTimeDiffBase)
    {       
      m_lTimeDiffBase = lNewDiff;
      return 0;
    }

    /*
     * If our difference got shorter than before then this is the new base
     * and our backup is 0
     */
    if(lNewDiff < m_lTimeDiffBase)
    {
      m_lTimeDiffBase = lNewDiff;
      return 0;
    }

    if (m_lLastBehindTime)
    {
      if (((INT32)m_ulBytesBehind +
          ((lNewDiff - m_lTimeDiffBase) - m_lLastBehindTime) * 
          (INT32)m_ulLastSetDelivery / 8000) > 0)
      {
          m_ulBytesBehind +=
          ((lNewDiff - m_lTimeDiffBase) - m_lLastBehindTime) * 
          (INT32)m_ulLastSetDelivery / 8000;
      }
      else
      {
          m_ulBytesBehind = 0;
      }
    }
    m_lLastBehindTime = lNewDiff - m_lTimeDiffBase;

    DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT_EXTENDED, 
          (s, "(%p)Terminal Buffer Report: Behind by %dms (%d bytes)", m_pSource,
          lNewDiff - m_lTimeDiffBase, m_ulBytesBehind));

    return lNewDiff - m_lTimeDiffBase;
}

STDMETHODIMP
ASMSourceInfo::SetCongestionFactor(UINT32 ulFactor)
{
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    return HXR_OK;
}


void    
ASMSourceInfo::ChangeAccelerationStatus(BOOL       bMayBeAccelerated,
                              BOOL     bUseAccelerationFactor,
                              UINT32         ulAccelerationFactor)
{
    if (m_bMayBeAccelerated == FALSE && bMayBeAccelerated == FALSE)
    {
      DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, 
            (s, "(%p)Acceleration Buffer Way Full: Factor=%d", m_pSource, ulAccelerationFactor));
      HX_ASSERT(bUseAccelerationFactor);

      UINT32 ulNewRate = m_ulSubscribedBw * ulAccelerationFactor / 100;

      IHXThinnableSource* pThin = NULL;

      if (HXR_OK == m_pSource->
          QueryInterface(IID_IHXThinnableSource, (void **)&pThin))
      {
          pThin->SetDeliveryBandwidth((m_ulLastSetDelivery = ulNewRate), 0);
      }
      HX_RELEASE(pThin);

      return;
    }

    m_bMayBeAccelerated = bMayBeAccelerated;

    if (!m_bMayBeAccelerated && (m_ulLastSetDelivery > m_ulSubscribedBw))
    {
      m_bPendingChill = TRUE;
    }
    else if (m_bMayBeAccelerated && m_ulRateBeforeDeAccel)
    {
      IHXThinnableSource* pThin = NULL;

      if (HXR_OK == m_pSource->
          QueryInterface(IID_IHXThinnableSource, (void **)&pThin))
      {
          /* Only attempt conservative restart on LBR sources */
          if (m_ulRateBeforeDeAccel < 150000)
          {
            /* Can we be conservative when switching back up? */
            if ((m_ulRateBeforeDeAccel * 0.50) > m_ulSubscribedBw)
            {
                /* Yes, be really conservative */
                m_ulRateBeforeDeAccel = (UINT32)
                    (m_ulRateBeforeDeAccel * 0.70);
            }
            else if ((m_ulRateBeforeDeAccel * 0.70) > m_ulSubscribedBw)
            {
                /* Be somewhat conservative */
                m_ulRateBeforeDeAccel = (UINT32)
                    (m_ulRateBeforeDeAccel * 0.85);
            }
          }

          DEBUG_OUT(m_pHXASM->m_pEM, DOL_TRANSPORT, 
            (s, "(%p)Acceleration Buffer at 50%: NewTransmissionRate=%d", m_pSource, m_ulRateBeforeDeAccel));

          pThin->SetDeliveryBandwidth(
            (m_ulLastSetDelivery = (UINT32) (m_ulRateBeforeDeAccel)), 0);
          m_ulRateBeforeDeAccel = 0;
      }
      HX_RELEASE(pThin);
    }
}

STDMETHODIMP
ASMSourceInfo::SetTransportType(TRANSPORT_TYPE type)
{
    if (m_bIsDone)
    {
      return HXR_OK;
    }

    m_TransportType = type;

    if (m_TransportType == TNG_TCP)
    {
      THRESHOLD = 5000;
      m_lOuterThreshold = 5000;
    }

    return HXR_OK;
}




ASMStreamInfo::ASMStreamInfo() :
    m_pNegotiator(0),
    m_pBias(0),
    m_pRuleGather(0),
    m_ulFixedBandwidth(0),
    m_ulLastBandwidth(0),
    m_bTimeStampDelivery(FALSE),
    m_ulNumThresholds(0),
    m_ulThresholdPosition(0),
    m_ulResistanceToLower(0),
    m_ulOffer(0),
    m_pThreshold(NULL),
    m_ulMaxEffectiveThreshold(-1),
    m_ulStreamNumber(0)
{
}

ASMStreamInfo::~ASMStreamInfo()
{
    HX_VECTOR_DELETE(m_pThreshold);
    HX_RELEASE(m_pNegotiator);
    HX_RELEASE(m_pBias);
    HX_RELEASE(m_pRuleGather);
}

Generated by  Doxygen 1.6.0   Back to index