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

hxsrc.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxsrc.cpp,v 1.35.2.1 2004/07/09 02:05:58 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 ***** */

#include "hxtypes.h"
#include "hxcom.h"
#ifdef _WINDOWS
#include <windows.h>
#endif

#include "hlxclib/stdio.h"
#include "hlxclib/stdlib.h"
#include "prefdefs.h"
#include "plprefk.h"
#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxengin.h"
#include "hxcore.h"
#include "hxprefs.h"
#include "hxpref.h"
#include "hxausvc.h"
#include "hxmon.h"
#include "hxclreg.h"
#include "hxgroup.h"
#include "hxsmbw.h"
#include "hxstrm.h"
#include "hxwin.h"


#include "hxcore.h"
#include "hxhyper.h"
#include "playhpnv.h"
#include "hxplugn.h"
#include "hxrendr.h"

#include "chxeven.h"
#include "chxelst.h"
#include "hxmap.h"
#include "hxrquest.h"
#include "hxmangle.h"
#include "hxtick.h"
#include "dbcs.h"

#include "hxstrutl.h"
#include "strminfo.h"
#include "timeval.h"
#include "statsmgr.h"
#include "hxbsrc.h"
#include "hxsrc.h"
#include "srcinfo.h"
#include "corshare.h"
#include "upgrdcol.h"
#include "hxrasyn.h"
#include "hxaudstr.h"
#include "hxplugn.h"
#include "hxrendr.h"
#include "errdbg.h"

// will be taken out once flags are defined in a separate file
#include "rmfftype.h"   
#include "hxplay.h"
#include "hxcleng.h"
#include "hxsrc.h"

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE           
static const char HX_THIS_FILE[] = __FILE__;
#endif

#if defined(HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES)
// TurboPlay should never be turned on in low heap mode, but just in case ...
#define TURBO_AUDIO_PUSHDOWN 100
#else
#define TURBO_AUDIO_PUSHDOWN 2000
#endif

HXSource::HXSource() :
        m_pPlayer (0)
      , m_lRefCount(0)
      , m_ulStreamIndex(0)
      , m_bInitialized (FALSE)
      , m_bIsPreBufferingDone(FALSE)
      , m_bClipTimeAdjusted(FALSE)
      , mLastError (HXR_OK)
      , m_ulPerfectPlayTime (0)
      , m_ulBufferedPlayTime(0)
        , m_ulStreamHeadersExpected(0)
      , m_bPerfectPlayEntireClip(FALSE)
      , m_bCannotBufferEntireClip(FALSE)
      , m_uNumStreams (0)
      , mFlags (0)
      , m_bPerfectPlayAllowed (FALSE)
      , mSaveAsAllowed (FALSE)
      , mLiveStream (FALSE)
      , m_bRestrictedLiveStream (FALSE)
      , m_bSourceEnd (FALSE)
      , m_bForcedSourceEnd(FALSE)
      , m_ulPreRollInMs (0)
      , m_ulPreRoll (0)
      , m_ulAvgBandwidth (0)
      , m_ulDuration (0)
      , m_bReceivedData (FALSE)
      , m_bReceivedHeader(FALSE)
      , m_bNonSeekable(FALSE)

      , m_nSeeking (0)
      , m_bPaused (FALSE)  
      , m_bFirstResume(TRUE)
      , m_bResumePending(FALSE)
      , m_bIsActive(FALSE)

      , m_uActiveStreams (0)

      , m_pszURL(NULL)
      , m_pURL(NULL)
      , m_bAltURL(TRUE)

      , m_ulStartTime (0)
      , m_ulEndTime (0)
      , m_ulDelay (0)
      , m_ulOriginalDelay (0)
      , m_ulPrefetchDelay (0)
      , m_llLastExpectedPacketTime(0)
      , m_ulRestrictedDuration(0)
      , m_bDelayed(FALSE)

      , m_ulSourceStartTime(0)
      , m_pPreferences (0)
      , m_pRegistry (0)
      , m_pScheduler (0)
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
      , m_pStats (0)
      , m_pStatsManager(NULL)
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
      , m_bLocked (FALSE)
      , m_pEngine (0)
      , m_bRebufferingRequired(FALSE)
      , m_bInitialBuffering(TRUE)
      , m_bPartOfNextGroup(FALSE)
      , m_bPartOfPrefetchGroup(FALSE)
      , m_pBufferManager(NULL)
      , m_pFileHeader(0)
      , m_bPerfectPlay(FALSE)
      , m_bBufferedPlay(FALSE)
      , m_ulLossHack(0)
      , m_ulNumFakeLostPackets(0)
      , m_ulLastBufferingCalcTime(0)
      , m_pSourceInfo(NULL)
      , m_pRequest(NULL)
      , m_pASMSource(NULL)
      , m_pBackChannel(NULL)
      , m_bDefaultAltURL(FALSE)
      , m_bCustomEndTime(FALSE)     
      , m_bCustomDuration(FALSE)
      , m_bIsPreBufferingStarted(FALSE)
      , m_ulOriginalDuration(0)
      , m_bReSetup(FALSE)
#if defined(HELIX_FEATURE_AUTOUPGRADE)
      , m_pUpgradeCollection(NULL)
#endif /* HELIX_FEATURE_AUTOUPGRADE */
      , m_bRTSPRuleFlagWorkAround(FALSE)
        , m_bContinueWithHeaders(FALSE)
      , m_bPrefetch(FALSE)
      , m_prefetchType(PrefetchUnknown)
      , m_ulPrefetchValue(0)
      , m_ulFirstPacketTime(0)
      , m_bIsMeta(FALSE)
      , m_bFastStart(FALSE)
      , m_serverTurboPlay(TURBO_PLAY_UNKNOWN)
      , m_ulMaxBandwidth(4000)      // 4000kbps
      , m_pAudioStreamList(NULL)
        , m_maxPossibleAccelRatio(4.0)    // I donno what's a good value?
        , m_ulTurboPushDown(TURBO_AUDIO_PUSHDOWN)
        , m_bSureStreamClip(FALSE)
        , m_ulTurboStartActiveTime(0)
      , m_srcEndCode(END_UNKNOWN)
      , m_pRecordControl(NULL)
      , m_bPlayFromRecordControl(FALSE)
        , m_pRedirectURL(NULL)
        , m_bRedirectPending(FALSE)
{
    mStreamInfoTable = new CHXMapLongToObj;
}

HXSource::~HXSource()
{
    // XXX moved this to the distuctor because we want to keep arround
    // the request until the renderers are close at which point we should
    // be released and deleted.
    HX_RELEASE(m_pRequest);
    HX_VECTOR_DELETE(m_pszURL);
    HX_DELETE(mStreamInfoTable);
}

void
HXSource::Stop()
{
    m_pSourceInfo = NULL;    

    HX_DELETE (m_pURL);
    HX_DELETE (m_pBufferManager);

    if ( FAILED(mLastError) )
    {
      HX_RELEASE(m_pRequest);
    }

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    if (m_pStatsManager)
    {
      m_pStatsManager->DoCleanup();
      HX_RELEASE(m_pStatsManager);
    }        
    HX_DELETE(m_pStats);    
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    DeleteAllEvents(); 

    HX_RELEASE(m_pRegistry);
    HX_RELEASE(m_pPreferences);
    HX_RELEASE(m_pScheduler);
    HX_RELEASE(m_pEngine);
}    

HX_RESULT HXSource::DoCleanup(EndCode endCode)
{
    m_ulDuration = 0;    
    m_ulPreRollInMs = 0;
    m_ulPreRoll = 0;
    m_ulAvgBandwidth = 0;
    m_ulLastBufferingCalcTime = 0;

    m_ulMaxBandwidth = 0;
    m_serverTurboPlay = TURBO_PLAY_UNKNOWN;

    m_bAltURL = FALSE;    
    m_bPaused = FALSE;
    m_bFirstResume = TRUE;
    m_bIsActive = FALSE;
    m_bResumePending = FALSE;
    m_bIsPreBufferingStarted = FALSE;
    m_bIsPreBufferingDone = FALSE;    
    m_bClipTimeAdjusted = FALSE;    
    m_bInitialBuffering = TRUE;
    m_bRebufferingRequired = FALSE;    
    m_bReceivedData = FALSE;
    m_bReceivedHeader = FALSE;

    ReleaseAudioStreams(m_pAudioStreamList);
    HX_DELETE(m_pAudioStreamList);

    DeleteStreamTable();

    CHXSimpleList::Iterator lIter = m_HXStreamList.Begin();
    for (; lIter != m_HXStreamList.End(); ++lIter)
    {
      HXStream* pStream = (HXStream*) (*lIter);
      pStream->Release();
    }

    m_HXStreamList.RemoveAll();    

    HX_RELEASE(m_pFileHeader);    
    HX_RELEASE(m_pASMSource);
    HX_RELEASE(m_pBackChannel);
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    HX_RELEASE(m_pUpgradeCollection);
#endif /* HELIX_FEATURE_AUTOUPGRADE */

    m_bForcedSourceEnd  = FALSE;
    m_bSourceEnd  = FALSE;

    HX_DELETE(m_pRedirectURL);
    m_bRedirectPending  = FALSE;

#if defined(HELIX_FEATURE_RECORDCONTROL)
    if(m_pRecordControl)
    {
      m_pRecordControl->Cleanup();
    }
#endif /* HELIX_FEATURE_RECORDCONTROL */
    HX_RELEASE(m_pRecordControl);

    return HXR_OK;
}

/////////////////////////////////////////////////////////////////////////
//    Method:
//          IUnknown::QueryInterface
//    Purpose:
//          Implement this to export the interfaces supported by your 
//          object.
//
STDMETHODIMP HXSource::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXStreamSource), (IHXStreamSource*)this },
            { GET_IIDHANDLE(IID_IHXPendingStatus), (IHXPendingStatus*)this },
            { GET_IIDHANDLE(IID_IHXInfoLogger), (IHXInfoLogger*)this },
            { GET_IIDHANDLE(IID_IHXPrivateStreamSource), (IHXPrivateStreamSource*)this },
            { GET_IIDHANDLE(IID_IHXSourceBufferingStats), (IHXSourceBufferingStats*)this },
            { GET_IIDHANDLE(IID_IHXSourceBufferingStats2), (IHXSourceBufferingStats2*)this },
#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
            { GET_IIDHANDLE(IID_IHXHyperNavigate), (IHXHyperNavigate*)this },
            { GET_IIDHANDLE(IID_IHXHyperNavigate2), (IHXHyperNavigate2*)this },
#endif /* defined(HELIX_FEATURE_HYPER_NAVIGATE) */
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXStreamSource*)this },
        };
    
    HX_RESULT res = ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
    
    // if successful, return immediately...
    if (SUCCEEDED(res))
    {
        return res;
    }
    // ... otherwise proceed onward
    
    if (IsEqualIID(riid, IID_IHXBackChannel))
    {
      if (m_pBackChannel)
      {
          AddRef();
          *ppvObj = (IHXBackChannel*)this;
          return HXR_OK;
      }
      else
      {
          *ppvObj = NULL;
          return HXR_NOINTERFACE;
      }
    }
    else if (IsEqualIID(riid, IID_IHXASMSource))
    {
      if (m_pASMSource)
      {
          AddRef();
          *ppvObj = (IHXASMSource*)this;
          return HXR_OK;
      }
      else
      {
          *ppvObj = NULL;
          return HXR_NOINTERFACE;
      }
    }

#if defined(HELIX_FEATURE_AUTOUPGRADE)
    else if (IsEqualIID(riid, IID_IHXUpgradeCollection))
    {
      if (!m_pUpgradeCollection)
      {
          m_pUpgradeCollection = new HXUpgradeCollection;
          m_pUpgradeCollection->AddRef();
      }

      return m_pUpgradeCollection->QueryInterface(riid, ppvObj);
    }
#endif /* HELIX_FEATURE_AUTOUPGRADE */
    else if (m_pRequest &&
      m_pRequest->QueryInterface(riid, ppvObj) == HXR_OK)
    {
      return HXR_OK;
    }
    else if (m_pFileHeader &&
      m_pFileHeader->QueryInterface(riid, ppvObj) == HXR_OK)
    {
      return HXR_OK;
    }

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

/////////////////////////////////////////////////////////////////////////
//    Method:
//          IUnknown::AddRef
//    Purpose:
//          Everyone usually implements this the same... feel free to use
//          this implementation.
//
STDMETHODIMP_(ULONG32) HXSource::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

/////////////////////////////////////////////////////////////////////////
//    Method:
//          IUnknown::Release
//    Purpose:
//          Everyone usually implements this the same... feel free to use
//          this implementation.
//
STDMETHODIMP_(ULONG32) HXSource::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
      return m_lRefCount;
    }

    delete this;
    return 0;
}

// *** IHXStreamSource methods ***

/************************************************************************
 *    Method:
 *          IHXStreamSource::IsLive
 *    Purpose:
 *          Ask the source whether it is live
 *
 */
STDMETHODIMP_ (BOOL) HXSource::IsLive(void)
{
    return mLiveStream;
}

/************************************************************************
 *    Method:
 *        IHXStreamSource::GetPlayer
 *    Purpose:
 *        Get the interface to the player object of which the source is
 *        a part of.
 *
 */
STDMETHODIMP HXSource::GetPlayer(IHXPlayer* &pPlayer)
{
    pPlayer = m_pPlayer;
    if (pPlayer)
    {
      pPlayer->AddRef();
    }

    return HXR_OK;
}

/************************************************************************
 *    Method:
 *        IHXStreamSource::GetContext
 *    Purpose:
 *        Get the interface to the context object of which the source is
 *        a part of.
 *
 */
STDMETHODIMP HXSource::GetContext(IUnknown* &pContext)
{
    pContext = ((IUnknown*)(IHXClientEngine*) m_pEngine);
    if (pContext)
    {
      pContext->AddRef();
    }

    return HXR_OK;
}

/************************************************************************
 *    Method:
 *        IHXStreamSource::GetURL
 *    Purpose:
 *        Get the URL for this source. NOTE: The returned string is
 *        assumed to be valid for the life of the IHXStreamSource from which it
 *        was returned.
 *
 */
STDMETHODIMP_(const char*) HXSource::GetURL(void)
{
    const char* pURL = NULL;

    /* 
     * Make sure that the we have not been re-directed
     * to a new URL.
     */ 
    if (m_pRequest && 
      m_pRequest->GetURL(pURL) == HXR_OK &&
      pURL)
    {
      if (!m_pszURL ||
          ::strcasecmp(pURL, m_pszURL) != 0)
      {
          HX_VECTOR_DELETE(m_pszURL);
          m_pszURL = new char[strlen(pURL) + 1];
          strcpy(m_pszURL, pURL); /* Flawfinder: ignore */
      }
    }

    // append RAM mimeType as URL option to notify the
    // caller(i.e. ViewSource)
    if (m_bIsMeta)
    {
      char* pszTemp = NULL;

      pszTemp = ::HXFindChar(m_pszURL, '?');
      if (pszTemp)
      {
            int lenTemp = strlen(m_pszURL) + strlen("&mimeType=") + strlen(RAM_MIMETYPE) + 1;
          pszTemp = new char[lenTemp];
          SafeSprintf(pszTemp, lenTemp, "%s%s%s", m_pszURL, "&mimeType=", RAM_MIMETYPE); /* Flawfinder: ignore */
      }
      else
      {
            int lenTemp = strlen(m_pszURL) + strlen("?mimeType=") + strlen(RAM_MIMETYPE) + 1;
          pszTemp = new char[lenTemp];
          SafeSprintf(pszTemp, lenTemp, "%s%s%s", m_pszURL, "?mimeType=", RAM_MIMETYPE); /* Flawfinder: ignore */
      }

      HX_VECTOR_DELETE(m_pszURL);
      m_pszURL = pszTemp;
    }

    return m_pszURL;
}


/************************************************************************
 *    Method:
 *        IHXStreamSource::GetStreamCount
 *    Purpose:
 *        Get the number of streams in this source
 *
 */
STDMETHODIMP_(UINT16)
HXSource::GetStreamCount()
{
    return m_HXStreamList.GetCount();
}


/************************************************************************
 *    Method:
 *        IHXStreamSource::GetStream
 *    Purpose:
 *        Get the stream with the given index.
 *    Note: 
 *        Since stream numbers may not be zero based, stream index is not
 *        equal to the stream number. Actual stream number may be determined 
 *        from IHXStream::GetStreamNumber()
 *
 */
STDMETHODIMP
HXSource::GetStream
(
    UINT16 nIndex,
    REF(IUnknown*) pUnknown
)
{
    LISTPOSITION lPosition = m_HXStreamList.FindIndex((int) nIndex);
    if (!lPosition)
    {
      pUnknown = NULL;
      return HXR_INVALID_PARAMETER;
    }

    HXStream* pStream = (HXStream*) m_HXStreamList.GetAt(lPosition);
    HX_ASSERT(pStream);

    return pStream->QueryInterface(IID_IUnknown,(void**)&pUnknown);
}


// IHXPrivateStreamSource methods 
STDMETHODIMP_(BOOL) HXSource::IsSaveAllowed()
{
    return mSaveAsAllowed;
}


/*
 * IHXBackChannel method
 */

/************************************************************************
 *    Method:
 *        IHXBackChannel::PacketReady
 *    Purpose:
 *      A back channel packet sent from Renderer to FileFormat plugin.
 */
STDMETHODIMP
HXSource::PacketReady(IHXPacket* pPacket)
{
    HX_ASSERT(m_pBackChannel);

    if (m_pBackChannel)
    {
      return m_pBackChannel->PacketReady(pPacket);
    }

    return HXR_FAIL;
}


/*
 * IHXASMSource methods
 */

/************************************************************************
 *    Method:
 *        IHXASMSource::Subscribe
 *    Purpose:
 *      Called to inform a file format that a subscription has occurred,
 *        to rule number uRuleNumber, for stream uStreamNumber.
 */
STDMETHODIMP
HXSource::Subscribe(UINT16    uStreamNumber,
                 UINT16 uRuleNumber)
{
    HX_ASSERT(m_pASMSource);

    if (m_pASMSource)
    {
      return m_pASMSource->Subscribe(uStreamNumber, uRuleNumber);
    }

    return HXR_FAIL;
}

/************************************************************************
 *    Method:
 *        IHXASMSource::Unsubscribe
 *    Purpose:
 *      Called to inform a file format that a unsubscription has occurred,
 *        to rule number uRuleNumber, for stream uStreamNumber.
 */
STDMETHODIMP
HXSource::Unsubscribe(UINT16  uStreamNumber,
                   UINT16     uRuleNumber)
{
    HX_ASSERT(m_pASMSource);

    if (m_pASMSource)
    {
      return m_pASMSource->Unsubscribe(uStreamNumber, uRuleNumber);
    }

    return HXR_FAIL;
}

void  
HXSource::AddHXStream(HXStream* pStream)
{
    pStream->AddRef();
    m_HXStreamList.AddTail(pStream);

    UINT16 uStreamNumber = pStream->GetStreamNumber();
    STREAM_INFO* pStreamInfo;
    if (mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void*& )pStreamInfo))
    {
      pStreamInfo->m_pStream = pStream;
      pStreamInfo->m_pStream->AddRef();

      pStreamInfo->BufferingState().OnStream((IHXStream*)pStream);
    }
}

HX_RESULT
HXSource::CollectAudioStreams(CHXSimpleList*& pAudioStreamList)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT         rc = HXR_OK;
    UINT16      i = 0;
    UINT16      uNumAudioStreams = 0;
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXAudioStream* pCHXAudioStream = NULL;
    IHXValues*        pHeader = NULL;

    pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    uNumAudioStreams = pAudioPlayer->GetAudioStreamCount();
    for (i = 0; i < uNumAudioStreams; i++)
    {
      pCHXAudioStream = pAudioPlayer->GetCHXAudioStream(i);
      pCHXAudioStream->AddRef();

      pHeader = ((IHXAudioStream*)pCHXAudioStream)->GetStreamInfo();

      if (pHeader &&
          IsAudioStreamFromThisSource(pHeader))
      {
          if (!pAudioStreamList)
          {
            pAudioStreamList = new CHXSimpleList();
          }

          pAudioStreamList->AddTail(pCHXAudioStream);
      }
      else
      {
          HX_RELEASE(pCHXAudioStream);
      }
      HX_RELEASE(pHeader);    
    }

cleanup:

    if (!pAudioStreamList)
    {  
      rc = HXR_FAILED;
    }

    return rc;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */
}

void        
HXSource::RemoveAudioStreams(void)
{    
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXSimpleList*  pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer->AddRef();

    if (HXR_OK == CollectAudioStreams(pAudioStreamList) && pAudioStreamList)
    {
      pAudioPlayer->ManageAudioStreams(pAudioStreamList, CHXAudioPlayer::STR_REMOVE);

      ReleaseAudioStreams(pAudioStreamList);
      HX_DELETE(pAudioStreamList);
    }

    HX_RELEASE(pAudioPlayer);

cleanup:
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */

    return;
}

void
HXSource::PauseAudioStreams(void)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXSimpleList*  pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer->AddRef();

    if (HXR_OK == CollectAudioStreams(pAudioStreamList) && pAudioStreamList)
    {
      pAudioPlayer->ManageAudioStreams(pAudioStreamList, CHXAudioPlayer::STR_PAUSE);

      ReleaseAudioStreams(pAudioStreamList);
      HX_DELETE(pAudioStreamList);
    }

    HX_RELEASE(pAudioPlayer);

cleanup:
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */

    return;
}

void
HXSource::ResumeAudioStreams(void)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXSimpleList*  pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer->AddRef();

    if (HXR_OK == CollectAudioStreams(pAudioStreamList) && pAudioStreamList)
    {
      pAudioPlayer->ManageAudioStreams(pAudioStreamList, CHXAudioPlayer::STR_RESUME);

      ReleaseAudioStreams(pAudioStreamList);
      HX_DELETE(pAudioStreamList);
    }

    HX_RELEASE(pAudioPlayer);

cleanup:
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */

    return;
}

void
HXSource::ReleaseAudioStreams(CHXSimpleList* pAudioStreamList)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    if (pAudioStreamList && !pAudioStreamList->IsEmpty())
    {
      CHXSimpleList::Iterator lIter = pAudioStreamList->Begin();
      for (; lIter != pAudioStreamList->End(); ++lIter)
      {
          CHXAudioStream* pAudioStream = (CHXAudioStream*) (*lIter);
          HX_RELEASE(pAudioStream);
      }
    }
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */

    return;
}

HX_RESULT HXSource::Init(HXPlayer * pPlayer, UINT32 unRegistryID)
{
    HX_RESULT     theErr = HXR_OK;
   
    m_pPlayer = pPlayer;
    if (m_pPlayer->QueryInterface(IID_IHXPreferences, (void **) &m_pPreferences) != HXR_OK)
    {
      theErr = HXR_INVALID_PARAMETER;     //HX_INVALID_INTERFACE;
    }

    m_pBufferManager = new CBufferManager(this);
    if(!m_pBufferManager)
    {
        theErr = HXR_OUTOFMEMORY;
    }

    // create registry entries
    if (HXR_OK != m_pPlayer->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry))
    {
      m_pRegistry = NULL;
    }
    else
    {
      m_ulRegistryID = unRegistryID;
    }

    if (!theErr &&
      m_pPlayer->QueryInterface(IID_IHXScheduler, (void **) &m_pScheduler) != HXR_OK)
    {
      theErr = HXR_INVALID_PARAMETER;     //HX_INVALID_INTERFACE;
    }

    IHXPreferences* pPref = NULL;

    m_pPlayer->QueryInterface(IID_IHXPreferences, (void**)&pPref);
    if (HXR_OK == ReadPrefINT32(pPref, "TurboPushdown", m_ulTurboPushDown))
    {
      m_ulTurboPushDown = (m_ulTurboPushDown / 100) * 100;  // round to multiple of 100
    }
    HX_RELEASE(pPref);

    m_pEngine = m_pPlayer->m_pEngine;
    m_pEngine->AddRef();

    return theErr;
}

HX_RESULT HXSource::SetupRegistry()
{
    HX_RESULT     theErr = HXR_OK;
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    UINT32  ulRepeatedRegistryID = 0;
    IHXBuffer*    pRepeatRegName = NULL;
    char        szSourceName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */

    HX_ASSERT(m_pSourceInfo);    

    if (m_pSourceInfo->m_bLeadingSource &&
      !m_pSourceInfo->m_pRepeatList)
    {
      m_pStats = new SOURCE_STATS(m_pRegistry, m_ulRegistryID);
    }
    else if (m_pRegistry && 
          HXR_OK == m_pRegistry->GetPropName(m_pPlayer->m_ulRepeatedRegistryID, pRepeatRegName))
    {
      SafeSprintf(szSourceName, MAX_DISPLAY_NAME, "%s.%ld%ld%ld", 
            pRepeatRegName->GetBuffer(),
            m_pSourceInfo->m_uGroupID,
            m_pSourceInfo->m_uTrackID,
            (int)m_pSourceInfo->m_bLeadingSource);
    
      ulRepeatedRegistryID = m_pRegistry->GetId(szSourceName);
      if (!ulRepeatedRegistryID)
      {
          ulRepeatedRegistryID = m_pRegistry->AddComp(szSourceName);
      }

      m_pStatsManager = new StatsManager(m_pRegistry, m_ulRegistryID, ulRepeatedRegistryID);
      m_pStatsManager->AddRef();

      m_pStats = new SOURCE_STATS(m_pRegistry, ulRepeatedRegistryID);
        if( !m_pStats )
        {
            theErr = HXR_OUTOFMEMORY;
        }
    }
    else
    {
      // why stats' creation failed??
      HX_ASSERT(FALSE);
    }

    HX_RELEASE(pRepeatRegName);
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    return theErr;
}

HX_RESULT HXSource::ReadPreferences(void)
{
    UINT32      un16Temp = 10;

    ReadPrefINT32(m_pPreferences, "PerfectPlayTime", un16Temp); 
    m_ulPerfectPlayTime = un16Temp;

    ReadPrefINT32(m_pPreferences, "BufferedPlayTime", un16Temp);
    m_ulBufferedPlayTime = un16Temp;

    ReadPrefBOOL(m_pPreferences, "PerfPlayEntireClip", m_bPerfectPlayEntireClip); 

    return HXR_OK;
}


HX_RESULT HXSource::DeleteStreamTable(void)
{
    HX_RESULT theErr = HXR_OK;

    STREAM_INFO   * sInfo = NULL;
      
    for (CHXMapLongToObj::Iterator i = mStreamInfoTable->Begin();
         i != mStreamInfoTable->End(); ++i) 
    {    
      sInfo = (STREAM_INFO*) (*i);
      
      if (sInfo)
      {
          HX_DELETE (sInfo);
      }
    }

    mStreamInfoTable->RemoveAll();
    m_ulStreamIndex = 0;
    m_uNumStreams = 0;
    
    return theErr;
}     


IHXValues* HXSource::GetHeaderInfo(UINT16 stream_number)
{
    STREAM_INFO   * pStreamInfo;
    if (mStreamInfoTable->Lookup((LONG32) stream_number, (void*& )pStreamInfo))
    {
      return pStreamInfo->m_pHeader;
    }
    else
    {
      return NULL;
    }
}

HX_RESULT   
HXSource::GetStreamHeaderInfo(UINT16 index, IHXValues*& hdr)
{
    HX_TRACE("HXSource::GetStreamHeaderInfo");
    
    // sanity check
    if (index >= m_uNumStreams)
    {
      return HXR_INVALID_PARAMETER; // HX_INVALID_INDEX;
    }
    
    CHXMapLongToObj::Iterator i = mStreamInfoTable->Begin();
    for (UINT16 j=0; j < index; j++)
    {
      ++i;
    }

    STREAM_INFO* pStreamInfo = (STREAM_INFO*) *i;

    hdr = pStreamInfo->m_pHeader;
    if (hdr)
    {
      hdr->AddRef();
    }

    return HXR_OK;
}


void  HXSource::SetFlags(UINT16 flags)
{
    mFlags = flags;

    if (mFlags & HX_PERFECT_PLAY_ENABLED)
    {
      m_bPerfectPlayAllowed = TRUE;
    }
    else
    {
      m_bPerfectPlayAllowed = FALSE;
    }

    if (mFlags & HX_SAVE_ENABLED)
    {
      mSaveAsAllowed = TRUE;
    }
    else
    {
      mSaveAsAllowed = FALSE;
    }
}

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
HX_RESULT HXSource::CopyMetaDataToRegistry(IHXValues* pHeader)
{
    // get Request Object
    char pszServerMetaData[256] = {0}; /* Flawfinder: ignore */
    char pszMetaData[256] = {0}; /* Flawfinder: ignore */

    IHXValues* pReqHeaders = NULL;
    IHXRequest* pRequest = NULL;
    IHXBuffer* pBuffer = NULL;
    char szRegKeyName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
    char buff[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
    char szSMDKey[256]; /* Flawfinder: ignore */
    ULONG32 ulValue = 0;
    IHXBuffer* pParentName = NULL;
    UINT32 regid = 0;
    const char szServerMetaData[] = {"ServerMetaData"};


    if (HXR_OK == m_pRegistry->GetPropName(m_pStats->m_ulRegistryID, pParentName))
    {
      SafeStrCpy(buff, (const char*) pParentName->GetBuffer(), MAX_DISPLAY_NAME);
      char* pDot = strrchr(buff, '.');
      if (pDot)
      {
          *pDot = '\0';
      }
      SafeStrCpy(szSMDKey, buff, 256);

      if (HXR_OK == GetRequest(pRequest))
      {
          // get request headers
          if (HXR_OK == pRequest->GetRequestHeaders(pReqHeaders))
          {
            // look for the meta data properties
            if (HXR_OK == pReqHeaders->GetPropertyCString("AcceptMetaInfo", pBuffer))
            {
                SafeStrCpy(pszMetaData, (char*) pBuffer->GetBuffer(), 256);
                HX_RELEASE(pBuffer);

                // look for comma delimited entries
                const char* pCharEntryStart = pszMetaData;
                const char* pCharEntryEnd = pCharEntryStart;

                while (pCharEntryEnd && *pCharEntryEnd)
                {
                  ++pCharEntryEnd;
                  if (*pCharEntryEnd == ',' || !*pCharEntryEnd)
                  {
                      // copy next prop request into buffer 
                      strncpy(buff, pCharEntryStart, (UINT32)pCharEntryEnd - (UINT32)pCharEntryStart); /* Flawfinder: ignore */
                      *(buff+(UINT32)pCharEntryEnd - (UINT32)pCharEntryStart) = '\0';

                      // see if this prop is in file header (it should be!)
                      if (HXR_OK == pHeader->GetPropertyCString(buff, pBuffer))
                      {
                        // create new registry entry
                        SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.%s", pParentName->GetBuffer(), buff);
                        regid = m_pRegistry->GetId(szRegKeyName);
                        if (!regid)
                        {
                            m_pRegistry->AddStr(szRegKeyName, pBuffer);
                        }
                        else
                        {
                            // set new value
                            m_pRegistry->SetStrByName(szRegKeyName, pBuffer);
                        }

                        HX_RELEASE(pBuffer);
                      }
                      else if (HXR_OK == pHeader->GetPropertyULONG32(buff, ulValue))
                      {
                        // create new registry entry
                        SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.%s", pParentName->GetBuffer(), buff);

                        regid = m_pRegistry->GetId(szRegKeyName);
                        if (!regid)
                        {
                            m_pRegistry->AddInt(szRegKeyName, ulValue);
                        }
                        else
                        {
                            // set new value
                            m_pRegistry->SetIntByName(szRegKeyName, ulValue);
                        }
                      }

                      pCharEntryStart = pCharEntryEnd + 1;
                  }
                }
            }

            // look for the meta data properties
            if (HXR_OK == pReqHeaders->GetPropertyCString("AcceptServerMetaData", pBuffer))
            {
                SafeStrCpy(pszServerMetaData, (char*) pBuffer->GetBuffer(), 256);
                HX_RELEASE(pBuffer);

                // first make sure we have a composit key for "statistics.Player0.ServerMetaData"
                SafeSprintf(buff, MAX_DISPLAY_NAME, "%s.%s", szSMDKey, szServerMetaData);
                regid = m_pRegistry->GetId(buff);
                if (!regid)
                {
                  m_pRegistry->AddComp(buff);
                }
                SafeStrCpy(szSMDKey, buff, 256);

                // look for comma delimited entries
                const char* pCharEntryStart = pszServerMetaData;
                const char* pCharEntryEnd = pCharEntryStart;

                while (pCharEntryEnd && *pCharEntryEnd)
                {
                  ++pCharEntryEnd;
                  if (*pCharEntryEnd == ',' || !*pCharEntryEnd)
                  {
                      // copy next prop request into buffer 
                      strncpy(buff, pCharEntryStart, (UINT32)pCharEntryEnd - (UINT32)pCharEntryStart); /* Flawfinder: ignore */
                      *(buff+(UINT32)pCharEntryEnd - (UINT32)pCharEntryStart) = '\0';

                      // see if this prop is in file header (it should be!)
                      if (HXR_OK == pHeader->GetPropertyCString(buff, pBuffer))
                      {
                        // create new registry entry (if one does not exist)
                        SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.%s", szSMDKey, buff);
                        regid = m_pRegistry->GetId(szRegKeyName);
                        if (!regid)
                        {
                            m_pRegistry->AddStr(szRegKeyName, pBuffer);
                        }
                        else
                        {
                            // set new value
                            m_pRegistry->SetStrByName(szRegKeyName, pBuffer);
                        }

                        HX_RELEASE(pBuffer);
                      }
                      else if (HXR_OK == pHeader->GetPropertyULONG32(buff, ulValue))
                      {
                        // create new registry entry
                        SafeSprintf(szRegKeyName, MAX_DISPLAY_NAME, "%s.%s", szSMDKey, buff);
                        regid = m_pRegistry->GetId(szRegKeyName);
                        if (!regid)
                        {
                            m_pRegistry->AddInt(szRegKeyName, ulValue);
                        }
                        else
                        {
                            // set new value
                            m_pRegistry->SetIntByName(szRegKeyName, ulValue);
                        }
                      }

                      pCharEntryStart = pCharEntryEnd + 1;
                  }
                }
            }

            HX_RELEASE(pReqHeaders);
          }

          HX_RELEASE(pRequest);
      }

      HX_RELEASE(pParentName);
    }

    return HXR_OK;
}
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

HX_RESULT HXSource::SetPlayTimes(UINT32 ulStartTime, 
                          UINT32 ulEndTime, 
                          UINT32 ulDelay, 
                          UINT32 ulDuration)
{
    m_ulStartTime     = ulStartTime;
    m_ulEndTime             = ulEndTime;
    /* We do not handle Delay field for now */
    m_ulDelay               = ulDelay;
    m_ulRestrictedDuration  = ulDuration;

    if (m_ulEndTime > 0)
    {
      m_bCustomEndTime = TRUE;
    }
    else
    {
      m_bCustomEndTime = FALSE;
    }

    return HXR_OK;
}

HX_RESULT
HXSource::UpdatePlayTimes(IHXValues* pValues)
{
    HX_RESULT     rc = HXR_OK;
    char    szStart[] = "Start";
    char    szEnd[] = "End";
    char    szDelay[] = "Delay";
    char    szDuration[] = "Duration";
    UINT32  ulStartTime = 0;
    UINT32  ulEndTime = 0;
    UINT32  ulDelay = 0;
    UINT32  ulRestrictedDuration = 0;

    pValues->GetPropertyULONG32(szStart, ulStartTime);
    pValues->GetPropertyULONG32(szEnd, ulEndTime);
    pValues->GetPropertyULONG32(szDelay, ulDelay);
    pValues->GetPropertyULONG32(szDuration, ulRestrictedDuration);

    if (ulStartTime           != m_ulStartTime    ||
      ulEndTime         != m_ulEndTime        ||
      ulDelay                 != m_ulDelay          ||
      ulRestrictedDuration    != m_ulRestrictedDuration)
    {
      SetPlayTimes(ulStartTime, ulEndTime, ulDelay, ulRestrictedDuration);
      rc = AdjustClipTime();
    }

    return rc;
}

ULONG32 
HXSource::GetPerfectPlayTime(void)
{
    ULONG32 ulCurrentPlayTime = m_pPlayer ? m_pPlayer->GetCurrentPlayTime() : 0;
    ULONG32 result            = m_bPerfectPlay ? m_ulPerfectPlayTime : m_ulBufferedPlayTime;

    if (m_ulDuration != 0)
    {
      // mPlaybackLength is in Milliseconds, we want to calculate
      // playback in seconds...
      ULONG32 playbackTimeLeftInClip = 
          ((m_ulDuration > ulCurrentPlayTime ? m_ulDuration - ulCurrentPlayTime : 0) /1000)+1;

      /* Perfect Play entire clip ONLY if user has chosen PerfectPlay specifically
       * If we internally go in buffered play mode, always use perfect play time
       * setting.
       */
      if (m_bPerfectPlay)
      {
          if (m_bPerfectPlayEntireClip)
          {
            result = playbackTimeLeftInClip;
          }
          else
          {
            result = min(m_ulPerfectPlayTime, playbackTimeLeftInClip);
          }
      }
      else // if (m_bBufferedPlay)
      {
          result = min(m_ulBufferedPlayTime, playbackTimeLeftInClip);
      }
    }
    
    // check if enough memory is available to handle the result
    if(result > 0)
    {
      // get 50% of the available memory
      ULONG32 maxMemAvail = GetAvailableMemory() / 2;
      ULONG32 bytesPerSecond = m_ulAvgBandwidth/8;
      ULONG32 maxTimeAvail = maxMemAvail/(bytesPerSecond > 0 ? bytesPerSecond : 1);

      // if this is true then we can't buffer the entire clip
      if (maxTimeAvail < result)
            m_bCannotBufferEntireClip = (m_bPerfectPlayEntireClip) ? TRUE : FALSE;
      else
            m_bCannotBufferEntireClip = FALSE;

      result = min(result,maxTimeAvail);
    }

    /* Value now returned in ms. */
    return 1000*(max(result, PERFECTPLAY_MIN_TIME));
}

STDMETHODIMP 
HXSource::ReportRebufferStatus(UINT16 uStreamNumber,
                          UINT8 unNeeded, 
                          UINT8 unAvailable) 
{
    STREAM_INFO* pStreamInfo = 0;

//    if (m_bDelayed ||
//    (m_ulDelay > 0 && m_ulDelay > m_pPlayer->GetCurrentPlayTime()))

    if (m_bDelayed)
    {
      return HXR_OK;
    }

    DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)ReportRebufferStatus %lu %lu %lu", this, uStreamNumber, unNeeded, unAvailable));

    if (mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void*& )pStreamInfo))
    {
      pStreamInfo->m_unNeeded     = unNeeded;
      pStreamInfo->m_unAvailable  = unAvailable;
      if (unNeeded > unAvailable)
      {
//        dfprintf("buff", "reportrebufferstatus: %lu\n", m_pPlayer->GetInternalCurrentPlayTime());       
//        g_bRahulLog = TRUE;

          if (m_bFastStart)
          {
                DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)ALMOST Turbo OFF ReportRebufferStatus", this));
                //with surestream audio only clips, rarender may report buffering immediately after resume
                if (m_bSureStreamClip)
            {
                if (CALCULATE_ELAPSED_TICKS(m_ulTurboStartActiveTime, HX_GET_TICKCOUNT()) > 1000)
                {
                  LeaveFastStart(TP_OFF_BY_REBUFFER);
                  DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Turbo OFF ReportRebufferStatus", this));
                }
            }
            else
            {
                    LeaveFastStart(TP_OFF_BY_REBUFFER);
                    DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Turbo OFF ReportRebufferStatus", this));
            }
          }

          // log rebuffer action
          LogInformation("BUFBEG", NULL);
          
          DoRebuffer();
      }
      else
      {
          m_bRebufferingRequired = IsRebufferRequired();
          if (!m_bRebufferingRequired)
          {
            // log rebuffer action
            LogInformation("BUFEND", NULL);
          }
      }
      
        return HXR_OK;
    }

    return HXR_UNEXPECTED;
}

STDMETHODIMP 
HXSource::SetGranularity
(
    UINT16 uStreamNumber,
    ULONG32 ulGranularity
) 
{
    STREAM_INFO* pStreamInfo = 0;

    if (mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void*& )pStreamInfo))
    {
      m_pPlayer->SetGranularity(this, uStreamNumber, ulGranularity);
      return HXR_OK;
    }
    else
    {
      return HXR_OK;
    }

    return HXR_UNEXPECTED;
}

BOOL
HXSource::TryResume(void)
{
    BOOL    bResume = FALSE;

    // resume the persistent source ASAP
    if (m_pSourceInfo && m_pSourceInfo->m_bIsPersistentSource)
    {
        m_bDelayed = FALSE;
        bResume = TRUE;
    }
    else if (m_bPaused && m_bDelayed && m_pPlayer &&
             m_pPlayer->CanBeStarted(this, m_pSourceInfo, m_bPartOfNextGroup))
    {
        UINT32 ulCurrentTime = m_pPlayer->GetInternalCurrentPlayTime();
        UINT32 ulStartTime = 0;

        if (m_ulDelay > m_ulPreRollInMs + NETWORK_FUDGE_FACTOR)
        {
            ulStartTime = m_ulDelay - (m_ulPreRollInMs + NETWORK_FUDGE_FACTOR);
        }

        if (ulCurrentTime >= ulStartTime)
        {
            m_bDelayed = FALSE;
            bResume = TRUE;
        }

        if (!m_bIsPreBufferingStarted)
        {
            m_bIsPreBufferingStarted = TRUE;
            bResume = TRUE;
        }
    }
    else if (m_bPrefetch)
    {
        bResume = TRUE;
    }

    if (bResume && CanBeResumed())
    {
        if (m_pSourceInfo)
        {
            m_pSourceInfo->Register();
        }

        m_bResumePending = TRUE;
    }

    return bResume;
}

BOOL
HXSource::IsAnyAudioStream(void)
{
    IHXAudioPlayer* pAudioPlayer          = NULL;
    BOOL          bAtLeastOneAudioStream  = FALSE;

    if (!m_pPlayer)
    {
      return FALSE;
    }

    m_pPlayer->QueryInterface(IID_IHXAudioPlayer, (void **) &pAudioPlayer);
    UINT16 uNumAudioStreams = pAudioPlayer->GetAudioStreamCount();
    for (UINT16 i = 0; i < uNumAudioStreams && !bAtLeastOneAudioStream; i++)
    {
      IHXAudioStream* pAudioStream = pAudioPlayer->GetAudioStream(i);
      IHXValues* pHeader = pAudioStream->GetStreamInfo();
      pAudioStream->Release();
      if (!pHeader)
      {
          continue;
      }
      
      if (IsAudioStreamFromThisSource(pHeader))
      {
          bAtLeastOneAudioStream = TRUE;
          pHeader->Release();
          break;
      }

      pHeader->Release();
    }

    if (!bAtLeastOneAudioStream)
    {
        IHXValues* pHeader = NULL;
        int nStreamCnt = GetNumStreams();
        ULONG32     ulIsAudioStream = FALSE;

        for (int i=0; i<nStreamCnt && !bAtLeastOneAudioStream; i++)
        {
            GetStreamHeaderInfo(i, pHeader);

            pHeader->GetPropertyULONG32("IsAudioStream", ulIsAudioStream);
            if (ulIsAudioStream)
            {
                bAtLeastOneAudioStream = TRUE;
            }
          HX_RELEASE(pHeader);
        }
    }

    pAudioPlayer->Release();

    return bAtLeastOneAudioStream;
}

void
HXSource::EventReady(CHXEvent* pEvent)
{
    if (m_pPlayer)
    {
      m_pPlayer->EventReady(this, pEvent);
    }
}

BOOL 
HXSource::IsAudioStreamFromThisSource(IHXValues* pAudioHeader)
{
    BOOL    bFound            = FALSE;

    CHXMapLongToObj::Iterator ndxStreamIterator = mStreamInfoTable->Begin();  
    for (; ndxStreamIterator != mStreamInfoTable->End(); ++ndxStreamIterator) 
    {
      STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*ndxStreamIterator);
      if (pStreamInfo->m_pHeader == pAudioHeader)
      {
          bFound = TRUE;
          break;
      }
    }

    return bFound;
}

ULONG32
HXSource::GetAvailableMemory()
{
    ULONG32 memAvail = 1000000;

#if   defined (__MWERKS__)
//  XXX Hack! We can't call any of the Memory Manager calls at interrupt time so we will have 
//  to change this to ask our interrupt safe memory allocator how much memory is free
    memAvail = 1000000;
#elif defined(_WINCE) && !defined(_WIN32_WCE_EMULATION)
    STORE_INFORMATION stInfo;
    GetStoreInformation(&stInfo);
    memAvail = stInfo.dwFreeSize;
#elif (_WIN32)
    MEMORYSTATUS status;
    status.dwLength = sizeof(MEMORYSTATUS);
    GlobalMemoryStatus(&status);
    memAvail = status.dwAvailPageFile;
#elif defined( _WINDOWS)
    memAvail = GetFreeSpace(0);
#elif defined (_UNIX)
    // XXXX Need to get this to compile.
    memAvail = 1000000;
#endif

    return memAvail;
}

void
HXSource::ReportError(HX_RESULT theErr)
{
    if (m_pPlayer)
    {
      m_pPlayer->ReportError(this, theErr);
    }
}


HX_RESULT         
HXSource::AdjustClipTime(void)
{
    HX_RESULT theErr = HXR_OK;
    UINT32  ulOriginalDuration = m_ulDuration;        
    UINT32  ulTrackEndTime = 0;
    CHXMapLongToObj::Iterator i;
    BOOL    bCustomEndTimeSet = FALSE;

    if (m_bPartOfPrefetchGroup)
    {
      if (m_ulDelay)
      {
          m_ulPrefetchDelay = m_ulDelay;
          m_bDelayed = TRUE;
          AdjustClipBandwidthStats(FALSE);
          DoPause();
      }

      m_ulEndTime = 0;
      m_bCustomEndTime = FALSE;
      goto cleanup;
    }
      
    /* For a live stream, the only qualifiers that make sense
     * are Duration and Delay. All other qualifiers should be made 0
     */
    if (mLiveStream)
    {
      m_ulStartTime = 0;

      if (!m_bRestrictedLiveStream)
      {
          m_ulEndTime = 0;
      }
    }

    for (i = mStreamInfoTable->Begin(); i != mStreamInfoTable->End(); ++i) 
    {    
      STREAM_INFO*      pStreamInfo = (STREAM_INFO*) (*i);

      ulTrackEndTime = 0;

      HX_RESULT hrTemp = pStreamInfo->m_pHeader->GetPropertyULONG32("EndTime", ulTrackEndTime);

      if (HXR_OK == hrTemp && !m_bCustomEndTime)
      {     
          if (m_ulEndTime < ulTrackEndTime)
          {
            m_ulEndTime = ulTrackEndTime;
          }
          pStreamInfo->m_bCustomEndTime = TRUE;
      }
      else if (m_bCustomEndTime)
      {
          ulTrackEndTime = m_ulEndTime;
          pStreamInfo->m_bCustomEndTime = TRUE;
      }

      if (ulTrackEndTime > 0 && !mLiveStream)
      {
          pStreamInfo->m_pHeader->SetPropertyULONG32("TrackEndTime",
                                          ulTrackEndTime);
          bCustomEndTimeSet = TRUE;
      }
    }
    
    // if max. duration is set on this source
    if (m_pSourceInfo && 
      m_pSourceInfo->m_ulMaxDuration)
    {
      if (m_ulRestrictedDuration)
      {         
          if (m_ulRestrictedDuration > m_pSourceInfo->m_ulMaxDuration)
          {
            m_ulRestrictedDuration = m_pSourceInfo->m_ulMaxDuration;
          }
      }
      else if (m_ulDuration)
      {
          if (m_ulDuration > m_pSourceInfo->m_ulMaxDuration)
          {
            m_ulRestrictedDuration = m_pSourceInfo->m_ulMaxDuration;
          }
      }
    }

    // By default, we always set the end time to be the duration of the clip,
    // but do not set end time if it was manually specified.
    if (!bCustomEndTimeSet && !mLiveStream)
    {
      m_ulEndTime = m_ulDuration;
    }

    /* Check if there is any end time */
    if ((m_ulEndTime < m_ulDuration) || m_bRestrictedLiveStream)
    {
      m_ulDuration = m_ulEndTime;
    }
    
    /* Is "Delay" specified too? */
    if (m_ulDelay > 0) 
    {
      /* Increase duration of this clip */
      m_ulDuration += m_ulDelay;
      UINT32 ulStartTime = 0;

      if (m_ulDelay > m_ulPreRollInMs + NETWORK_FUDGE_FACTOR)
      {
          ulStartTime = m_ulDelay - (m_ulPreRollInMs + NETWORK_FUDGE_FACTOR);
      }

      // no need to pause delayed persistent component since Pause() will be called
      // on actual tracks' AdjustClipTime() if necessary
      if (m_pSourceInfo && !m_pSourceInfo->m_bIsPersistentSource)
      {
          m_bDelayed = TRUE;
          AdjustClipBandwidthStats(FALSE);
          DoPause();
      }
    }

    if (m_ulStartTime > 0) /* reduce duration by start time amount */
    {
      if (m_ulDuration > m_ulStartTime)
      {
          m_ulDuration -= m_ulStartTime;
      }
      else
      {
          /* This is bad case. We consider it invalid */
          m_ulDuration = 0;
      }
    }

    /* We now allow to increase the default duration of the clip */
    if (m_ulRestrictedDuration > 0)
    {
      m_ulDuration = m_ulRestrictedDuration + m_ulDelay;

      if (mLiveStream && !m_bRestrictedLiveStream)
      {
          m_bRestrictedLiveStream = TRUE;
          m_ulEndTime = m_ulRestrictedDuration + m_ulStartTime;
      }
      
      if (m_ulEndTime > m_ulRestrictedDuration + m_ulStartTime)
      {
          m_ulEndTime = m_ulRestrictedDuration + m_ulStartTime;
      }
    }

    // orig duration is active duration for this source -- time for which
    // this source lasts.
    if (m_ulDuration > m_ulDelay)
    {
      m_ulOriginalDuration = m_ulDuration - m_ulDelay;
    }
    else
    {
      m_ulOriginalDuration = 0;
    }

    if (m_pURL                                &&
      rtspProtocol == m_pURL->GetProtocol()         &&
      m_llLastExpectedPacketTime != m_ulEndTime   &&
      !m_bFirstResume)
    {
      m_bRTSPRuleFlagWorkAround = TRUE;
    }
    /* If we receive a packet after this stream, we consider the stream to be done */
    m_llLastExpectedPacketTime  = CAST_TO_INT64 m_ulEndTime;

    // Seek to the starting position only if the source
    // has not been resumed yet
    if (m_ulStartTime > 0 && m_bFirstResume) 
    {
      /* We will add m_ulStartTime in DoSeek() call*/
      theErr = DoSeek(0);
    }

    /* Update stream durations if required */
    for (i = mStreamInfoTable->Begin(); i != mStreamInfoTable->End(); ++i) 
    {    
      STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*i);
      if (m_ulStartTime > 0)
      {
          pStreamInfo->m_pHeader->SetPropertyULONG32("TrackStartTime",
                                  m_ulStartTime);
      }

      
      if (m_ulEndTime > 0 && 
          !mLiveStream    &&
          HXR_OK != pStreamInfo->m_pHeader->GetPropertyULONG32("TrackEndTime",
                                                  ulTrackEndTime))
      {
          pStreamInfo->m_pHeader->SetPropertyULONG32("TrackEndTime",
                                          m_ulEndTime);
      }

      if (ulOriginalDuration != m_ulDuration)
      {
          pStreamInfo->m_ulDuration = m_ulDuration;
          pStreamInfo->m_pHeader->SetPropertyULONG32("Duration", 
                              pStreamInfo->m_ulDuration);
      }

      if (m_ulDelay > 0)
      {
          pStreamInfo->m_pHeader->SetPropertyULONG32("Delay", m_ulDelay);
      }
    }

//{FILE* f1 = ::fopen("d:\\temp\\url.txt", "a+"); ::fprintf(f1, "%p %s %lu %lu\n", this, m_pszURL, m_ulDelay, m_ulDuration);::fclose(f1);}

cleanup:

    m_bClipTimeAdjusted = TRUE;

    return theErr;
}

void
HXSource::GenerateFakeLostPacket(CHXEvent*& theEvent)
{
    IHXPacket* pPacket = theEvent->GetPacket();
    CHXPacket* pLostPacket = new CHXPacket;
    pLostPacket->AddRef();
    pLostPacket->Set(0, 0, pPacket->GetStreamNumber(), 0, 0);
    pLostPacket->SetAsLost();

    /* Create a new event with lost packet */
    CHXEvent* pEvent = new CHXEvent(pLostPacket);
    pEvent->SetTimeStartPos(theEvent->GetTimeStartPos());
    pEvent->SetTimeOffset(theEvent->GetTimeOffset());
    pEvent->SetPreSeekEvent(theEvent->IsPreSeekEvent());
    pLostPacket->Release();

    delete theEvent;
    theEvent = pEvent;
}

char*
HXSource::GetAltURL(BOOL& bDefault)
{
#if defined(HELIX_FEATURE_ALT_URL)
    char*   pAltURL = NULL;

    if (!m_pURL || m_bInitialized)
    {
      goto cleanup;
    }

    pAltURL = m_pURL->GetAltURL(bDefault);

cleanup:

    return pAltURL;
#else
    return NULL;
#endif /* HELIX_FEATURE_ALT_URL */
}

HX_RESULT
HXSource::SetRequest(const CHXURL* pURL, BOOL bAltURL)
{
    HX_RESULT           hr = HXR_OK;
    IHXValues*          pValues = NULL;
    IHXValues*          pValuesInRequest = NULL;
    IHXGroup*           pGroup = NULL;
    IHXGroup2*          pGroup2 = NULL;
    IHXGroupManager*    pGroupManager = NULL;

    HX_RELEASE(m_pRequest);

    if (m_pPlayer)
    {
      m_pPlayer->GetActiveRequest(m_pRequest);

      if (m_pRequest)
      {
          m_pPlayer->ResetActiveRequest();
      }
    }

#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    if (m_pPlayer && m_pSourceInfo)
    {
      if (HXR_OK == m_pPlayer->QueryInterface(IID_IHXGroupManager, (void**)&pGroupManager))
      {
          if (HXR_OK == pGroupManager->GetGroup(m_pSourceInfo->m_uGroupID, pGroup))
          {
            if (HXR_OK == pGroup->QueryInterface(IID_IHXGroup2, (void**)&pGroup2))
            {
                pGroup2->GetTrack2(m_pSourceInfo->m_uTrackID, pValues, pValuesInRequest);
                UINT32 ulValue = 0;
                char   szDuration[128] = {0}; /* Flawfinder: ignore */
                IHXBuffer* pBuffer = NULL;
                if (pValues && HXR_OK == pValues->GetPropertyULONG32("Duration", ulValue))
                {
                  if (!pValuesInRequest)
                  {
                      pValuesInRequest = new CHXHeader();
                      if( pValuesInRequest )
                      {
                          pValuesInRequest->AddRef();
                      }
                      else
                      {
                          hr = HXR_OUTOFMEMORY;
                      }
                  }
                  if (pValuesInRequest)
                  {
                      SafeSprintf (szDuration, 128, "%lu", ulValue); /* Flawfinder: ignore */
                      pBuffer = new CHXBuffer();
                      pBuffer->AddRef();
                      pBuffer->Set((UCHAR*)szDuration, strlen(szDuration) + 1);
                      pValuesInRequest->SetPropertyCString("Duration", pBuffer);
                      HX_RELEASE(pBuffer);
                  }
                }
            }
            HX_RELEASE(pGroup2);
          }
          HX_RELEASE(pGroup);
      }
      HX_RELEASE(pGroupManager);
    }
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */

    IHXRegistry* pRegistry = NULL;   
    m_pEngine->QueryInterface(IID_IHXRegistry, (void**)&pRegistry);

    hr = ::SetRequest(pURL->GetEscapedURL(), bAltURL, m_pPreferences, pRegistry, pValuesInRequest, m_pRequest);

    HX_RELEASE(pValues);
    HX_RELEASE(pValuesInRequest);
    HX_RELEASE(pRegistry);

#if defined(HELIX_FEATURE_RECORDCONTROL)
    if(hr == HXR_OK && pURL->GetProtocol() != fileProtocol)
    {
      if(!m_pRecordControl)
      {
          m_pRecordControl = new HXRecordControl((IHXPlayer*)m_pPlayer, (IHXStreamSource*)this);
          if(m_pRecordControl)
          {
            m_pRecordControl->AddRef();
            if(m_pRecordControl->IsValid())
                    m_bPlayFromRecordControl = m_pRecordControl->CanGetPackets();
                else
                HX_RELEASE(m_pRecordControl);
          }
      }

      if(m_pRecordControl)
      {
          m_pRecordControl->SetSource((IHXStreamSource*)this);
      }
    }
#endif /* HELIX_FEATURE_RECORDCONTROL */

    return hr;
}

void
HXSource::UpdateDuration(UINT32 ulDuration)
{
    CHXSimpleList* pRepeatList = m_pSourceInfo->GetRepeatList();

    // ulDuration excludes the delay time
    if (pRepeatList && 
      ulDuration >= (m_ulDuration - m_ulDelay))
    {
      m_pSourceInfo->m_ulTotalTrackDuration = ulDuration + m_ulDelay;
      if (m_pSourceInfo->m_pPeerSourceInfo)
      {
          m_pSourceInfo->m_pPeerSourceInfo->m_ulTotalTrackDuration = m_pSourceInfo->m_ulTotalTrackDuration;
      }
    }
    else
    {
      m_ulOriginalDuration = m_ulRestrictedDuration = ulDuration;
      AdjustClipTime();
      m_pSourceInfo->UpdateDuration(m_ulDuration);
    }
}

void
HXSource::UpdateDelay(UINT32 ulDelay)
{
    m_ulDelay = ulDelay;
    AdjustClipTime();
    m_pSourceInfo->UpdateDelay(m_ulDelay);
}

void
HXSource::InitialBufferingDone(void)
{
    m_bInitialBuffering = FALSE;

    // resume if we satisfy the initial preroll AND we have issued
    // rebuffer
    // note: IsRebufferRequired() should return FALSE!!
    if (m_bRebufferingRequired)
    {
      m_bRebufferingRequired = IsRebufferRequired();
      HX_ASSERT(!m_bRebufferingRequired);
    }

    return;
}

void
HXSource::DoRebuffer(void)
{
    m_bRebufferingRequired  = TRUE;

    if (m_pPlayer)
    {
      m_pPlayer->InternalPause();       
        ReBuffer();
    }

    return;
}

BOOL        
HXSource::IsRebufferRequired(void)
{
    BOOL        bResult = FALSE;
    STREAM_INFO*    pStreamInfo = NULL;

    // Check if all streams are doing OK
    for (CHXMapLongToObj::Iterator ndxStrm = mStreamInfoTable->Begin();
       ndxStrm != mStreamInfoTable->End(); ++ndxStrm) 
    {    
      pStreamInfo = (STREAM_INFO*) (*ndxStrm);
      
      if (pStreamInfo->m_unNeeded > pStreamInfo->m_unAvailable)
      {
          bResult = TRUE;
          break;
      }
    }

    return bResult;
}

BOOL
HXSource::IsRebufferDone(void)
{
    BOOL    bResult = TRUE;

    if (m_pSourceInfo)
    {
      bResult = m_pSourceInfo->IsRebufferDone();
    }

    return bResult;
}

void        
HXSource::ScheduleProcessCallback()
{
    if (m_pSourceInfo)
    {
        m_pSourceInfo->ScheduleProcessCallback();
    }
}

#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
/************************************************************************
 *    Method:
 *        IHXHyperNavigate::GoToURL
 *    Purpose:
 *        Acts as a proxy for actual hypernavigate interface.
 *        Is used to convert any relative URLs to absolute URLs
 */
STDMETHODIMP 
HXSource::GoToURL(const char* pURL, const char* pTarget)
{
    return Execute(pURL, pTarget, NULL, NULL, NULL);
}

/************************************************************************
 *    Method:
 *        IHXHyperNavigate2::Execute
 *    Purpose:
 *        
 *    Parameters:
 *      pURL:         URL (absolute or relative)
 *        pTargetInstance:    
 *        pTargetApplication: 
 *        pTargetRegion:
 *        pParams:
 */
STDMETHODIMP 
HXSource::Execute(const char* pURL,
               const char* pTargetInstance,
               const char* pTargetApplication,
               const char* pTargetRegion,
               IHXValues* pParams)
{
    HX_RESULT theErr = HXR_OK;
    CHXString newURL = pURL;

//    pURL = "rogers.rt";

//    if (pTargetInstance && 
//    stricmp(pTargetInstance, "_player") == 0 &&
    if (ShouldConvert(pTargetInstance) && 
      pURL  &&
      strnicmp(pURL, URL_COMMAND, sizeof(URL_COMMAND) - 1) != 0 )
    {
      CHXURL urlObj(pURL);
      IHXValues* pHeader = urlObj.GetProperties();
      IHXBuffer* pBuffer = NULL;

      if(pHeader && 
         m_pszURL &&
         HXR_OK != pHeader->GetPropertyBuffer(PROPERTY_SCHEME, pBuffer))
      {
          // relative URL
          // if it starts with '/', make it relative to the root of 
          // the URL prefix

          CHXString urlPrefix, urlRoot;
          char* pURLFragment = NULL;
          theErr = CHXURL::GeneratePrefixRootFragment(m_pszURL, urlPrefix, urlRoot, pURLFragment);
          HX_VECTOR_DELETE(pURLFragment);

          if (!theErr)
          {
            if(*pURL == '/')
            {
                newURL = urlRoot + pURL;
            }
            else
            {
                newURL = urlPrefix + pURL;
            }     
          }
      }
      HX_RELEASE(pBuffer);
      HX_RELEASE(pHeader);
    }
    
    AddRef();

    HX_ASSERT(m_pPlayer && m_pPlayer->m_pHyperNavigate);
    if (m_pPlayer && m_pPlayer->m_pHyperNavigate)
    {
      theErr = m_pPlayer->m_pHyperNavigate->ExecuteWithContext(newURL, 
                  pTargetInstance, pTargetApplication, pTargetRegion, 
                  pParams, (IUnknown*) (IHXStreamSource*) this);
    }

    Release();

    return theErr;
}
#endif /* defined(HELIX_FEATURE_HYPER_NAVIGATE) */

STDMETHODIMP
HXSource::GetTotalBuffering(UINT16  uStreamNumber,
                      REF(INT64)  llLowestTimestamp, 
                      REF(INT64)  llHighestTimestamp,
                      REF(UINT32) ulNumBytes,
                      REF(BOOL)   bDone)
{
    HX_RESULT res = HXR_NO_DATA;
    
    llLowestTimestamp = 0;
    llHighestTimestamp = 0;
    ulNumBytes = 0;
    bDone = FALSE;

    STREAM_INFO* pStreamInfo;
    if (mStreamInfoTable->Lookup((LONG32) uStreamNumber, (void*& )pStreamInfo))
    {
      HXBufferingState& bufState = pStreamInfo->BufferingState();
      BOOL   bUseTransportStats = FALSE;

      INT64  llTransportLowTS = 0;
      INT64  llTransportHighTS = 0;
      UINT32 ulTransportBytes = 0;
      BOOL   bTransportDone = FALSE;

      if (!IsLocalSource() &&
          (HXR_OK == GetCurrentBuffering(uStreamNumber,
                                 llTransportLowTS,
                                 llTransportHighTS,
                                 ulTransportBytes,
                                 bTransportDone)))
      {
          bufState.UpdateTransportStats(llTransportLowTS,
                                llTransportHighTS,
                                ulTransportBytes,
                                bTransportDone);

          bUseTransportStats = TRUE;

          // Update bDone with what the transport says.
          bDone = bTransportDone;
      }

      res = bufState.GetBufferingStats(llLowestTimestamp,
                               llHighestTimestamp,
                               ulNumBytes,
                               bUseTransportStats);
    }


    return res;
}

/* 
 * All relative URLs are converted to absolute URLs unless the 
 * original request (ram/smil) passed in OpenRequest/OpenURL()
 * is a mem: URL AND the target is not _player.
 *
 * This fixes relative URLs being hurled to the browser using events
 * come from the same location as the .ram file. (Broadcase usage case)
 * PR 31352
 *
 * This also fixes content on CD-ROMs where relative URLs being hurled 
 * to the browser using events come from the same location as 
 * the .rm file in which they are merged. 
 * PR 23489
 */
BOOL HXSource::ShouldConvert(const char* pTargetInstance)
{
    if (pTargetInstance && 
      stricmp(pTargetInstance, "_player") == 0)
    {
      return TRUE;
    }
    
    const char* pPlayerURL = NULL;
    IHXRequest* pPlayerRequest = NULL;
    if (m_pPlayer)
    {
      m_pPlayer->GetRequest(pPlayerRequest);
      if (pPlayerRequest)
      {
          pPlayerRequest->GetURL(pPlayerURL);
      }
    }
    HX_RELEASE(pPlayerRequest);

    if (pPlayerURL && ::strncasecmp(pPlayerURL, "mem:", 4) == 0)
    {
      return FALSE;     
    }

    return TRUE;
}

void
HXSource::MergeUpgradeRequest(BOOL bAddDefault /*= FALSE*/, char* pUpgradeString /* = NULL*/)
{
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    if (m_pPlayer && 
      bAddDefault && 
      (!m_pUpgradeCollection || m_pUpgradeCollection->GetCount() == 0))
    {
      if (!m_pUpgradeCollection)
      {
          m_pUpgradeCollection = new HXUpgradeCollection;
      }

      if (!pUpgradeString)
      {
          pUpgradeString = "Missing Component";
      }

      IHXBuffer* pPluginID = (IHXBuffer*) new CHXBuffer;
      pPluginID->AddRef();
      pPluginID->Set((const UINT8*)pUpgradeString, strlen(pUpgradeString) + 1);
      m_pUpgradeCollection->Add(eUT_Required, pPluginID, 0, 0);
      pPluginID->Release();
    }

    if (m_pPlayer && m_pUpgradeCollection && m_pUpgradeCollection->GetCount() > 0)
    {
      UINT32 ulCount = m_pUpgradeCollection->GetCount();
      IHXUpgradeCollection* pPlayerUpgrade;
      m_pPlayer->QueryInterface(IID_IHXUpgradeCollection, (void**) &pPlayerUpgrade);
      for (UINT32 i = 0; i < ulCount; i++)
      {
          HXUpgradeType upgradeType;
          IHXBuffer* pPluginId = (IHXBuffer*) new CHXBuffer;
          UINT32  majorVersion;
          UINT32  minorVersion;
          pPluginId->AddRef(); 
          // GetAt is a non-COM like API. It expects pPluginID to be allocated by the user
          // and does not perform an addref either!
          m_pUpgradeCollection->GetAt(i, upgradeType, pPluginId, majorVersion, minorVersion);
          pPlayerUpgrade->Add(upgradeType, pPluginId, majorVersion, minorVersion);
          pPluginId->Release();
      }

      pPlayerUpgrade->Release();
      m_pUpgradeCollection->RemoveAll();
    }
#endif /* HELIX_FEATURE_AUTOUPGRADE */
}

void
HXSource::ClearUpgradeRequest()
{
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    if (m_pUpgradeCollection)
    {
      m_pUpgradeCollection->RemoveAll();
    }
#endif /* HELIX_FEATURE_AUTOUPGRADE */
}

void
HXSource::EnterPrefetch(PrefetchType prefetchType, UINT32 ulPrefetchValue)
{
    m_bPrefetch = TRUE;
    m_prefetchType = prefetchType;
    m_ulPrefetchValue = ulPrefetchValue;

    return;
}

void
HXSource::LeavePrefetch(void)
{
    m_bPrefetch = FALSE;

    // send prefetch notification so that SMIL
    // renderer can resolve the duration on this prefetch track
    if (m_pSourceInfo)
    {
      m_pPlayer->PrefetchTrackDone(m_pSourceInfo->m_uGroupID, 
                             m_pSourceInfo->m_uTrackID, 
                             HXR_OK);
    }

    return;
}

void        
HXSource::SetSoundLevel(UINT16 uSoundLevel, BOOL bReflushAudioDevice)
{
#if defined(HELIX_FEATURE_SMIL_SOUNDLEVEL)
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXAudioStream* pCHXAudioStream = NULL;
    CHXSimpleList*  pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer->AddRef();

    if (HXR_OK == CollectAudioStreams(pAudioStreamList) && pAudioStreamList)
    {
      pAudioPlayer->SetSoundLevel(pAudioStreamList, uSoundLevel, bReflushAudioDevice);

      ReleaseAudioStreams(pAudioStreamList);
      HX_DELETE(pAudioStreamList);
    }

    HX_RELEASE(pAudioPlayer);

cleanup:
#endif /* HELIX_FEATURE_SMIL_SOUNDLEVEL */

    return;
}

void        
HXSource::SetAudioDeviceReflushHint(void)
{
#if defined(HELIX_FEATURE_SOUNDLEVEL)
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXSimpleList*  pAudioStreamList = NULL;

    if (!m_pPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer = m_pPlayer->GetAudioPlayer();
    if (!pAudioPlayer)
    {
      goto cleanup;
    }

    pAudioPlayer->AddRef();

    if (HXR_OK == CollectAudioStreams(pAudioStreamList) && pAudioStreamList)
    {
      pAudioPlayer->ManageAudioStreams(pAudioStreamList, CHXAudioPlayer::STR_SETHINT);

      ReleaseAudioStreams(pAudioStreamList);
      HX_DELETE(pAudioStreamList);
    }

    HX_RELEASE(pAudioPlayer);

cleanup:
#endif /* HELIX_FEATURE_SOUNDLEVEL */

    return;
}

void
HXSource::LeaveFastStart(TurboPlayOffReason leftReason)
{
    m_turboPlayStats.tpOffReason = leftReason;
    m_bFastStart = FALSE;
}

void
HXSource::DeleteAllEvents()
{
    if (m_PacketBufferList.GetCount() > 0)
    {
      LISTPOSITION pos = m_PacketBufferList.GetHeadPosition();
      while (pos != NULL)
      {
          CHXEvent* pTempEvent  = (CHXEvent*) m_PacketBufferList.GetNext(pos);
          delete pTempEvent;
      }

      m_PacketBufferList.RemoveAll();
    }
}

void  
HXSource::SetMinimumPreroll(ULONG32 ulMinimumAudioPreroll, ULONG32 ulMinimumStartingPreroll)
{
    UINT32 ulTotalMinimumPreroll = 0;

    if (m_pPlayer)
    {
      // get the user-set minimum preroll
      m_pPlayer->GetMinimumPreroll(ulTotalMinimumPreroll);
    }

    if (IsAnyAudioStream())
    {
      m_ulPreRollInMs   += ulMinimumAudioPreroll;
    }

    if (m_ulPreRollInMs < ulTotalMinimumPreroll)
    {
      m_ulPreRollInMs = ulTotalMinimumPreroll;
    }

    DEBUG_OUT(m_pPlayer, DOL_TRANSPORT, (s, "(%p)Preroll: %lu MinPreroll %lu MinAudioPreroll %lu", this, m_ulPreRollInMs, ulTotalMinimumPreroll, ulMinimumStartingPreroll));

    m_pBufferManager->SetMinimumPreroll(IsLocalSource() | m_bPerfectPlay,
                              ulTotalMinimumPreroll,
                              ulMinimumStartingPreroll);
}

HX_RESULT         
HXSource::SendHeaderToRecordControl(BOOL bFileHeader, IHXValues* pHeader)
{
#if defined(HELIX_FEATURE_RECORDCONTROL)
    HX_RESULT nResult = HXR_OK;

    if(m_pRecordControl && pHeader)
    {
      if(bFileHeader)
          nResult = m_pRecordControl->OnFileHeader(pHeader);
      else
          nResult = m_pRecordControl->OnStreamHeader(pHeader);

      if(nResult != HXR_OK)
      {
          m_bPlayFromRecordControl = FALSE;
          if(nResult != HXR_RECORD)
            HX_RELEASE(m_pRecordControl);
      }
    }
    return nResult;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_RECORDCONTROL */
}

void
HXSource::ProcessFileHeader(void)
{
    UINT32      bNonSeekAble = 0;
    IHXBuffer*  pTitle = NULL;
    IHXBuffer*  pAuthor = NULL;
    IHXBuffer*  pCopyright = NULL;
    IHXBuffer*  pAbstract = NULL;
    IHXBuffer*  pDescription = NULL;
    IHXBuffer*  pKeywords = NULL;
    IHXValues*  pValues = NULL;

    if (m_pURL)
    {
      pValues = m_pURL->GetOptions();
    }

    // retrieve the TAC from the URL
    if (pValues)
    {
      pValues->GetPropertyBuffer("Title", pTitle);
        pValues->GetPropertyBuffer("Author", pAuthor);
        pValues->GetPropertyBuffer("Copyright", pCopyright);
        pValues->GetPropertyBuffer("Abstract", pAbstract);
        pValues->GetPropertyBuffer("Description", pDescription);
        pValues->GetPropertyBuffer("Keywords", pKeywords);

//#define LOSS_HACK
#ifdef LOSS_HACK
      UINT32 ulLoss = 0;
      if (HXR_OK == pValues->GetPropertyULONG32("Loss", ulLoss))
      {
          m_ulLossHack = ulLoss;
          /* Initialize random number generator */
          ::srand((unsigned int) HX_GET_TICKCOUNT());
      }
#endif /*LOSS_HACK*/
    }

    if (m_pFileHeader)
    {
        if (!pTitle)        m_pFileHeader->GetPropertyBuffer("Title", pTitle);
        if (!pAuthor)       m_pFileHeader->GetPropertyBuffer("Author", pAuthor);
        if (!pCopyright)    m_pFileHeader->GetPropertyBuffer("Copyright", pCopyright);
        if (!pDescription)  m_pFileHeader->GetPropertyCString("Description", pDescription);
        if (!pAbstract)     m_pFileHeader->GetPropertyCString("Abstract", pAbstract);
        if (!pKeywords)     m_pFileHeader->GetPropertyCString("Keywords", pKeywords);

        m_pFileHeader->GetPropertyULONG32("NonSeekable", bNonSeekAble);
      m_bNonSeekable = bNonSeekAble ? TRUE : FALSE;
        
        m_pFileHeader->GetPropertyULONG32("StreamCount",m_ulStreamHeadersExpected);
            
        HX_ASSERT(mStreamInfoTable->IsEmpty() == TRUE);
        if (mStreamInfoTable->IsEmpty() && m_ulStreamHeadersExpected > 0 &&
            m_ulStreamHeadersExpected < mStreamInfoTable->GetHashTableSize())
        {
            mStreamInfoTable->InitHashTable(m_ulStreamHeadersExpected);
        }
    }

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    if (m_pStats)
    {
        if (pTitle && m_pStats->m_pTitle)
        {
          m_pStats->m_pTitle->SetStr((char*)(pTitle->GetBuffer()));
        }

        if (pAuthor && m_pStats->m_pAuthor)
        {
          m_pStats->m_pAuthor->SetStr((char*)(pAuthor->GetBuffer()));
        }

        if (pCopyright && m_pStats->m_pCopyright)
        {
          m_pStats->m_pCopyright->SetStr((char*)(pCopyright->GetBuffer()));
        }

        if (pAbstract && m_pStats->m_pAbstract)
        {
          m_pStats->m_pAbstract->SetStr((char*)(pAbstract->GetBuffer()));
        }
    
        if (pDescription && m_pStats->m_pDescription)
        {
            m_pStats->m_pDescription->SetStr((char*)(pDescription->GetBuffer()));
        }

        if (pKeywords && m_pStats->m_pKeywords)
        {
          m_pStats->m_pKeywords->SetStr((char*)(pKeywords->GetBuffer()));
        }
    }

    CopyMetaDataToRegistry(m_pFileHeader);
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    m_bReceivedHeader = TRUE;

    HX_RELEASE(pTitle);
    HX_RELEASE(pAuthor);
    HX_RELEASE(pCopyright);
    HX_RELEASE(pAbstract);
    HX_RELEASE(pDescription);
    HX_RELEASE(pKeywords);
    HX_RELEASE(pValues);

    return;
}

static BOOL GetHeaderBOOL(IHXValues* pHeader, const char* pKey)
{
    BOOL bRet = FALSE;

    ULONG32 ulTemp = 0;
    if ((HXR_OK == pHeader->GetPropertyULONG32(pKey, ulTemp)) && ulTemp)
    {
      bRet = TRUE;
    }

    return bRet;
}

HX_RESULT
HXSource::ProcessStreamHeaders(IHXValues* pHeader, STREAM_INFO*& pStreamInfo)
{
    HX_RESULT       rc = HXR_OK;
    UINT32          ulStreamNumber = 0;
    UINT32          ulAvgBitRate = 0;
    UINT32          ulAvgPacketSize = 0;
    UINT32          ulPreroll = 0;
    ULONG32         ulPredata = 0;
    UINT32          ulDuration = 0;
    UINT32          ulTemp = 0;
    void*           lTmp = NULL;

    pStreamInfo = NULL;

    if (!pHeader)
    {
        rc = HX_INVALID_HEADER;
        goto cleanup;
    }

    // Use file header for default duration
    if (m_pFileHeader)
    {
        m_pFileHeader->GetPropertyULONG32("Duration", ulDuration);
        if (!m_ulDuration && ulDuration)
        {
            m_ulDuration = ulDuration;
            ulDuration = 0;
        }
    }

    pHeader->GetPropertyULONG32("StreamNumber",     ulStreamNumber);
    pHeader->GetPropertyULONG32("AvgBitRate",       ulAvgBitRate);
    pHeader->GetPropertyULONG32("AvgPacketSize",    ulAvgPacketSize);
    pHeader->GetPropertyULONG32("Preroll",          ulPreroll);
    pHeader->GetPropertyULONG32("Predata",          ulPredata);
    pHeader->GetPropertyULONG32("Duration",         ulDuration);

    if (mStreamInfoTable->Lookup((LONG32) ulStreamNumber, (void *&) lTmp))
    {
      // a header with this stream number already exists..
        rc = HX_INVALID_HEADER;
        goto cleanup;
    }

    // max preroll
    if (m_ulPreRollInMs < ulPreroll)
    {
      m_ulPreRollInMs = ulPreroll;
    }

    m_ulAvgBandwidth   += ulAvgBitRate;

    // max duration...
    if (m_ulDuration < ulDuration)
    {
      m_ulDuration = ulDuration;
    }

    pStreamInfo = new STREAM_INFO;
    if (!pStreamInfo)
    {
      rc = HXR_OUTOFMEMORY;
        goto cleanup;
    }

    pStreamInfo->m_pHeader                  = pHeader;
    pStreamInfo->m_pHeader->AddRef();

    pStreamInfo->m_bCustomEndTime           = FALSE;
    pStreamInfo->m_bSrcStreamDone           = FALSE;
    pStreamInfo->m_bSrcStreamFillingDone    = FALSE;
    pStreamInfo->m_bPacketRequested         = FALSE;
    
    pStreamInfo->m_uStreamNumber = (UINT16) ulStreamNumber;

    pStreamInfo->m_ulDuration = ulDuration;

    pStreamInfo->BufferingState().OnStreamHeader(
      ulPreroll,
      ulPredata,
      GetHeaderBOOL(pHeader, "PreDataAtStart"),
      GetHeaderBOOL(pHeader, "PreDataAfterSeek"),
      GetHeaderBOOL(pHeader, "PrerollAtStart"),
      GetHeaderBOOL(pHeader, "PrerollAfterSeek"),
      ulAvgBitRate);


    mStreamInfoTable->SetAt(ulStreamNumber, (void *) pStreamInfo);

cleanup:

    return rc;
}

HX_RESULT HXSource::OnTimeSync(ULONG32 ulCurrentTime)
{
    HX_RESULT res = HXR_OK;

    for (CHXMapLongToObj::Iterator i = mStreamInfoTable->Begin();
         i != mStreamInfoTable->End(); ++i) 
    {    
      STREAM_INFO* pStreamInfo = (STREAM_INFO*) (*i);

      pStreamInfo->BufferingState().OnTimeSync(ulCurrentTime);
    }

    return res;
}

Generated by  Doxygen 1.6.0   Back to index