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

srcinfo.cpp

/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: srcinfo.cpp,v 1.26.2.3 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"
#include "hxresult.h"
#include "smiltype.h"
#include "hxcomm.h"           // IHXRegistryID
#include "hxengin.h"
#include "hxcore.h"
#include "hxupgrd.h"
#include "hxrendr.h"
#include "hxasm.h"
#include "hxsmbw.h"
#include "hxgroup.h"
#include "hxausvc.h"
#include "hxslist.h"
#include "hxmap.h"
#include "chxpckts.h"
#include "chxeven.h"
#include "chxelst.h"
#include "strminfo.h"

#include "timeval.h"
#include "hxbsrc.h"
#include "hxsrc.h"
#include "hxstrm.h"
#include "hxsmstr.h"
#include "hxaudply.h"
#include "basgroup.h"
#include "advgroup.h"
#include "hxthread.h"
#include "hxtick.h"
#include "hxstrutl.h"

#include "srcinfo.h"
#include "hxplay.h"
#include "hxcleng.h"
#include "plghand2.h"

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

#define TIME_SYNC_FUDGE_FACTOR      10
#define GOTOEXITONERROR(theErr, label)      if ((theErr) != 0) goto label

SourceInfo::SourceInfo(HXPlayer* pPlayer)
{
    m_pRendererMap = new CHXMapLongToObj;
    
    m_pPlayer = pPlayer;
    m_pPlayer->AddRef();
    m_pSource               = NULL;
    m_bDone           = FALSE;
    m_bStopped              = FALSE;
    m_bInitialized          = FALSE;
    m_pStatus               = NULL;
    m_bAllPacketsReceived   = FALSE;
    m_bActive               = TRUE;
    m_bIsPersistentSource   = FALSE;
    m_bIsRegisterSourceDone = FALSE;
    m_uTrackID              = 0;
    m_uGroupID              = 0;
    m_bToBeResumed          = TRUE;
    m_bAreStreamsSetup      = FALSE;
    m_bTrackStartedToBeSent = TRUE;
    m_bTrackStoppedToBeSent = TRUE;
    m_bPrefetch             = FALSE;
    m_bLoadPluginAttempted  = FALSE;
    m_pCurrentScheduleList  = NULL;
    m_ulSourceDuration      = 0;
    m_ulMaxDuration         = 0;
    m_ulTrackDuration       = 0;
    m_ulTotalTrackDuration  = 0;
    m_pDependNode     = NULL;
    m_uNumDependencies      = 0;
    m_bTobeInitializedBeforeBegin = FALSE;
    m_bAltURL               = FALSE;
    m_lastErrorFromMainURL  = HXR_OK;
    m_lastError             = HXR_OK;
    m_bLocked               = FALSE;
    m_bIsTrackDurationSet   = FALSE;
    m_bDurationTimeSyncScheduled = FALSE;
    m_bAudioDeviceReflushHint = FALSE;
    m_pProcessCallback = new CHXGenericCallback((void*)this, (fGenericCBFunc)ProcessCallback);
    m_pProcessCallback->AddRef();

    m_prefetchType = PrefetchUnknown;
    m_ulPrefetchValue = 0;
    m_uSoundLevel = 100;
    m_fillType = FillRemove;

    m_pPeerSourceInfo = NULL;   
    m_bSeekPending = FALSE;
    m_bIndefiniteDuration = FALSE;
    m_bRepeatIndefinite = FALSE;
    m_bSeekToLastFrame = FALSE;
    m_ulRepeatInterval = 0;
    m_ulRepeatDelayTimeOffset = 0;
    m_ulSeekTime = 0;
    m_ulPausedStartTime = 0;

    m_bLeadingSource = TRUE;
    m_bRepeatPending = FALSE;
    m_pRepeatList = NULL;
    m_curPosition = 0;
    
    m_ulPersistentComponentID = MAX_UINT32;
    m_ulPersistentComponentSelfID = MAX_UINT32;
    m_pRendererAdviseSink = NULL;

#ifdef THREADS_SUPPORTED
    HXMutex::MakeMutex(m_pMutex);
#else
    HXMutex::MakeStubMutex(m_pMutex);
#endif

    /*
     * The following members are needed for live sync support.
     */
    m_pWallClock = NULL;
    m_ulStreamStartTime = 0;
    m_llLatestPacketTime    = 0;
}

SourceInfo::~SourceInfo()
{
    if (m_pProcessCallback && m_pPlayer->m_pScheduler)
    {
      m_pPlayer->m_pScheduler->Remove(m_pProcessCallback->GetPendingCallback());
        m_pProcessCallback->CallbackCanceled();
    }

    if (m_pRepeatList)
    {
      while (m_pRepeatList->GetCount())
      {
          RepeatInfo* pRepeatInfo = (RepeatInfo*)m_pRepeatList->RemoveHead();
          HX_DELETE(pRepeatInfo);
      }

      HX_DELETE(m_pRepeatList);
    }

    HX_RELEASE(m_pStatus);
    HX_RELEASE(m_pProcessCallback);
    HX_RELEASE(m_pPlayer);
    HX_DELETE(m_pCurrentScheduleList);
    HX_VECTOR_DELETE(m_pDependNode);
    HX_DELETE(m_pMutex);

    HX_DELETE(m_pRendererMap);
    /*
     * For live sync support, we may have used a shared wall
     * clock, if so then we're done with it now, so we may need 
     * to do some cleanup work here.     
     */
    DoneWithWallClock();
};



HX_RESULT
SourceInfo::Begin()
{
    HX_RESULT theErr = HXR_OK;

    if(!m_pSource || !m_pSource->IsInitialized())
    {
      return HXR_OK;
    }

    if (m_pPlayer->m_bInitialized)
    {
      // handle the seek so that the server will be notified 
      // via the play request upon the first resume
      if (m_bSeekPending)
      {
          m_bSeekPending = FALSE;
      
          Pause();
          Seek(m_ulSeekTime);
          m_pSource->DoSeek(m_ulSeekTime);
      }

      theErr = m_pSource->DoResume();
    }

    if (!m_bInitialized)
    {
      return HXR_OK;
    }

    /* Only send this OnBegin()'s if not the first begin. In the case
     * of the first begin, these are actually sent after the header's
     * arrive...
     */
    if (!m_pPlayer->m_bIsFirstBegin && !m_pPlayer->m_bInternalPauseResume)
    {
      CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
      for (; !theErr &&
            ndxRend != m_pRendererMap->End(); ++ndxRend)
      {
          RendererInfo* pRendInfo = (RendererInfo*) (*ndxRend);

          if (!pRendInfo->m_bInitialBeginToBeSent)
          {
            IHXRenderer* pRend  = (IHXRenderer*) pRendInfo->m_pRenderer;
            pRend->OnBegin(m_pPlayer->m_ulCurrentPlayTime);
          }
      }
    }

    return theErr;
}


HX_RESULT
SourceInfo::Pause()
{
    HX_RESULT     theErr      = HXR_OK;

    if(!m_pSource)
    {
      return HXR_OK;
    }

    theErr = m_pSource->DoPause();

    /* Do not send OnPause to renderers if it is an internal Pause */
    if (m_pPlayer->m_bInternalPauseResume || !m_bInitialized)
    {
      return theErr;
    }

    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; !theErr &&
          ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo = (RendererInfo*) (*ndxRend);
      IHXRenderer* pRend     = (IHXRenderer*) pRendInfo->m_pRenderer;

      m_pPlayer->m_pScheduler->Remove(
         pRendInfo->m_pTimeSyncCallback->GetPendingCallback());
        
        pRendInfo->m_pTimeSyncCallback->CallbackCanceled();
      pRendInfo->m_bIsFirstCallback   = TRUE;

      pRend->OnPause(m_pPlayer->m_ulCurrentPlayTime);
    }

    return theErr;
}


HX_RESULT
SourceInfo::Seek(UINT32 ulSeekTo)
{
    HX_RESULT                     rc = HXR_OK;
    INT64                   llLastExpectedPacketTime = 0;
    BOOL                    bSeekToLastFrame = FALSE;
    BOOL                    bDurationTimeSyncSent = TRUE;
    UINT32                  ulValue = 0;
    RendererInfo*           pRendInfo = NULL;
    STREAM_INFO*            pStreamInfo = NULL;
    IHXValues*                    pStatus = NULL;
    IHXPersistentRenderer*        pPersRender = NULL;
    IHXPersistentComponent*       pPersComp = NULL;
    HXPersistentComponentManager*  pPersCompMgr = NULL;
    CHXMapLongToObj::Iterator ndx;

    /* m_pSource should never be NULL */
    HX_ASSERT(m_pSource);
    if(!m_pSource || !m_bInitialized)
    {
      return HXR_OK;
    }

    m_bDone = FALSE;
    m_bActive = TRUE;
    m_bAllPacketsReceived = FALSE;
    llLastExpectedPacketTime = m_pSource->GetLastExpectedPacketTime();

    /* Are we seeking past the last expected packet time?
     * If so, verify the "show" attribute to see whether we need to
     * get the last video frame
     */    
    if (!m_pSource->IsLive() && ulSeekTo >= INT64_TO_UINT32(llLastExpectedPacketTime + m_pSource->GetDelay()))
    {
#if defined(HELIX_FEATURE_NESTEDMETA)
      pPersCompMgr = m_pPlayer->m_pPersistentComponentManager;
      if (FillFreeze == m_fillType && pPersCompMgr) 
      {
          rc = pPersCompMgr->GetPersistentComponent(m_ulPersistentComponentID,
                                          pPersComp);
          HX_ASSERT(HXR_OK == rc);

          if (pPersComp)
          {
            rc = pPersComp->GetPersistentRenderer(pPersRender);
            HX_ASSERT(HXR_OK == rc);

            rc = pPersRender->GetElementStatus(m_uGroupID,
                                       m_uTrackID,
                                       ulSeekTo,
                                       pStatus);
            HX_ASSERT(HXR_OK == rc);

            if (pStatus && HXR_OK == pStatus->GetPropertyULONG32("Show", ulValue))
            {
                bSeekToLastFrame = (BOOL)ulValue;
            }

            HX_RELEASE(pStatus);
            HX_RELEASE(pPersRender);
            HX_RELEASE(pPersComp);
          }
      }
      else if (FillHold == m_fillType)
      {
          bSeekToLastFrame = TRUE;
      }
#else
      if (FillHold == m_fillType)
      {
          bSeekToLastFrame = TRUE;
      }
#endif /* HELIX_FEATURE_NESTEDMETA */
    }

    // also check if we already sent OnTimeSync() upon its duration ends
    // which means the renderer got the last frame so we don't need to issue
    // last frame seek
    if (bSeekToLastFrame)
    {
      ndx = m_pRendererMap->Begin();
      for (; ndx != m_pRendererMap->End(); ++ndx)
      {
          pRendInfo = (RendererInfo*)(*ndx);
          if (!pRendInfo->m_bDurationTimeSyncSent)
          {
            bDurationTimeSyncSent = FALSE;
          }
      }

      if (bDurationTimeSyncSent)
      {
          bSeekToLastFrame = FALSE;
      }
    }

    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo     = (RendererInfo*)(*ndxRend);
      IHXRenderer* pRend         = (IHXRenderer*)pRendInfo->m_pRenderer;
      STREAM_INFO*  pStreamInfo   = pRendInfo->m_pStreamInfo;
      
      pStreamInfo->m_bSrcInfoStreamDone  = FALSE;

      pRendInfo->m_pStream->ResetASMRuleState();
      pStreamInfo->ResetPostEndTimeEventList();

      if (m_pSource->IsLive())
      {
#if defined(HELIX_FEATURE_RECORDCONTROL)
          if(m_pSource->IsPlayingFromRecordControl())
          {
            pStreamInfo->m_ulTimeBeforeSeek = m_pPlayer->m_ulTimeBeforeSeek;
            pStreamInfo->m_ulTimeAfterSeek = m_pPlayer->m_ulTimeAfterSeek;

            if (pRendInfo->m_bTimeDiffPositive)
            {
                pStreamInfo->m_ulTimeBeforeSeek += pRendInfo->m_ulTimeDiff;
                pStreamInfo->m_ulTimeAfterSeek += pRendInfo->m_ulTimeDiff;
            }
            else
            {
                pStreamInfo->m_ulTimeBeforeSeek -= pRendInfo->m_ulTimeDiff;
                pStreamInfo->m_ulTimeAfterSeek -= pRendInfo->m_ulTimeDiff;
            }
          }
          else
#endif /* HELIX_FEATURE_RECORDCONTROL */
          {
            UINT32 ulLastTimeSync = (LONG32) m_pPlayer->m_ulLiveSeekTime;

            if (pRendInfo->m_bTimeDiffPositive)
            {
                ulLastTimeSync += pRendInfo->m_ulTimeDiff;
            }
            else
            {
                ulLastTimeSync -= pRendInfo->m_ulTimeDiff;
            }

            pStreamInfo->m_ulTimeBeforeSeek = ulLastTimeSync;
            pStreamInfo->m_ulTimeAfterSeek  = ulLastTimeSync + m_pPlayer->m_ulElapsedPauseTime;
          }
      }
      else
      {
          pStreamInfo->m_ulTimeBeforeSeek = m_pPlayer->m_ulTimeBeforeSeek;
          if (bSeekToLastFrame)
          {       
            HX_ASSERT(llLastExpectedPacketTime + m_pSource->GetDelay() >= 1);
            pStreamInfo->m_ulTimeAfterSeek = INT64_TO_UINT32(llLastExpectedPacketTime + m_pSource->GetDelay() - 1);
          }
          else
          {
            pStreamInfo->m_ulTimeAfterSeek = m_pPlayer->m_ulTimeAfterSeek;
          }
      }
      
      pRend->OnPreSeek(pStreamInfo->m_ulTimeBeforeSeek,
                   pStreamInfo->m_ulTimeAfterSeek);

      pStreamInfo->m_pStream->m_bPostSeekToBeSent = TRUE;

      // reset renderer info attributes 
      pRendInfo->m_ulLatestEventTime          = 0;
      pRendInfo->m_bIsFirstCallback     = TRUE;
      pRendInfo->m_ulLastSyncTime         = 0;
      pRendInfo->m_ulNextDueSyncTime      = m_pPlayer->m_ulCurrentPlayTime;

      /* Do we need to send a time sync for renderer duration? */
      if (bSeekToLastFrame || pRendInfo->m_ulNextDueSyncTime <= pRendInfo->m_ulDuration)
      {
          pRendInfo->m_bDurationTimeSyncSent  = FALSE;
          pRendInfo->m_bOnEndOfPacketSent = FALSE;
      }
      else
      {
          pRendInfo->m_bDurationTimeSyncSent  = TRUE;
      }

      m_pPlayer->m_pScheduler->Remove(
         pRendInfo->m_pTimeSyncCallback->GetPendingCallback());
        
        pRendInfo->m_pTimeSyncCallback->CallbackCanceled();

      if (!pRendInfo->m_bInitialBeginToBeSent)
      {
          pRendInfo->m_bInitialBeginToBeSent  = TRUE;
          m_pPlayer->EnterToBeginList(pRendInfo);
      }

      if (m_pSource->IsLive())
      {
          pRendInfo->m_BufferingReason    = BUFFERING_LIVE_PAUSE;
      }
      else
      {
          pRendInfo->m_BufferingReason    = BUFFERING_SEEK;
      }
    }

    m_bSeekToLastFrame = bSeekToLastFrame;
    m_llLatestPacketTime = 0;

    return HXR_OK;
}

HX_RESULT
SourceInfo::BeginTrack(void)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT         rc = HXR_OK;
    UINT32      ulDelay = 0;
    UINT32      ulPausedTime = 0;
    RendererInfo*   pRendInfo = NULL;
    STREAM_INFO*    pStreamInfo = NULL;
    CHXAudioPlayer* pAudioPlayer = NULL;
    CHXMapLongToObj::Iterator ndxRend;

    if (!m_pSource)
    {
      rc = HXR_UNEXPECTED;
      goto cleanup;
    }

    if (m_pSource->IsPaused())
    {
      ulPausedTime = m_pPlayer->m_ulCurrentPlayTime - m_ulPausedStartTime;    
      ulDelay = m_pSource->GetDelay() + ulPausedTime;
      
      // update source's delay time which will call sourceinfo's
      // UpdateDelay()
      m_pSource->UpdateDelay(ulDelay);

      // resume
      m_pSource->ResumeAudioStreams();

      rc = Begin();
    }
    // track is stopped ahead of its duration
    else if (m_bStopped)
    {
      m_bStopped = FALSE;
      m_bSeekPending = TRUE;
      m_ulSeekTime = m_pPlayer->m_ulCurrentPlayTime;
      
      m_pSource->ReSetup();
    }
    // either track has not been played yet
    // or track is still playing
    else
    {
      rc = HXR_FAILED;
      goto cleanup;
    }
   
cleanup:
    
    return rc;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */
}

HX_RESULT
SourceInfo::PauseTrack(void)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT     rc = HXR_OK;

    // stop the source
    if (m_pSource)
    {
      m_pSource->PauseAudioStreams();
    }

    m_ulPausedStartTime = m_pPlayer->m_ulCurrentPlayTime;
    rc = Pause();

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

HX_RESULT
SourceInfo::SeekTrack(UINT32 ulSeekTime)
{
    // low priority since it is rarely used by the SMIL
    return HXR_NOTIMPL;
}

HX_RESULT
SourceInfo::StopTrack(void)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT     rc = HXR_OK;

    m_bStopped = TRUE;

    // stop the source
    if (m_pSource)
    {
      m_pSource->RemoveAudioStreams();
    }

    Reset();

    m_bDone = TRUE;
    m_pPlayer->m_uNumSourcesActive--;

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

HX_RESULT
SourceInfo::SetSoundLevel(UINT16 uSoundLevel, BOOL bReflushAudioDevice)
{
    m_uSoundLevel = uSoundLevel;
    m_pSource->SetSoundLevel(uSoundLevel, bReflushAudioDevice);

    return HXR_OK;
}

void
SourceInfo::Reset()
{
    /* m_pSource should never be NULL */
    HX_ASSERT(m_pSource);

    if (!m_pSource)
    {
      return;
    }

#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    if(m_bIsPersistentSource)
    {
      m_bDone = FALSE;
      m_bAllPacketsReceived = FALSE;

      CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
      for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
      {
          RendererInfo* pRendInfo     = (RendererInfo*)(*ndxRend);
          IHXRenderer* pRend         = (IHXRenderer*)pRendInfo->m_pRenderer;
          STREAM_INFO*  pStreamInfo   = pRendInfo->m_pStreamInfo;
          pStreamInfo->m_bSrcInfoStreamDone  = FALSE;

          /* Reset the latest packet time */
          pRendInfo->m_ulLatestEventTime      = 0;

          m_pPlayer->m_pScheduler->Remove(
             pRendInfo->m_pTimeSyncCallback->GetPendingCallback());
        
            pRendInfo->m_pTimeSyncCallback->CallbackCanceled();

          pRendInfo->m_bIsFirstCallback       = TRUE;
          pRendInfo->m_ulLastSyncTime         = 0;
          pRendInfo->m_ulNumberOfPacketsQueued= 0;
          pRendInfo->m_ulNextDueSyncTime      = 0;
          if (!pRendInfo->m_bInitialBeginToBeSent && pRendInfo->m_pRenderer)
          {
            pRendInfo->m_bInitialBeginToBeSent  = TRUE;
            m_pPlayer->EnterToBeginList(pRendInfo);
          }
      }
    }
    else
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */
    { 
      DoCleanup();
      RenderersCleanup();
    }

    return;
}


void
SourceInfo::DoCleanup(EndCode endCode)
{
    if (m_pProcessCallback && m_pPlayer->m_pScheduler)
    {
      m_pPlayer->m_pScheduler->Remove(m_pProcessCallback->GetPendingCallback());
        m_pProcessCallback->CallbackCanceled();
    }

    if (m_bIsPersistentSource)
    {
      return;
    }

    m_bLocked = TRUE;
    m_pMutex->Lock();

    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo = (RendererInfo*)(*ndxRend);

      /* Tell each renderer that we are done with the stream */
      if(pRendInfo)
      {
            if (pRendInfo->m_pStream &&
                pRendInfo->m_pStreamInfo && pRendInfo->m_pStreamInfo->m_pHeader)
            {
                IHXBuffer* pMimeTypeBuffer = NULL;
              pRendInfo->m_pStreamInfo->m_pHeader->GetPropertyCString("MimeType", pMimeTypeBuffer);

              if (pMimeTypeBuffer && pMimeTypeBuffer->GetBuffer() &&
                    ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/vnd.rn-objectsstream") == 0 ||
                    ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/x-rn-objects") == 0 ||
                ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/vnd.rn-objects") == 0)
              {
                  m_pPlayer->m_pEngine->m_lROBActive--;
                    HX_ASSERT(m_pPlayer->m_pEngine->m_lROBActive >=0 );
              }

                HX_RELEASE(pMimeTypeBuffer);
            }

          if(pRendInfo->m_pRenderer)
            pRendInfo->m_pRenderer->EndStream();

          if (pRendInfo->m_bInitialBeginToBeSent)
          {
            m_pPlayer->RemoveFromPendingList(pRendInfo);
          }

          if (pRendInfo->m_pTimeSyncCallback)
          {
//{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p RELEASING TimeSyncCallback: Pending: %d Handle: %lu\n", pRendInfo->m_pTimeSyncCallback, (int)pRendInfo->m_bIsCallbackPending, (UINT32) pRendInfo->m_PendingHandle);::fclose(f1);}

              m_pPlayer->m_pScheduler->Remove(
                 pRendInfo->m_pTimeSyncCallback->GetPendingCallback());
        
                pRendInfo->m_pTimeSyncCallback->CallbackCanceled();
                HX_RELEASE(pRendInfo->m_pTimeSyncCallback);
          }

          HX_RELEASE(pRendInfo->m_pStream);
      }
    }

    // cleanup (i.e. registry)
    m_pSource->DoCleanup(endCode);

    UnRegister();

    m_lastError = HXR_OK;
    m_bAreStreamsSetup = FALSE;
    m_bDone = FALSE;
    m_bInitialized = FALSE;
    m_bSeekPending = FALSE;
    m_bSeekToLastFrame = FALSE;

    m_pMutex->Unlock();
    m_bLocked = FALSE;
}

void
SourceInfo::Stop(EndCode endCode)
{
    /* We have already been here once */
    if (m_pSource == NULL)
    {
      return;
    }

    DoCleanup(endCode);

    if (m_bIsPersistentSource)
    {
      return;
    }

    m_bLocked = TRUE;
    m_pMutex->Lock();

    m_pSource->Stop();

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (m_bTrackStoppedToBeSent)
    {
      m_pPlayer->m_pGroupManager->TrackStopped(m_uGroupID, m_uTrackID);  
      m_bTrackStoppedToBeSent = FALSE;
      if (m_pPeerSourceInfo)
      {
          m_pPeerSourceInfo->m_bTrackStoppedToBeSent = FALSE;
      }
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    m_pMutex->Unlock();
    m_bLocked = FALSE;
}

void
SourceInfo::Remove()
{
    // stop the source
    if (m_pSource)
    {
      m_pSource->RemoveAudioStreams();
    }

    m_bDone = TRUE;

    Stop();
    CloseRenderers();
}

/*
 * -- LIVE SYNC SUPPORT --
 *
 * SharedWallClock class is used for live sync support.
 * There is one of these objects per shared wall clock.
 *
 * This object will also be associated with an HXPlayer
 * since we won't ever share wall clocks between two players.
 * This is an intentional design choice, since it doesn't
 * reall make sense to do any sync-ing across multiple players.
 * 
 * This object will keep a list of source's that are sharing
 * it. This is mainly needed so that the wall clock can
 * reset the start time for all the sources in the event that
 * it gets a new start time that is earlier than it had
 * previously thought. Basically, the start time of the wall
 * clock is what does the syncing.      
 */
SharedWallClock::SharedWallClock
(
    const char* pName, 
    UINT32 ulStartTime,
    HXPlayer* pPlayer
)
    : m_ulStartTime(ulStartTime)
    , m_strName(pName)
    , m_pPlayer(pPlayer)
{
    HX_ASSERT(m_pPlayer);
    (*m_pPlayer->m_pSharedWallClocks)[pName] = this;
};

/*
 * -- LIVE SYNC SUPPORT --
 *
 * Obviously this is the method that handles resyncing the
 * start times for all the sources that share the wall clock.
 *
 * This method also returns the start time. The intended useage
 * is for the caller to pass the start time that it expects, and
 * then respect the start time that is returned. In the event that
 * the input start time is less than the previously known start
 * time, then all sources are reset.
 */
UINT32
SharedWallClock::ResetStartTime(UINT32 ulStartTime)
{
    if (ulStartTime < m_ulStartTime)
    {
      m_ulStartTime = ulStartTime;
      CHXSimpleList::Iterator indx = m_UserList.Begin();

      for (; indx != m_UserList.End(); ++indx)
      {
          SourceInfo* pSourceInfo = (SourceInfo*)(*indx);
          pSourceInfo->ResetStartTime(ulStartTime);
      }
    }
    return m_ulStartTime;
};

/*
 * -- LIVE SYNC SUPPORT --
 *
 * Nothing tricky here, we just track the incoming user on our
 * list of known users.
 */
void
SharedWallClock::AddUser(SourceInfo* pSourceInfo)
{
    m_UserList.AddTail(pSourceInfo);
};

/*
 * -- LIVE SYNC SUPPORT --
 *
 * This method removes users from the shared clock's user list
 * and also cleans up the shared clock when the last user is
 * removed. So, any caller of this method should take note to
 * NOT use the shared clock after calling this method.
 */
void
SharedWallClock::RemoveUser(SourceInfo* pSourceInfo)
{
    LISTPOSITION pos = m_UserList.Find(pSourceInfo);
    HX_ASSERT(pos);

    m_UserList.RemoveAt(pos);
    
    if (m_UserList.IsEmpty())
    {
      m_pPlayer->m_pSharedWallClocks->RemoveKey(m_strName);
      delete this;
    }
};

/*
 * -- LIVE SYNC SUPPORT --
 *
 * If the start time is changed for a source then all the
 * renderer's need to have their start time's reset. This
 * method just loops through the renderer info to do the work.
 */
void
SourceInfo::ResetStartTime(UINT32 ulStartTime)
{
    if (ulStartTime < m_ulStreamStartTime)
    {
      m_ulStreamStartTime = ulStartTime;
      CHXMapLongToObj::Iterator indx = m_pRendererMap->Begin();

      for (; indx != m_pRendererMap->End(); ++indx)
      {
          RendererInfo* pRendererInfo = (RendererInfo*)(*indx);
          pRendererInfo->m_ulStreamStartTime = ulStartTime;
      }
    }
};

/*
 * -- LIVE SYNC SUPPORT --
 *
 * This is the real work horse for live sync support. This
 * method actually determines if the URL for the source is
 * targeted at a shared wall clock by looking for the wallclock
 * option in the URL.
 *
 * If the wallclock name is found then we try to find the wall
 * clock object for this name and player. If we don't find it
 * then we create a new clock. If we do find it then we want
 * to determine if the start time should be reset to the lower
 * value. We also return the start time to be stored in the
 * renderers.
 */
UINT32
SourceInfo::CalculateLiveStartTime(IHXPacket* pFirstPacket)
{
    UINT32 ulStreamStartTime = pFirstPacket->GetTime();;

    /*
     * Find out if this live feed has a "wallclock" property.
     */
    CHXURL* pURL = m_pSource->GetCHXURL();
    IHXValues*  pValues = pURL->GetOptions();
    IHXBuffer* pWallClockName = NULL;

    pValues->GetPropertyBuffer("wallclock", pWallClockName);

    if (pWallClockName)
    {
      m_strWallClockName = (const char*)pWallClockName->GetBuffer();

      /* We shouldn't already have a wall clock! */
      HX_ASSERT(m_pWallClock == NULL);

      /*
       * Lookup a wall clock with this name, if it's not found then
       * we are the first one, and we should create a shared wallclock
       * object, add it to the list, and do the standard setup.
       */
      void* pLookupResult = NULL;
      if (!m_pPlayer->FindSharedWallClocks(m_strWallClockName,pLookupResult))
      {
          m_pWallClock = new SharedWallClock(m_strWallClockName,
                              ulStreamStartTime,
                              m_pPlayer);
      }
      else
      {
          m_pWallClock = (SharedWallClock*)pLookupResult;
          ulStreamStartTime = m_pWallClock->ResetStartTime(ulStreamStartTime);
      }
      m_pWallClock->AddUser(this);
    }

    HX_RELEASE(pValues);
    HX_RELEASE(pWallClockName);

    return ulStreamStartTime;
}

/*
 * -- LIVE SYNC SUPPORT --
 *
 * Basic clean up support for wall clock object. Notice that after
 * calling RemoveUser, you can use the wall clock object since it
 * may get deleted... so we always reset our wall clock object
 * pointer to NULL.
 */
void
SourceInfo::DoneWithWallClock()
{
    if (m_pWallClock)
    {
      m_pWallClock->RemoveUser(this);
      m_pWallClock = NULL;
    }
}

HX_RESULT
SourceInfo::ProcessIdle(BOOL      bIsFirst,
                    ULONG32&    ulNumStreamsToBeFilled,
                    BOOL&       bIsBuffering,
                    UINT16&     uLowestBuffering,
                    BOOL          bPersistent)
{
    HX_RESULT           theErr                = HXR_OK;
    CHXEvent*          pEvent              = NULL;
    HXSource*          pSource             = NULL;
    IHXPendingStatus*  pStatus             = NULL;
    RendererInfo*       pRendInfo           = NULL;
    IHXValues*         pHeader             = NULL;
    HXStream*          pStream             = NULL;
    IHXRenderer*       pRenderer           = NULL;
    STREAM_INFO*        pStreamInfo         = NULL;
    IHXPacket*         pPacket             = NULL;
    UINT16              unStatusCode        = 0;
    UINT16              unPercentDone       = 0;
    UINT32        ulPacketTime          = 0;
    INT64         llActualPacketTime  = 0;
    INT64         llLastExpectedPacketTime = 0;
    IHXBuffer*         pStatusDesc         = NULL;
    BOOL          bAtInterrupt          = FALSE;

    bAtInterrupt = m_pPlayer->m_pEngine->AtInterruptTime();

    if (m_bStopped)
    {
      return HXR_OK;
    }

    /* Check if a source has not been initialized. This will happen
     * ONLY when we start a new track in the mid of a presentation
     */
    if (!m_bInitialized)
    {
      /* Do not initialize source at interrupt time */
      if (bAtInterrupt)
      {
          ScheduleProcessCallback();
          return HXR_OK;
      }

      theErr = InitializeAndSetupRendererSites();

      if (theErr || !m_bInitialized)
      {
          return theErr;
      }
    }

    if (m_bSeekPending)
    {
      m_bSeekPending = FALSE;
      
      Pause();
      Seek(m_ulSeekTime);
      m_pSource->DoSeek(m_ulSeekTime);
      Begin();
    }

    pSource = m_pSource;
    pStatus = m_pStatus;

    // don't start getting events till the player setup has been
    // done   
    if (!m_pPlayer->m_bInitialized  || 
      m_pPlayer->m_bSetupToBeDone || 
      m_pPlayer->m_bPostSetupToBeDone)
    {
      return HXR_OK;
    }
    
    UINT16  uIndex      = 0;
    BOOL    bHandled    = TRUE;
    llLastExpectedPacketTime = m_pSource->GetLastExpectedPacketTime();

    LISTPOSITION posRend = m_pCurrentScheduleList->GetHeadPosition();
    for (; uIndex < m_pCurrentScheduleList->GetCount(); uIndex++)
    {
      BOOL  bSentMe = TRUE;
      BOOL  bEndMe = FALSE;   
      llActualPacketTime = 0;
      
      theErr = HXR_OK;

      if (uIndex > 0)
      {
          if (bHandled)
          {
            posRend = m_pCurrentScheduleList->RemoveAt(posRend);
            LISTPOSITION listRet = m_pCurrentScheduleList->AddTail(pRendInfo);
                // This check is critical for catching oom errors. XXXJHHB
                if( listRet == NULL )
                {
                    return HXR_OUTOFMEMORY;
                }
          }
          else
          {
            m_pCurrentScheduleList->GetNext(posRend);
          }
      }

      bHandled = TRUE;
      pRendInfo       = (RendererInfo*) 
                  m_pCurrentScheduleList->GetAt(posRend);

      pStreamInfo     = pRendInfo->m_pStreamInfo;

      if (pStreamInfo->m_bSrcInfoStreamDone)
      {
          // SPECIAL CASE:
          // the player received all the packets(m_bSrcStreamDone is TRUE) and 
          // EndOfPacket() hasn't been sent to the renderer yet, 
          // BUT the renderer still calls ReportRebufferStatus()  
          if (!IsRebufferDone())
          {
            bIsBuffering = TRUE;
          }
          else
          {
            CheckIfDone();
          }
          continue;
      }

      if (bIsFirst)
      {
          pStreamInfo->m_bSrcInfoStreamFillingDone = FALSE;
          ulNumStreamsToBeFilled++;
      }

      BOOL bThisSourceBuffering = FALSE;

      if (!bPersistent)
      {
          // every HXSource has to implement IID_IHXPendingStatus
          HX_ASSERT(pStatus);
          HX_VERIFY(HXR_OK == pStatus->GetStatus(unStatusCode, pStatusDesc,
                                       unPercentDone));
          HX_RELEASE(pStatusDesc);

          if ((HX_STATUS_BUFFERING == unStatusCode && unPercentDone < 100) ||
            HX_STATUS_CONTACTING == unStatusCode)
          {
            bIsBuffering            = TRUE;
            bThisSourceBuffering    = TRUE;

            if (uLowestBuffering > unPercentDone)
            {
                uLowestBuffering = unPercentDone;
            }
          }
      }

      /* the event times are actual ts - preroll.. so we do not
       * need to add preroll in calculations here...
       */     
       
      UINT32 ulDeliveryTime = m_pPlayer->m_ulCurrentPlayTime + 
                           m_pPlayer->m_ulLowestGranularity;

#ifdef _MACINTOSH
#define ADDITIONAL_PREDELIVERY_TIME 4000
      /* on Mac we try to be even farther ahead than the timeline in
       * packet delivery since the callbacks are not that smooth
       * and if we are really close to the wire, it results in
       * unnecccessary re-buffers. 
       */ 
      ulDeliveryTime += ADDITIONAL_PREDELIVERY_TIME;
#endif
      
      if (pSource)
      {
          pSource->FillRecordControl();
      }

      if (bPersistent || bThisSourceBuffering ||
          (pRendInfo->m_ulLatestEventTime <= ulDeliveryTime))
      {       
          theErr = pSource->GetEvent(pStreamInfo->m_uStreamNumber, pEvent);

          if (!theErr)
          {
            pPacket = pEvent->GetPacket();

            if (pEvent->IsPreSeekEvent())
            {
                 // associate the packet with its renderer..
                 pEvent->m_pRendererInfo   = pRendInfo;               
                 if (!bAtInterrupt || pRendInfo->m_bInterruptSafe)
                 {
                   theErr = m_pPlayer->SendPacket(pEvent);
                   delete pEvent;
                 }
                 else
                 {
                  // insert event in the common packet/event list...
                  theErr = m_pPlayer->m_EventList.InsertEvent(pEvent);
                        if( theErr == HXR_OUTOFMEMORY )
                        {
                            return HXR_OUTOFMEMORY;
                        }
                  pRendInfo->m_ulNumberOfPacketsQueued++;
                 }

                 continue;
            }

            if (!pPacket->IsLost())
            {
                ulPacketTime = pPacket->GetTime();

                llActualPacketTime = 
                  pRendInfo->m_pStreamInfo->BufferingState().CreateINT64Timestamp(ulPacketTime);

                if (m_llLatestPacketTime < llActualPacketTime)
                {
                  m_llLatestPacketTime = llActualPacketTime;
                }

                pRendInfo->m_ulLatestEventTime  = pEvent->GetTimeStartPos();
                
                if (pSource->IsLive() && pRendInfo->m_bIsFirstPacket)
                {
                  pRendInfo->m_bIsFirstPacket     = FALSE;

                  /*
                   * -- LIVE SYNC SUPPORT --
                   *
                   * We used to just set the stream start time to the 
                   * timestamp of this first packet. Now we use this
                   * helper function to implement support for sharing
                   * start times for sources off of the same wall clock.
                   * See other LIVE SYNC SUPPORT comments for more 
                   * details.
                   */
                  UINT32 ulLiveStart = CalculateLiveStartTime(pPacket);
                  pRendInfo->m_ulStreamStartTime = ulLiveStart;
                  m_ulStreamStartTime = ulLiveStart;

                  UINT32  ulLowestTime = 0;
                  BOOL    bAtLeastOneLowestTime = FALSE;
                  UINT16  uNumLowestKnown = 0;
                  CHXMapLongToObj::Iterator tmpndxRend = m_pRendererMap->Begin();

                  for (;!theErr && tmpndxRend != m_pRendererMap->End();
                        ++tmpndxRend)
                  {
                      RendererInfo* pTmpRendInfo  = (RendererInfo*)(*tmpndxRend);
                      /* Have we received the lowest packet?*/
                      if (!pTmpRendInfo->m_bIsFirstPacket)
                      {
                        uNumLowestKnown++;
                        if (!bAtLeastOneLowestTime)
                        {
                            bAtLeastOneLowestTime = TRUE;
                            ulLowestTime = pTmpRendInfo->m_ulStreamStartTime;
                            SetLiveSyncStartTime(pSource, pTmpRendInfo, ulLowestTime);
                        }
                        else
                        {
                            if (ulLowestTime > pTmpRendInfo->m_ulStreamStartTime)
                            {
                              ulLowestTime = pTmpRendInfo->m_ulStreamStartTime;
                            }
                        }
                      }
                  }

                  if (uNumLowestKnown > 1)
                  {
                      tmpndxRend = m_pRendererMap->Begin();

                      for (;!theErr && tmpndxRend != m_pRendererMap->End();
                            ++tmpndxRend)
                      {
                        RendererInfo* pTmpRendInfo      = (RendererInfo*)(*tmpndxRend);
                        /* Have we received the lowest packet?*/
                        if (!pTmpRendInfo->m_bIsFirstPacket)
                        {
                            pTmpRendInfo->m_ulStreamStartTime = ulLowestTime;
                            SetLiveSyncStartTime(pSource, pTmpRendInfo, ulLowestTime);
                        }
                      }
                  }
                }

                if ((!pSource->IsLive() || pSource->isRestrictedLiveStream()) &&
                  llActualPacketTime > llLastExpectedPacketTime)
                {
                  // XXX HP
                  // work around since the rule flag of all RTSP packets are set to
                  // HX_ASM_SWITCH_ON only and this could cause the stream doesn't end 
                  // properly if its endtime was changed after the first resume has been 
                  // sent
                  // THIS WILL BE FIXED IN THE NEXT SERVER RELEASE("dial-tone")  
                  if (pSource->m_bRTSPRuleFlagWorkAround)
                  {
                      bSentMe = FALSE;
                      bEndMe = TRUE;
                  }
                  else 
                  {
                      pRendInfo->m_pStream->PostEndTimePacket(pPacket, bSentMe, bEndMe);
                  }
                }
            }               

            if (bSentMe)
            {               
                // clear up the post events which were not sent
                if (pStreamInfo->m_pPostEndTimeEventList)
                {
                  while (pStreamInfo->m_pPostEndTimeEventList->GetNumEvents())
                  {
                      CHXEvent* pPostEndTimeEvent = pStreamInfo->m_pPostEndTimeEventList->RemoveHead();

                      // associate the packet with its renderer..
                      pPostEndTimeEvent->m_pRendererInfo   = pRendInfo;
                      // insert event in the common packet/event list...
                      theErr = m_pPlayer->m_EventList.InsertEvent(pPostEndTimeEvent);
                            if( theErr == HXR_OUTOFMEMORY )
                            {
                                return HXR_OUTOFMEMORY;
                      }
                      pRendInfo->m_ulNumberOfPacketsQueued++;
                  }
                }

                // associate the packet with its renderer..
                pEvent->m_pRendererInfo   = pRendInfo;
                // insert event in the common packet/event list...
                theErr = m_pPlayer->m_EventList.InsertEvent(pEvent);
                if( theErr == HXR_OUTOFMEMORY )
                    {
                        return HXR_OUTOFMEMORY;
                }
                pRendInfo->m_ulNumberOfPacketsQueued++;
            }
            else
            {
                if (!pStreamInfo->m_pPostEndTimeEventList)
                {
                  pStreamInfo->m_pPostEndTimeEventList = new CHXEventList();
                }

                if (pStreamInfo->m_pPostEndTimeEventList)
                {
//{FILE* f1 = ::fopen("c:\\temp\\out.txt", "a+"); ::fprintf(f1, "bSentMe is FALSE PacketTime: %lu PacketRule: %u\n", pEvent->GetPacket()->GetTime(), pEvent->GetPacket()->GetASMRuleNumber());::fclose(f1);}                  
                  theErr = pStreamInfo->m_pPostEndTimeEventList->InsertEvent(pEvent);
                  if( theErr == HXR_OUTOFMEMORY )
                  {
                      return theErr;
                  }
                }
            }
          }
          else
          {
            bHandled = FALSE;
          }

          if (theErr && !bPersistent)
          {
            if (!pStreamInfo->m_bSrcInfoStreamFillingDone &&
                ulNumStreamsToBeFilled > 0)
            {
                pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE;
                ulNumStreamsToBeFilled--;
            }
          }
      }
      else
      {
          if (!pStreamInfo->m_bSrcInfoStreamFillingDone &&
            ulNumStreamsToBeFilled > 0)
          {
            pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE;
            ulNumStreamsToBeFilled--;
          }
      }

      if (theErr == HXR_BUFFERING)
      {
          if (bPersistent)
          {
            bIsBuffering    = TRUE;
          }
      }
      else if (theErr == HXR_AT_END)
      {
          if (!pStreamInfo->m_bSrcInfoStreamDone)
          {
            if (!bAtInterrupt || pRendInfo->m_bInterruptSafe)
            {
                pStreamInfo->m_bSrcInfoStreamDone = TRUE;

                pStreamInfo->ResetPostEndTimeEventList();

                if (pRendInfo->m_ulNumberOfPacketsQueued == 0 &&
                  pRendInfo->m_pRenderer)
                {             
                  m_pPlayer->SendPostSeekIfNecessary(pRendInfo);
                  pRendInfo->m_pRenderer->OnEndofPackets();
                  pRendInfo->m_bOnEndOfPacketSent = TRUE;   
                }

                CheckIfDone();
            }
            else
            {
                ScheduleProcessCallback();
                continue;
            }
          }
      }
      else if (theErr == HXR_NO_DATA)
      {
          /* mask this error */
          theErr  = HXR_OK;
      }
      if (!llActualPacketTime)
      {
          STREAM_INFO* pStrInfo = pRendInfo->m_pStreamInfo;
          UINT32 ulPktTime = 
            pStrInfo->BufferingState().LastPacketTimestamp();
          llActualPacketTime = 
            pStrInfo->BufferingState().CreateINT64Timestamp(ulPktTime);
          
          /* if this is a stream where we do not have to wait to receive 
           * a packet >= stream's last expected packet time, 
           * make the highest timestamp to be the HIGHEST timestamp
           * across ALL streams for this source.
           *
           * This is to fix end tag support on sources with sparse streams
           * e.g. audio/video with an event stream where we may not really 
           * have a packet till way down in the future.  
           */ 
          if (pRendInfo->m_pStreamInfo->m_bCanBeStoppedAnyTime &&
            !pStreamInfo->m_bSrcInfoStreamDone &&
            m_llLatestPacketTime > llLastExpectedPacketTime)
          {
            /* check if ALL other streams have ended */
            if (AllOtherStreamsHaveEnded(pStreamInfo))
            {
                    /*
                     * The logic above was designed to handle endTime's
                     * on a/v streams, so that once we received a/v packets
                     * past the end time (even though more packets are 
                     * still coming in), we can go ahead and end the
                     * event stream. However, this was causing a bug
                     * where syncmm event streams were getting terminated
                     * even though there was a packet waiting for it
                     * at the transport. This additional test imposes
                     * that we don't terminate the stream unless we
                     * have no packets waiting at the transport AND
                     * the stream has said it's done.
                     */
                    if (pStreamInfo->BufferingState().DoneAtTransport())
                    {
                    bEndMe          = TRUE;
                    llActualPacketTime  = m_llLatestPacketTime;
                    }
            }
          }
      }

      if (!bPersistent && 
          (!pSource->IsLive() || pSource->isRestrictedLiveStream()) && 
          !pStreamInfo->m_bSrcInfoStreamDone &&
          llActualPacketTime > llLastExpectedPacketTime &&
          bEndMe)
      {
          if (!bAtInterrupt || pRendInfo->m_bInterruptSafe)
          {
            pStreamInfo->m_bSrcInfoStreamDone = TRUE;

            pStreamInfo->ResetPostEndTimeEventList();

            if (!pStreamInfo->m_bSrcInfoStreamFillingDone &&
                ulNumStreamsToBeFilled > 0)
            {
                pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE;
                ulNumStreamsToBeFilled--;
            }

            if (pRendInfo->m_ulNumberOfPacketsQueued == 0 &&
                pRendInfo->m_pRenderer)
            {
                m_pPlayer->SendPostSeekIfNecessary(pRendInfo);
                pRendInfo->m_pRenderer->OnEndofPackets();
                pRendInfo->m_bOnEndOfPacketSent = TRUE;     
            }

            if (!pSource->isRestrictedLiveStream())
            {
                CheckIfDone();
            }
          }
          else
          {
            ScheduleProcessCallback();
            continue;
          }
      }
    }

    if (!bPersistent && 
      m_bInitialized &&
      m_ulSourceDuration < m_pPlayer->m_ulCurrentPlayTime && 
      m_pSource && 
      !m_pSource->IsLive() &&
      m_pSource->IsActive())
    {
      /* Remove bandwidth usage for this source */
      m_pSource->AdjustClipBandwidthStats(FALSE);
    }
    else if (m_bInitialized &&
          m_pSource &&
          m_pPlayer->m_ulCurrentPlayTime > m_pSource->GetDelay() &&
          m_pPlayer->m_ulCurrentPlayTime <= m_ulSourceDuration && 
          !m_pSource->IsActive())
    {
      /* Add bandwidth usage for this source */
      m_pSource->AdjustClipBandwidthStats(TRUE);
    }

    return HXR_OK;
}

HX_RESULT
SourceInfo::Register()
{
    HX_RESULT theErr = HXR_OK;
    if (!m_bIsRegisterSourceDone)
    {
      m_bIsRegisterSourceDone = TRUE;

      if (m_pSource->m_bSureStreamClip)
      {
          m_pPlayer->SureStreamSourceRegistered(this);
      }
      
      m_pSource->CanBeFastStarted();

#if defined(HELIX_FEATURE_ASM)
      /* Register Source with ASM Bandwidth Manager */
      IHXBandwidthManager* pMgr = 0;

      HX_VERIFY(HXR_OK == m_pPlayer->QueryInterface(
          IID_IHXBandwidthManager, (void **)&pMgr));

      theErr = pMgr->RegisterSource(m_pSource, (IUnknown*) (IHXPlayer*) m_pPlayer);
      pMgr->Release();
#endif /* HELIX_FEATURE_ASM */
    }

    return theErr;
}

HX_RESULT
SourceInfo::UnRegister()
{
    HX_RESULT theErr = HXR_OK;
    if (m_bIsRegisterSourceDone)
    {
      m_bIsRegisterSourceDone = FALSE;

      if (m_pSource->m_bSureStreamClip)
      {
          m_pPlayer->SureStreamSourceUnRegistered(this);
      }

#if defined(HELIX_FEATURE_ASM)
      /* Register Source with ASM Bandwidth Manager */
      IHXBandwidthManager* pMgr = 0;

      HX_VERIFY(HXR_OK == m_pPlayer->QueryInterface(
          IID_IHXBandwidthManager, (void **)&pMgr));

      HX_ASSERT(pMgr) ;
      if (pMgr)
      {
            theErr = pMgr->UnRegisterSource(m_pSource);
            pMgr->Release();
      }

        CheckIfDone();
#endif /* HELIX_FEATURE_ASM */
    }

    return theErr;
}

void        
SourceInfo::ChangeAccelerationStatus(BOOL bMayBeAccelerated,
                             BOOL bUseAccelerationFactor,
                             UINT32 ulAccelerationFactor)
{
    IHXBandwidthManager* pMgr = 0;

    HX_VERIFY(HXR_OK == m_pPlayer->QueryInterface(
      IID_IHXBandwidthManager, (void **)&pMgr));

    if (pMgr)
    {
      pMgr->ChangeAccelerationStatus(m_pSource, bMayBeAccelerated,
                               bUseAccelerationFactor, ulAccelerationFactor);
      pMgr->Release();
    }
}

void SourceInfo::CheckIfDone()
{
    BOOL bIsDone = TRUE;
    CHXMapLongToObj::Iterator   ndxRend;
    RendererInfo*   pRendInfo   = NULL;
    STREAM_INFO*    pStreamInfo = NULL;

    // keep the source active throughout the duration
    // of source
    if (m_bDone                           &&
      m_bActive                     && 
      m_pPlayer->m_uNumSourcesActive > 0  &&
      !KeepSourceActive())
    {   
      m_bActive = FALSE;
      m_pPlayer->m_uNumSourcesActive--;
    }

    if (!m_bDone)
    {
      ndxRend = m_pRendererMap->Begin();

      for (;ndxRend != m_pRendererMap->End(); ++ndxRend)
      {
          pRendInfo       = (RendererInfo*)(*ndxRend);
          pStreamInfo     = pRendInfo->m_pStreamInfo;

          if (!pStreamInfo->m_bSrcInfoStreamDone)
          {
            bIsDone = FALSE;
            break;
          }
      }

      if (bIsDone || m_pSource->IsSourceDone())
      {
          m_bDone = TRUE;     

          if (!m_bAllPacketsReceived)
          {
            m_bAllPacketsReceived = TRUE;
            // If we are done receiving all the packets, release bandwidth
            UnRegister();
          }

          if (!m_pSource->IsSourceDone())
          {
            m_pSource->SetEndOfClip(TRUE);
          }

          if (m_pPlayer->m_uNumCurrentSourceNotDone > 0)
          {
            m_pPlayer->m_uNumCurrentSourceNotDone--;
          }
      }
    }

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (!m_bActive && 
      m_bTrackStoppedToBeSent &&
      !m_pPlayer->m_pEngine->AtInterruptTime())
    {
      // send TrackStopped at the end of its active duration
      m_bTrackStoppedToBeSent = FALSE;
      m_pPlayer->m_pGroupManager->TrackStopped(m_uGroupID, m_uTrackID);  
      if (m_pPeerSourceInfo)
      {
          m_pPeerSourceInfo->m_bTrackStoppedToBeSent = FALSE;
      }
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

void
SourceInfo::SetupRendererSites(BOOL bIsPersistent)
{
    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo   = (RendererInfo*) (*ndxRend);
      IHXRenderer* pRenderer   = (IHXRenderer*) pRendInfo->m_pRenderer;

      HX_DISPLAY_TYPE    ulFlags;
      IHXBuffer*         pInfoBuffer = NULL;

      /*
       * Find out if the renderer is a display type renderer.
       */
      if (HXR_OK == pRenderer->GetDisplayType(ulFlags,pInfoBuffer))
      {
          HX_RELEASE(pInfoBuffer);
          if (HX_DISPLAY_WINDOW == (HX_DISPLAY_WINDOW & ulFlags))
          {
            STREAM_INFO*  pStreamInfo = pRendInfo->m_pStreamInfo;
            IHXValues*   pProps      = pStreamInfo->m_pStreamProps;
            /*
             * Call the helper function that handles setup of a
             * renderer site. This function will do the
             * whole process of finding out if a site exists by
             * PlayToFrom; if not, it calls the site supplier; then it
             * it actually hooks up the SiteUserSupplier with all
             * the appropriate sites, etc.
             */
            m_pPlayer->SetupRendererSite(pRenderer,pProps,bIsPersistent);
          }
      }
    }
}


HX_RESULT
SourceInfo::InitializeRenderers(BOOL& bSourceInitialized)
{
    HX_RESULT   theErr              = HXR_OK;
    HX_RESULT     theFinalErr     = HXR_OK;
    IHXValues* pHeader             = NULL;
    HXStream*  pStream             = NULL;
    IHXRenderer*   pRenderer       = NULL;
    IHXBuffer* pMimeTypeBuffer     = NULL;
    IUnknown*   pUnkRenderer        = NULL;
    STREAM_INFO*    pStreamInfo     = NULL;
    BOOL    bAddDefaultUpgrade  = FALSE;

    bSourceInitialized = FALSE;

    if (m_pPlayer->m_pEngine->AtInterruptTime()) //for Mac
    {
      return HXR_OK;
    }

    if (m_pSource->GetLastError() != HXR_OK)
    {
      /* Since the source has an error, mark plugin load attempt
       * to TRUE so that the player object can request upgrade
       * if it needs to
       */
      m_bLoadPluginAttempted = TRUE;
      return HXR_OK;
    }

    if (!m_pSource->IsInitialized())
    {
      // atleast one source is not yet initialized
      return HXR_OK;
    }

    bSourceInitialized = TRUE;

#if defined(HELIX_FEATURE_NESTEDMETA)
    IHXPersistentComponent* pPersistentComponent = NULL;

    if (HXR_OK == m_pPlayer->m_pPersistentComponentManager->GetPersistentComponent(m_ulPersistentComponentID,
                                                               pPersistentComponent))
    {
      // no need to AddRef() since it's maintained by PersistentManager
      m_pRendererAdviseSink = ((HXPersistentComponent*)pPersistentComponent)->m_pRendererAdviseSink;
      m_pRendererAdviseSink->AddRef();
    }

    HX_RELEASE(pPersistentComponent);
#endif /* HELIX_FEATURE_NESTEDMETA */

    theErr = SetupStreams();

    if (m_bIndefiniteDuration ||
      m_pSource->IsLive()     || 
      m_pPlayer->IsLive())
    {
      m_pPlayer->m_bIsLive = TRUE;
      
      m_pPlayer->m_pAudioPlayer->SetLive(m_pPlayer->m_bIsLive);

      if (m_pSource->isRestrictedLiveStream())
      {
          m_pPlayer->SetPresentationTime(max(m_pPlayer->m_ulPresentationDuration, GetActiveDuration()));
      }
      else
      {
          m_pPlayer->SetPresentationTime(0);
      }
    }
    else
    {
      m_pPlayer->SetPresentationTime(max(m_pPlayer->m_ulPresentationDuration, GetActiveDuration()));
    }

    // attemp to load all the plugins
    m_bLoadPluginAttempted = TRUE;

    UINT16 uNumStreams = m_pSource->GetNumStreams();
    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (UINT16 i = 0; ndxRend != m_pRendererMap->End(); ++ndxRend, i++)
    {
      RendererInfo*     pRendInfo = (RendererInfo*)(*ndxRend);

      pStreamInfo = pRendInfo->m_pStreamInfo;
      pHeader         = pStreamInfo->m_pHeader;
      pStream         = pRendInfo->m_pStream;
      
      HX_ASSERT(pHeader);
      HX_ASSERT(pStream);

      pRenderer       = NULL;
      pUnkRenderer    = NULL;
      bAddDefaultUpgrade  = FALSE;
      HX_RELEASE(pMimeTypeBuffer);

      pHeader->GetPropertyCString("MimeType", pMimeTypeBuffer);

      HX_ASSERT(pMimeTypeBuffer && pMimeTypeBuffer->GetBuffer());
      if (!pMimeTypeBuffer || !pMimeTypeBuffer->GetBuffer())
      {
          GOTOEXITONERROR(theErr = HXR_NOT_INITIALIZED, exit);
      }

      /* 
       * Check for "CanBeStoppedAnyTime" property. For streams with this 
       * property, we do not have to wait to receive a 
       * packet with timestamp >= lastPacketTime. 
       * We can instead use the highest timestamp received across
       * ALL the streams in a given source 
       */
      UINT32 ulCanBeStoppedAnyTime = 0;
      if (pHeader->GetPropertyULONG32("CanBeStoppedAnyTime", ulCanBeStoppedAnyTime) == HXR_OK)      
      {   
          pStreamInfo->m_bCanBeStoppedAnyTime = (ulCanBeStoppedAnyTime == 1);
      }
      /* temporary hack till we fix rmff fileformat to correctly set this
       * property AND the servers areupdated to have this fixed fileformat.
       */
      else if (::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/x-pn-realevent") == 0 ||
             ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "syncMM/x-pn-realvideo") == 0)
      {
          pStreamInfo->m_bCanBeStoppedAnyTime = TRUE;
      }
      else if (::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/vnd.rn-objectsstream") == 0 ||
                ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/x-rn-objects") == 0 ||
             ::strcasecmp((const char*) pMimeTypeBuffer->GetBuffer(), "application/vnd.rn-objects") == 0)
      {
          m_pPlayer->m_pEngine->m_lROBActive++;
      }

      IHXPluginHandler3* pPlugin2Handler3 = NULL;
      HX_VERIFY(HXR_OK ==
          m_pPlayer->m_pPlugin2Handler->QueryInterface(IID_IHXPluginHandler3, (void**) &pPlugin2Handler3));

      if (!(HXR_OK == pPlugin2Handler3->FindGroupOfPluginsUsingStrings(PLUGIN_CLASS, PLUGIN_RENDERER_TYPE, 
          PLUGIN_RENDERER_MIME, (char*)pMimeTypeBuffer->GetBuffer(), NULL, NULL, pRendInfo->m_pRendererEnumerator) &&
          pRendInfo->m_pRendererEnumerator &&
          (HXR_OK == pRendInfo->m_pRendererEnumerator->GetNextPlugin(pUnkRenderer, NULL)) &&
          pUnkRenderer))
      {
#if defined(HELIX_FEATURE_AUTOUPGRADE)
          if(m_pPlayer->m_pUpgradeCollection)
            m_pPlayer->m_pUpgradeCollection->Add(eUT_Required, pMimeTypeBuffer, 0, 0);
#endif /* HELIX_FEATURE_AUTOUPGRADE */

          theErr = HXR_NO_RENDERER;
      }

      HX_RELEASE(pPlugin2Handler3);

      GOTOEXITONERROR(theErr, nextrend);

tryNextRendererForSameMimeType:
      HX_ASSERT(pUnkRenderer);
      pUnkRenderer->QueryInterface(IID_IHXRenderer, (void**) &pRenderer);
      theErr = pStream->SetRenderer(pUnkRenderer);

      GOTOEXITONERROR(theErr, nextrend);
      HX_RELEASE(pUnkRenderer);

        // now get the TAC info for this track/source
        UINT32 sourceID;
      sourceID        = 0;
        if (HXR_OK == m_pSource->GetID(sourceID))
        {
            m_pPlayer->CheckTrackAndSourceOnTrackStarted(m_uGroupID, m_uTrackID, sourceID);
        }

      if (!pStreamInfo->m_pStreamProps)
      {
          // Create an IHXValues for storing stream properties related
          // to metafile initilization and layout hookup.
          pStreamInfo->m_pStreamProps = new CHXHeader();
          pStreamInfo->m_pStreamProps->AddRef();
      }

      IHXBuffer* pStreamPlayTo;
      pStreamPlayTo = NULL;
      // If the stream doesn't have a playto property, than
      // check if the parent source has a playto property
      if ((HXR_OK != pStreamInfo->m_pStreamProps->GetPropertyCString("playto",pStreamPlayTo)) ||
          !pStreamPlayTo)
      {
          /* Set region name to playto property */
          pStreamInfo->m_pStreamProps->GetPropertyCString("region",pStreamPlayTo);
          
          /* create a unique value */
          if (!pStreamPlayTo)
          {
            char szBuffer[14]; /* Flawfinder: ignore */
            ULONG32 length = SafeSprintf(szBuffer,14, "%#010lx",(ULONG32)(void*)pStreamInfo); /* Flawfinder: ignore */

            pStreamPlayTo = (IHXBuffer*) new CHXBuffer();
            pStreamPlayTo->AddRef();

            pStreamPlayTo->Set((UCHAR*)szBuffer,length+1);
          }

          pStreamInfo->m_pStreamProps->SetPropertyCString("playto",pStreamPlayTo);
      }

      HX_RELEASE(pStreamPlayTo);

      theErr = SetupRenderer(pRendInfo, pRenderer, pStreamInfo, pStream);

nextrend:
      if (theErr)
      {
          if (theErr == HXR_OUTOFMEMORY)
          {
            m_pPlayer->Report( HXLOG_ERR, theErr, 0, NULL, NULL );
          }

          if (theErr == HXR_REQUEST_UPGRADE)
          {
            bAddDefaultUpgrade = TRUE;
          }

          HX_RELEASE(pUnkRenderer);
          if (pRendInfo->m_pRendererEnumerator &&
            HXR_OK == pRendInfo->m_pRendererEnumerator->GetNextPlugin(pUnkRenderer, NULL) &&
            pUnkRenderer)
          {
            theErr = HXR_OK;
            HX_RELEASE(pRendInfo->m_pRenderer);
            goto tryNextRendererForSameMimeType;
          }
          else
          {
            if (!theFinalErr)
            {
                bSourceInitialized = FALSE;
                theFinalErr = theErr;
            }         

            // merge any upgrade requests for this source to the player
            m_pSource->MergeUpgradeRequest(bAddDefaultUpgrade, pMimeTypeBuffer ? (char*) pMimeTypeBuffer->GetBuffer() : (char*)NULL);
            theErr = HXR_OK;
          }
      }
    }

exit:

    if (theErr && !theFinalErr)
    {
      bSourceInitialized = FALSE;
      theFinalErr = theErr;
    }

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if(!theFinalErr && 
       m_bTrackStartedToBeSent)
    {    
      m_pPlayer->m_pGroupManager->TrackStarted(m_uGroupID, m_uTrackID);  
      m_bTrackStartedToBeSent = FALSE;
      if (m_pPeerSourceInfo)
      {
          m_pPeerSourceInfo->m_bTrackStartedToBeSent = FALSE;
      }
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    HX_RELEASE(pMimeTypeBuffer);
    HX_RELEASE(pUnkRenderer);

    if (!theFinalErr)
    {
      theFinalErr = InitializeRenderersExt(bSourceInitialized);
    }

    if (!theFinalErr && bSourceInitialized)
    {
      m_bInitialized = TRUE;
        
      // renderers initialized...clear any pending upgrade requests for this source!
      m_pSource->ClearUpgradeRequest();

      if (m_bAudioDeviceReflushHint)
      {
          m_pSource->SetAudioDeviceReflushHint();
      }

      // set the soundLevel != 100 by default
      if (m_uSoundLevel != 100)
      {
          m_pSource->SetSoundLevel(m_uSoundLevel, FALSE);
      }

      /* Enter the order of the stream numbers in which they will be 
       * scheduled for GetEvent() calls
       */
      if (NULL == m_pCurrentScheduleList)
      {
          m_pCurrentScheduleList = new CHXSimpleList;
      }

      CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
      for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
      {
          RendererInfo* pRendInfo = (RendererInfo*)(*ndxRend);
          m_pCurrentScheduleList->AddTail((void*) pRendInfo);
      }
    }

    return theFinalErr;
}

HX_RESULT
SourceInfo::InitializeRenderersExt(BOOL& bSourceInitialized)
{
    return HXR_OK;
}

HX_RESULT
SourceInfo::SetupStreams()
{
    if (m_bAreStreamsSetup)
    {
      return HXR_OK;
    }

    HX_RESULT         theErr          = HXR_OK;
    IHXValues*        pHeader         = NULL;
    HXStream*         pStream         = NULL;
    STREAM_INFO*    pStreamInfo     = NULL;
    RendererInfo*   pRendInfo       = NULL;
    HXSource*         pSource     = m_pSource;

    if (!pSource->IsInitialized())
    {
      HX_ASSERT(FALSE);
      return HXR_UNEXPECTED;
    }

    UINT16 uNumStreams = pSource->GetNumStreams();

    HX_ASSERT(m_pRendererMap->IsEmpty() == TRUE);
    if (m_pRendererMap->IsEmpty() && uNumStreams > 0 &&
      (UINT32) uNumStreams < m_pRendererMap->GetHashTableSize())
    {
      m_pRendererMap->InitHashTable((UINT32) uNumStreams);
    }
    
    for (UINT16 i=0; i < uNumStreams; i++)
    {
      UINT32      ulStreamNumber = 0;
      pHeader         = NULL;
      pStream         = NULL;

      pSource->GetStreamHeaderInfo(i, pHeader);

      if (!pHeader)
      {
          GOTOEXITONERROR(theErr = HXR_FAILED, exit);     
      }

      pStream = new HXStream;
      if (!pStream)
      {
          theErr = HXR_OUTOFMEMORY;
          goto exit;
      }

      pStream->AddRef();
      theErr = pStream->Init(m_pPlayer, pSource, pHeader);
      
      GOTOEXITONERROR(theErr, exit);

      pHeader->GetPropertyULONG32("StreamNumber", ulStreamNumber);

      if (HXR_OK != pSource->GetStreamInfo(ulStreamNumber, pStreamInfo) || !pStreamInfo)
      {
          GOTOEXITONERROR(theErr = HXR_FAILED, exit);
      }

      HX_RELEASE(pHeader);

      pRendInfo = NewRendererInfo();
      if (!pRendInfo)
      {
          theErr = HXR_OUTOFMEMORY;
          GOTOEXITONERROR(theErr, exit);
      }
      // get properties of the header
      pRendInfo->m_pRenderer          = NULL;
      pRendInfo->m_pStreamInfo        = pStreamInfo;
      pRendInfo->m_ulGranularity      = 0;
      pRendInfo->m_ulDuration         = pStreamInfo->m_ulDuration;
      pRendInfo->m_BufferingReason    = BUFFERING_START_UP;
        
        struct timeSyncParamStruct obj = {this, pRendInfo};
        pRendInfo->m_pTimeSyncCallback  = new CTimeSyncCallback((void*)&obj, (fGenericCBFunc)TimeSyncCallback);
      pRendInfo->m_pStream          = pStream;
      pRendInfo->m_pStream->AddRef();

      if (m_ulSourceDuration < pStreamInfo->m_ulDuration)
      {
          m_ulSourceDuration = pStreamInfo->m_ulDuration;
      }
    
      if (pRendInfo->m_pTimeSyncCallback)
      {
          pRendInfo->m_pTimeSyncCallback->AddRef();
      }
      else
      {
          theErr = HXR_OUTOFMEMORY;
          GOTOEXITONERROR(theErr, exit);
      }

      m_pRendererMap->SetAt(pStreamInfo->m_uStreamNumber, (void*) pRendInfo);

      if (pStream)
      {
          if (pStream->IsSureStream())
          {
            pSource->m_bSureStreamClip = TRUE;
          }
          pSource->AddHXStream(pStream);
          HX_RELEASE(pStream);
      }
    }

exit:
    HX_RELEASE(pStream);
    HX_RELEASE(pHeader);

    if (!theErr)
    {
      m_bAreStreamsSetup = TRUE;
    }

    return theErr;
}

RendererInfo* 
SourceInfo::NewRendererInfo()
{
    return (new RendererInfo());
}

HX_RESULT
SourceInfo::SetupRenderer(RendererInfo*& pRendInfo, IHXRenderer*& pRenderer, 
                   STREAM_INFO*& pStreamInfo, HXStream*& pStream)
{
    HX_RESULT       theErr              = HXR_OK;
    ULONG32         ulSyncGranularity   = DEFAULT_TIMESYNC_GRANULARITY;
    BOOL        bLiveSource         = FALSE;
    HXSource*      pSource             = m_pSource;
    IHXPlugin*     pPlugin             = NULL;
    STREAM_INFO*    pSrcStreamInfo  = NULL;
    IHXStatistics* pStatistics            = NULL;
    const char**    ppTmpMimeType = 0;

    pRendInfo->m_pRenderer          = pRenderer;

    if (HXR_OK != pRenderer->QueryInterface(IID_IHXPlugin,(void**)&pPlugin))
    {
      theErr = HXR_NOT_INITIALIZED;
    }
    else
    {
      /* Initialize the plugin for use */
      if (HXR_OK != pPlugin->InitPlugin((IUnknown*) (IHXStreamSource*) m_pSource))
      {
          theErr = HXR_NOT_INITIALIZED;
      }
      pPlugin->Release();
    }

    GOTOEXITONERROR(theErr, exit);

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    if (HXR_OK == pRenderer->QueryInterface(IID_IHXStatistics, (void**) &pStatistics))
    {
      if (HXR_OK == pSource->GetStreamInfo(pRendInfo->m_pStreamInfo->m_uStreamNumber, pSrcStreamInfo) &&
          pSrcStreamInfo && pSrcStreamInfo->m_pStats)
      {
          pStatistics->InitializeStatistics(pSrcStreamInfo->m_pStats->m_pRenderer->m_ulRegistryID);
      }

      HX_RELEASE (pStatistics);
    }
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    theErr = pRenderer->StartStream(pStream, m_pPlayer);
    GOTOEXITONERROR(theErr, exit);

    theErr = pRenderer->OnHeader(pStreamInfo->m_pHeader);
    GOTOEXITONERROR(theErr, exit);

    // start the stream
    /* get the minimum granularity */
    pRenderer->GetRendererInfo(ppTmpMimeType, ulSyncGranularity);
    /* sanity check */
    if (ulSyncGranularity < MINIMUM_TIMESYNC_GRANULARITY)
    {
      ulSyncGranularity = MINIMUM_TIMESYNC_GRANULARITY;
    }

    if (ulSyncGranularity < m_pPlayer->m_ulLowestGranularity)
    {
      m_pPlayer->m_ulLowestGranularity = ulSyncGranularity;
    }

    // get properties of the header
    pStreamInfo->m_ulDelay        = m_pSource->GetDelay();
    pRendInfo->m_ulGranularity      = ulSyncGranularity;
    pRendInfo->m_ulDuration         = pStreamInfo->m_ulDuration;
    // OnHeader may have overriddden the m_ulPreroll from the stream header
    // if it was too big or too small or not set.

    ULONG32 ulPreroll;
    if (HXR_OK == pStreamInfo->m_pHeader->GetPropertyULONG32("Preroll", ulPreroll))
    {
      pStreamInfo->BufferingState().SetPreroll(ulPreroll);
    }

    // check if renderer is interrupt safe
    IHXInterruptSafe* pInterruptSafe;
    if (HXR_OK == pRenderer->QueryInterface(IID_IHXInterruptSafe,(void**)&pInterruptSafe))
    {
      HX_ASSERT(pInterruptSafe) ;
      if (pInterruptSafe)
      {
          pRendInfo->m_bInterruptSafe = pInterruptSafe->IsInterruptSafe();
          pInterruptSafe->Release();
      }
    }    
    
    m_pPlayer->m_bResumeOnlyAtSystemTime |= (!pRendInfo->m_bInterruptSafe);
    
    /* Enter to the begin list so that we can call Begin at the right time */
    m_pPlayer->EnterToBeginList(pRendInfo);

    // notify the persistent renderer(source) who implements
    // IHXRendererAdviseSink to monitor the status of its tracks
    if (m_pRendererAdviseSink && pStream && !m_bIsPersistentSource)
    {
      bLiveSource = pSource->IsLive();

      if (m_bIndefiniteDuration)
      {
          m_ulTrackDuration = MAX_UINT32;
      }
      else  
      {     
          m_ulTrackDuration = m_pSource->GetDuration();
      }

      if (!m_bIsTrackDurationSet)
      {         
          m_bIsTrackDurationSet = TRUE;

          m_pRendererAdviseSink->TrackDurationSet(m_uGroupID,
                                        m_uTrackID,
                                        m_ulTrackDuration,
                                        pStreamInfo->m_ulDelay,
                                        bLiveSource);
      }
    } 

    if (m_pRendererAdviseSink && pStream)
    {
      IUnknown* pUnk = 0;
      if(HXR_OK == pStream->QueryInterface(IID_IUnknown, (void**)&pUnk))
      {
          /* 
           * construct the IHXValues info for the RendererInitialized call
           */
          IHXValues* pValues = new CHXHeader;
          pValues->AddRef();

          pValues->SetPropertyULONG32("GroupIndex", m_uGroupID);
          pValues->SetPropertyULONG32("TrackIndex", m_uTrackID);
          pValues->SetPropertyULONG32("Delay", pStreamInfo->m_ulDelay);
          
          /* We should really fix SMIL renderer to look at MAX duration
           * For now, we will pass max duration for all the renderers.
           * The only case where the duration is different is with image maps 
           * in video/audio stream.
           */
          pValues->SetPropertyULONG32("Duration", m_ulTrackDuration);       
          pValues->SetPropertyULONG32("LiveSource", bLiveSource);

          if (!m_id.IsEmpty())
          {
            IHXBuffer* pBuffer = new CHXBuffer();
            pBuffer->AddRef();
    
            pBuffer->Set((const UCHAR*)(const char*)m_id, m_id.GetLength()+1);
            pValues->SetPropertyCString("id", pBuffer);

            HX_RELEASE(pBuffer);
          }

          HX_RESULT rc = m_pRendererAdviseSink->RendererInitialized(pRenderer, pUnk, pValues);

          pValues->Release();
          pUnk->Release();
      }
    }

    // XXX HP we need to re-examine how the SMIL renderer's layout site 
    // setup work!!
    if (m_bIsPersistentSource)
    {
      m_pPlayer->m_bSetupLayoutSiteGroup = FALSE;
    }

exit:
    return theErr;
}


HX_RESULT
SourceInfo::InitializeAndSetupRendererSites()
{
    HX_RESULT theErr = HXR_OK;
    BOOL bInitialized = FALSE;

    if (HXR_OK != m_lastError)
    {
        return m_lastError;
    }

    if (m_bLocked)
    {
      return HXR_OK;
    }

    m_bLocked = TRUE;
    m_pMutex->Lock();

    theErr = InitializeRenderers(bInitialized);
    if (!theErr && m_bInitialized)
    {
      /* This source may have audio streams */
      if (!m_pPlayer->m_ulMinimumAudioPreroll)
      {
          m_pPlayer->m_ulMinimumAudioPreroll = 
            m_pPlayer->m_pAudioPlayer->GetInitialPushdown();
      }

      UINT32 ulMinimumStartingPreroll = m_pPlayer->m_pAudioPlayer->GetInitialPushdown(TRUE);

      m_pSource->SetMinimumPreroll(m_pPlayer->m_ulMinimumAudioPreroll, ulMinimumStartingPreroll);

#if defined(HELIX_FEATURE_VIDEO)
      /* Set all the renderer sites */
      SetupRendererSites(!m_pPlayer->m_bSetupLayoutSiteGroup);

      /* Did we have to call BeginChangeLayout? */
      if (m_pPlayer->m_pSiteSupplier                  && 
          !m_pPlayer->m_bBeginChangeLayoutTobeCalled  &&
          // XXX HP we will not call DoneChangeLayout on persistent source until
          //            the actual source has been initialized. this fixed the resizing
          //            problem during stop/play on SMIL in RAM
          //            the other DoneChangeLayout in HXPlayer won't be called either
          //            since we set m_bSetupLayoutSiteGroup=FALSE in SetupRenderer() of
          //            the persistent source
          !m_bIsPersistentSource)
      {
          /*
           * At this point all renderers are layed out!
           */
          m_pPlayer->m_bBeginChangeLayoutTobeCalled   = TRUE;
          m_pPlayer->m_pSiteSupplier->DoneChangeLayout();
      }
#endif /* HELIX_FEATURE_VIDEO */

      if (m_pSource->TryResume())
      {
          m_pPlayer->RegisterSourcesDone();
      }

      Begin();
    }

    if (HXR_OK != theErr && HXR_OK == m_lastError)
    {
        m_lastError = theErr;
    }

    m_pMutex->Unlock();
    m_bLocked = FALSE;

    return theErr;
}

void
SourceInfo::RenderersCleanup()
{
    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo = (RendererInfo*)(*ndxRend);
      LONG32            lStreamNumber = ndxRend.get_key();

      if(m_pRendererAdviseSink && pRendInfo->m_pRenderer)
      {
          IHXValues* pValues = new CHXHeader;
          pValues->AddRef();
          pValues->SetPropertyULONG32("GroupIndex", m_uGroupID);
          pValues->SetPropertyULONG32("TrackIndex", m_uTrackID);
          pValues->SetPropertyULONG32("StreamNumber", lStreamNumber);

          if (!m_id.IsEmpty())
          {
            IHXBuffer* pBuffer = new CHXBuffer();
            pBuffer->AddRef();
    
            pBuffer->Set((const UCHAR*)(const char*)m_id, m_id.GetLength()+1);
            pValues->SetPropertyCString("id", pBuffer);

            HX_RELEASE(pBuffer);
          }

          m_pRendererAdviseSink->RendererClosed(pRendInfo->m_pRenderer, pValues);
          pValues->Release();
      }

      // remove all the packets associated with this renderer
      LISTPOSITION lPos = m_pPlayer->m_EventList.GetHeadPosition();
      while(lPos && m_pPlayer->m_EventList.GetCount())
      {         
          CHXEvent* pEvent = (CHXEvent*)m_pPlayer->m_EventList.GetAt(lPos);
          
          if (pEvent->m_pRendererInfo == pRendInfo)
          {
            HX_DELETE(pEvent);
            lPos = m_pPlayer->m_EventList.RemoveAt(lPos);
          }
          else
          {
            m_pPlayer->m_EventList.GetNext(lPos);
          }
      }

      RenderersCleanupExt(pRendInfo);

      HX_RELEASE(pRendInfo->m_pRenderer);
      HX_RELEASE(pRendInfo->m_pRendererEnumerator);
      HX_DELETE(pRendInfo);
    }

    if (m_pCurrentScheduleList)
    {
      m_pCurrentScheduleList->RemoveAll();
    }

    m_pRendererMap->RemoveAll();

    return;
}

void
SourceInfo::RenderersCleanupExt(RendererInfo* pRendInfo)
{
    return;
}

HX_RESULT
SourceInfo::CloseRenderers()
{
    if (m_bActive)
    {
      m_bActive = FALSE;
      m_pPlayer->m_uNumSourcesActive--;
    }

    // persistent source will be closed by the persistent manager
    if (m_bIsPersistentSource)
    {
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
        //Move this reg tree to a different place.
        m_pPlayer->UpdatePersistentSrcInfo(this,
                                           m_pPlayer->m_pStats->m_ulRegistryID,
                                           m_uTrackID);
#endif        
      return HXR_FAIL;
    }

    // This way the source will still be around until the
    // renderers are closed.
    HX_RELEASE(m_pSource);

    RenderersCleanup();

    HX_RELEASE(m_pRendererAdviseSink);

    return HXR_OK;
}

HX_RESULT 
SourceInfo::OnTimeSync(ULONG32 ulCurrentTime)
{
    HX_RESULT theErr = HXR_OK;

//{FILE* f1 = ::fopen("d:\\temp\\audio.txt", "a+"); ::fprintf(f1, "SourceInfo::OnTimeSync: %lu\n", ulCurrentTime);::fclose(f1);}

    CHXMapLongToObj::Iterator ndxRend =   m_pRendererMap->Begin();

    for (; !theErr && ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo = (RendererInfo*)(*ndxRend);

      /* It is OK to send time sync within +TIME_SYNC_FUDGE_FACTOR */
      if (!pRendInfo->m_bInitialBeginToBeSent &&
          pRendInfo->m_ulNextDueSyncTime <=
          ulCurrentTime + TIME_SYNC_FUDGE_FACTOR &&
          (m_pSource->IsLive() || ulCurrentTime <= pRendInfo->m_ulDuration ||
          !pRendInfo->m_bDurationTimeSyncSent ||
           (m_bIsPersistentSource && !m_bActive)))
      {
          m_pPlayer->m_pScheduler->Remove(
             pRendInfo->m_pTimeSyncCallback->GetPendingCallback());
        
            pRendInfo->m_pTimeSyncCallback->CallbackCanceled();
          
            theErr = OnTimeSync(pRendInfo, TRUE);

          if(m_pPlayer->m_bCurrentPresentationClosed)
          {
            goto exit;
          }
      }
    }

exit:
    return theErr;
}

HX_RESULT    
SourceInfo::OnTimeSync(RendererInfo* pRendInfo, BOOL bUseCurrentTime)
{
    HX_RESULT theErr = HXR_OK;

    if (m_bLocked)
    {
      return HXR_OK;
    }

    m_bLocked = TRUE;
    m_pMutex->Lock();

    // no OnTimeSync() when the source(track) is paused
    if (!m_pSource || m_pSource->IsPaused())
    {
      m_pMutex->Unlock();
      m_bLocked = FALSE;
      return HXR_OK;
    }

    if (!m_pPlayer->m_bInitialized)
    {
      m_pMutex->Unlock();
      m_bLocked = FALSE;
      return HXR_NOT_INITIALIZED;
    }

    m_pPlayer->m_bCurrentPresentationClosed = FALSE;

    /* Do we query for the current time?
     * This routine may be called as a callback (where we want to find
     * out the current time) OR can be called for all DUE renderers
     * whenevr we get a timesync (here we do not want to call getcurrenttime()
     * again)
     *
     * Changed to: (on 09/05/1998 --RA) 
     *
     * Always ask the audio services what the current time is. This is 
     * because we do not make system call in this function anymore to get the 
     * audio device time. Instead, we use realtime to adjust the
     * last audio time returned by the device.
     */

    m_pPlayer->m_ulCurrentPlayTime = 
      m_pPlayer->m_pAudioPlayer->GetCurrentPlayBackTime();

    if (m_pPlayer->m_bIsFirstTimeSync)
    {
      m_pPlayer->m_bIsFirstTimeSync  = FALSE;
      m_pPlayer->m_ulFirstTimeSync   = m_pPlayer->m_ulCurrentPlayTime;
    }

    /*
     * Call ProcessCurrentEvents ONLY if we are here form a scheduled
     * timesync callback. If we are here from HXPlayer::OnTimeSync, we
     * should have already called ProcessCurrentEvents in HXPlayer.
     */
    if (!bUseCurrentTime)
    {
      theErr  = m_pPlayer->ProcessCurrentEvents();
    }

    /* Duration check */
    ULONG32 ulCurrentPlayTime = m_pPlayer->m_ulCurrentPlayTime;

//{FILE* f1 = ::fopen("c:\\temp\\sync.txt", "a+"); ::fprintf(f1, "SourceInfo::OnTimeSync: Renderer: %p %lu\n", pRendInfo->m_pRenderer, ulCurrentPlayTime);::fclose(f1);}

    IHXRenderer* lRend         = (IHXRenderer*) pRendInfo->m_pRenderer;
    STREAM_INFO*  pStreamInfo   = pRendInfo->m_pStreamInfo;
    
    if (m_pSource->isRestrictedLiveStream() && 
      ulCurrentPlayTime > pRendInfo->m_ulDuration)
    {
      // mark all the streams done if one of the streams is done
      if (!pStreamInfo->m_bSrcInfoStreamDone)
      {
          pStreamInfo->m_bSrcInfoStreamDone = TRUE;

          pStreamInfo->ResetPostEndTimeEventList();

          if (!pStreamInfo->m_bSrcInfoStreamFillingDone)
          {
            pStreamInfo->m_bSrcInfoStreamFillingDone = TRUE;
          }
      }
      
      CheckIfDone();

      goto exit;
    }

    if (m_pSource)
    {
      theErr = m_pSource->OnTimeSync(ulCurrentPlayTime);
    }

    /* if we were in a seek state before, we need to send a postseekmessage
     * before sending timesync...
     */

    /* We should probably not do this since there may be Pre-Seek Packets for
     * some renderers that have not been sent yet since they are not
     * interrup safe.
     */
    /*
    if (pRendInfo->m_BufferingReason == BUFFERING_SEEK || 
      pRendInfo->m_BufferingReason == BUFFERING_LIVE_PAUSE)
    {
      pRendInfo->m_BufferingReason   = BUFFERING_CONGESTION;
      lRend->OnPostSeek(pStreamInfo->m_ulTimeBeforeSeek,
                    pStreamInfo->m_ulTimeAfterSeek);
    }
    */

    /* We only want to send time sync if it is greater than the last time
     * sync sent to the renderer
     */
//{FILE* f1 = ::fopen("c:\\temp\\sync.txt", "a+"); ::fprintf(f1, "SourceInfo::OnTimeSync: lastsynctime: %lu currentplaytime: %lu\n", pRendInfo->m_ulLastSyncTime, ulCurrentPlayTime );::fclose(f1);}

    if (pRendInfo->m_bIsFirstCallback ||
      pRendInfo->m_ulLastSyncTime < ulCurrentPlayTime)
    {
      /* tell the renderer what their time should be (not the player's time)
       * taking into account the source's start time, delay, loop count.
       */
      UINT32 ulRealtime = ulCurrentPlayTime;

      if (m_pSource->IsLive())
      {
          /* First TimeSync and received at least one packet */
          if (pRendInfo->m_bIsFirstTimeSync && !pRendInfo->m_bIsFirstPacket)
          {
            pRendInfo->m_bIsFirstTimeSync = FALSE;
            pRendInfo->m_bTimeDiffPositive = 
                (pRendInfo->m_ulStreamStartTime >= 
                m_pPlayer->m_ulFirstTimeSync);

            // CALCULATE_ELAPSED_TICKS assumes 0 is > 0xf??????? and 
            // since we know it's not in this case we special case it
            if (m_pPlayer->m_ulFirstTimeSync != 0)
            {
                if (pRendInfo->m_bTimeDiffPositive)
                {
                  pRendInfo->m_ulTimeDiff        = 
                              CALCULATE_ELAPSED_TICKS(m_pPlayer->m_ulFirstTimeSync,
                              pRendInfo->m_ulStreamStartTime);
                }
                else
                {
                  pRendInfo->m_ulTimeDiff        = 
                              CALCULATE_ELAPSED_TICKS(pRendInfo->m_ulStreamStartTime,
                              m_pPlayer->m_ulFirstTimeSync);
                }
            }
            else
            {
                pRendInfo->m_ulTimeDiff        = 
                  pRendInfo->m_ulStreamStartTime;
            }
          }

          if (pRendInfo->m_bTimeDiffPositive)
          {
              ulRealtime += pRendInfo->m_ulTimeDiff;
          }
          else
          {
              ulRealtime -= pRendInfo->m_ulTimeDiff;
          }
      }

      BOOL bAtInterrupt = m_pPlayer->m_pEngine->AtInterruptTime();
      if (!bAtInterrupt || pRendInfo->m_bInterruptSafe)
      {
          if (!m_bIsPersistentSource      && 
            !m_pSource->IsLive()    &&
            ulRealtime >= pRendInfo->m_ulDuration)
          {
            ulRealtime = pRendInfo->m_ulDuration;
          }

          theErr = lRend->OnTimeSync(ulRealtime);         
          if( theErr == HXR_OUTOFMEMORY )
          {
              m_pPlayer->Report( HXLOG_ERR, theErr, 0, NULL, NULL );
          }
          if( theErr != HXR_OK )
          {
              goto exit;
          }

#if defined(HELIX_FEATURE_SMIL_REPEAT)
          // repeat support:
          // make sure we called OnTimeSync() on the active source
          // before we tearing down its peer source
          if (!bAtInterrupt       && 
            m_pPeerSourceInfo   &&
            m_pPeerSourceInfo->m_bRepeatPending)
          {
            CHXSimpleList*  pRepeatList = m_bLeadingSource?m_pRepeatList:m_pPeerSourceInfo->m_pRepeatList;

            HX_ASSERT(pRepeatList);

            RepeatInfo*     pRepeatInfo = NULL;
            HXSource*       pPeerSource = m_pPeerSourceInfo->m_pSource;
            LISTPOSITION          nextPos = 0;

            // take care repeat="indefinite" when max. duration is set
            if (m_bRepeatIndefinite &&
                m_ulMaxDuration     &&
                m_pSource->GetDuration() >= m_pSource->m_ulOriginalDelay + m_ulMaxDuration)
            {
                m_pPeerSourceInfo->Reset();
            }
            // otherwise, prepare for the new repeat
            else
            {
                if (m_curPosition != pRepeatList->GetTailPosition())
                {
                  nextPos = m_curPosition;
                  pRepeatInfo = (RepeatInfo*)pRepeatList->GetAtNext(nextPos);
                }       
                else if (m_bRepeatIndefinite)
                {
                  nextPos = (RepeatInfo*)pRepeatList->GetHeadPosition();
                  pRepeatInfo = (RepeatInfo*)pRepeatList->GetAt(nextPos);

                  UINT32 ulDelayTimeOffset = m_pSource->GetDelay() + m_ulRepeatInterval - pRepeatInfo->ulDelay;
                  m_pPeerSourceInfo->m_ulRepeatDelayTimeOffset = ulDelayTimeOffset;
                  m_ulRepeatDelayTimeOffset = ulDelayTimeOffset;
                }

                if (nextPos && pRepeatInfo)
                {
                  m_pPeerSourceInfo->m_curPosition = nextPos;

                  // initialize the new repeat
                  m_pPeerSourceInfo->m_uTrackID = pRepeatInfo->uTrackID;
                  m_pPeerSourceInfo->Reset();
                  pPeerSource->ReSetup();
                }
                // done with the repeat
                else
                {
                  m_pPeerSourceInfo->Reset();
                }       
            }
            m_pPeerSourceInfo->m_bRepeatPending = FALSE;
          }
#endif /* HELIX_FEATURE_SMIL_REPEAT */

          if ((UINT32) ulRealtime >= pRendInfo->m_ulDuration && pRendInfo->m_bOnEndOfPacketSent)
          {
            pRendInfo->m_bDurationTimeSyncSent = TRUE;
          }
      }
      else 
      {
          if (!pRendInfo->m_pTimeSyncCallback->GetPendingCallback())
          {
                pRendInfo->m_pTimeSyncCallback->CallbackScheduled(
                 m_pPlayer->m_pScheduler->RelativeEnter(pRendInfo->m_pTimeSyncCallback, 0));
//{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p ADDING IMMEDIATE TimeSyncCallback: Handle: %lu Thread: %lu\n", pRendInfo->m_pTimeSyncCallback, (UINT32) pRendInfo->m_PendingHandle, GetCurrentThreadId());::fclose(f1);}
          }

          goto exit;
      }

      if(m_pPlayer->m_bCurrentPresentationClosed)
      {
          goto exit;
      }

      pRendInfo->m_ulLastSyncTime = ulCurrentPlayTime;
    }

    /* Do we need to send more timesyncs */
    if (m_pSource->IsLive() || !pRendInfo->m_bDurationTimeSyncSent ||
      (m_bIsPersistentSource && !m_bActive))
    {
      ULONG32 ulNextCBTime = pRendInfo->m_ulGranularity;

      /* Do we need to increment our next due time sync value?
       * This check is needed since a lot of WOM_DONEs may get accumulated
       * and by the time we end up getting the time sync,
       * we have already played a bunch of data thereby resulting in a
       * jump in current audio time.
       * So we only increment next due time sync if the audio clock is
       * also moving
       */
      if (pRendInfo->m_ulNextDueSyncTime  <
          ulCurrentPlayTime + pRendInfo->m_ulGranularity)
      {
          pRendInfo->m_ulNextDueSyncTime  += pRendInfo->m_ulGranularity;
      }

      /* We wanna reset ourself if its either the first callback OR
       * somehow we are lagging behind in the timesyncs
       */
      if (pRendInfo->m_bIsFirstCallback ||
          pRendInfo->m_ulNextDueSyncTime < pRendInfo->m_ulLastSyncTime)
      {
          pRendInfo->m_bIsFirstCallback = FALSE;
          HXTimeval lTime = m_pPlayer->m_pScheduler->GetCurrentSchedulerTime();
          pRendInfo->m_pTimeSyncCBTime->tv_sec = lTime.tv_sec;
          pRendInfo->m_pTimeSyncCBTime->tv_usec = lTime.tv_usec;
          pRendInfo->m_ulNextDueSyncTime  = pRendInfo->m_ulLastSyncTime +
                                    pRendInfo->m_ulGranularity;

          /* Next due time sync at integral multiple of granularity */
          ULONG32 ulTimeDiff = pRendInfo->m_ulNextDueSyncTime % pRendInfo->m_ulGranularity;
          pRendInfo->m_ulNextDueSyncTime -= ulTimeDiff;
          ulNextCBTime -= ulTimeDiff;
      }

      if (pRendInfo->m_ulNextDueSyncTime > pRendInfo->m_ulDuration &&
          (!m_bIsPersistentSource && m_bActive) && !m_pSource->IsLive())
      {
          ULONG32 ulDiff = pRendInfo->m_ulNextDueSyncTime - pRendInfo->m_ulDuration;
          if (ulNextCBTime > ulDiff)
          {
            ulNextCBTime -= ulDiff;
          }
          pRendInfo->m_ulNextDueSyncTime = pRendInfo->m_ulDuration;
      }

      *(pRendInfo->m_pTimeSyncCBTime) += (int) (ulNextCBTime*1000);

      if (!pRendInfo->m_pTimeSyncCallback->GetPendingCallback())
      {
          UINT32 ulSchedTime = 0;
          if (pRendInfo->m_ulNextDueSyncTime > ulCurrentPlayTime)
          {
            ulSchedTime = pRendInfo->m_ulNextDueSyncTime - ulCurrentPlayTime;
          }
          pRendInfo->m_pTimeSyncCallback->CallbackScheduled(
             m_pPlayer->m_pScheduler->RelativeEnter(pRendInfo->m_pTimeSyncCallback, ulSchedTime));
      }
    }

exit:
    m_pMutex->Unlock();
    m_bLocked     = FALSE;
    return theErr;
}

void        
SourceInfo::Resumed()
{
    if (m_bTobeInitializedBeforeBegin)
    {
      m_bTobeInitializedBeforeBegin = FALSE;

      if (m_pPlayer->m_uNumSourceToBeInitializedBeforeBegin > 0)
      {
          m_pPlayer->m_uNumSourceToBeInitializedBeforeBegin--;
      }
    }
}

void
SourceInfo::UpdateDuration(UINT32 ulDuration)
{
    m_ulTotalTrackDuration = m_ulTrackDuration = m_ulSourceDuration = ulDuration;
    if (m_pPeerSourceInfo)
    {
      m_pPeerSourceInfo->m_ulTotalTrackDuration = m_ulTotalTrackDuration;
    }

    CHXMapLongToObj::Iterator i = m_pRendererMap->Begin();
    for (; i != m_pRendererMap->End(); ++i)
    {
      RendererInfo* pRendInfo = (RendererInfo*)(*i);

      IHXUpdateProperties* pUpdateProperties = NULL;
      if (pRendInfo->m_pRenderer &&
          HXR_OK == pRendInfo->m_pRenderer->QueryInterface(IID_IHXUpdateProperties,
                                               (void**)&pUpdateProperties))
      {
          IHXValues* pValues = new CHXHeader();
          pValues->AddRef();

          pValues->SetPropertyULONG32("End", m_pSource->GetEndTime());
          pValues->SetPropertyULONG32("Duration", ulDuration);

          pUpdateProperties->UpdatePlayTimes(pValues);
          HX_RELEASE(pValues);
      }
      HX_RELEASE(pUpdateProperties);

      pRendInfo->m_ulDuration = ulDuration;
      pRendInfo->m_pStreamInfo->m_ulDuration = ulDuration;
    }

    m_pPlayer->AdjustPresentationTime();
}

void
SourceInfo::UpdateDelay(UINT32 ulDelay)
{
    INT32   lOffset = 0;
    UINT32  ulStartTime = 0;
    UINT32  ulDuration = 0;

    ulStartTime = m_pSource->GetStartTime();
    ulDuration = GetActiveDuration();

    CHXMapLongToObj::Iterator i = m_pRendererMap->Begin();
    for (; i != m_pRendererMap->End(); ++i)
    {
      RendererInfo* pRendInfo = (RendererInfo*)(*i);
      lOffset = ulDelay - pRendInfo->m_pStreamInfo->m_ulDelay;

      // adjust the packet time offset within the core
      LISTPOSITION lPos = m_pPlayer->m_EventList.GetHeadPosition();
      while(lPos)
      {         
          CHXEvent* pEvent = (CHXEvent*)m_pPlayer->m_EventList.GetNext(lPos);
          
          if (pEvent->m_pRendererInfo == pRendInfo)
          {
            pEvent->SetTimeOffset(ulStartTime - ulDelay); 
          }
      }

      // adjust the packet time offset within the renderer
      IHXUpdateProperties* pUpdateProperties = NULL;
      if (pRendInfo->m_pRenderer &&
          HXR_OK == pRendInfo->m_pRenderer->QueryInterface(IID_IHXUpdateProperties,
                                               (void**)&pUpdateProperties))
      {
          pUpdateProperties->UpdatePacketTimeOffset(lOffset);
      }
      HX_RELEASE(pUpdateProperties);

      pRendInfo->m_pStreamInfo->m_ulDelay = ulDelay;
      pRendInfo->m_ulDuration = ulDuration;
      pRendInfo->m_pStreamInfo->m_ulDuration = ulDuration;
    }

    m_pPlayer->AdjustPresentationTime();
}

#ifdef SEQ_DEPENDENCY
void
SourceInfo::SetDependency(IHXBuffer* pDependency)
{
    char* pTemp = = new char[pDependency->GetSize()+1];
    strcpy(pTemp, pDependency->GetBuffer()); /* Flawfinder: ignore */

    UINT16 i = 0;
    
    m_uNumDependencies = 1;

    /* Find the number of dependencies */
    while(pTemp[i])
    {
      if (pTemp[i] == '.')
      {
          m_uNumDependencies++;
      }
      i++;
    }

    m_pDependNode = new UINT16[m_uNumDependencies];

    char* pNode = strtok(pTemp, ".\0");

    /* At least one node should be present */
    HX_ASSERT(pNode);

    i = 0;
    while(pNode)
    {
      m_pDependNode[i++] = atoi(pNode);
      pNode = strtok(NULL, ".\0");
    }

    HX_ASSERT(i == m_uNumDependencies);

    HX_VECTOR_DELETE(pTemp);
}
#endif /*SEQ_DEPENDENCY*/

BOOL        
SourceInfo::IsRebufferDone(void)
{
    BOOL        bResult = TRUE;
    RendererInfo*   pRendInfo = NULL;

    if (m_pSource && m_pSource->m_bRebufferingRequired)
    {
      CHXMapLongToObj::Iterator i = m_pRendererMap->Begin();
      for (; i != m_pRendererMap->End(); ++i)
      {
          pRendInfo = (RendererInfo*)(*i);
          
          if (!pRendInfo->m_bOnEndOfPacketSent)
          {
            bResult = FALSE;
            break;
          }
      }
    }

    return bResult;
}

void
SourceInfo::ReInitializeStats()
{
    if (!m_bInitialized)
    {
      return;
    }

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (UINT16 i = 0; ndxRend != m_pRendererMap->End(); ++ndxRend, i++)
    {
      RendererInfo*     pRendInfo = (RendererInfo*)(*ndxRend);

      HX_ASSERT(pRendInfo->m_pRenderer);
      if (!pRendInfo->m_pRenderer)
      {
          return;
      }

      IHXStatistics* pStatistics    = NULL;
      STREAM_INFO*    pSrcStreamInfo  = NULL;
      if (HXR_OK == pRendInfo->m_pRenderer->QueryInterface(IID_IHXStatistics, (void**) &pStatistics))
      {
          if (HXR_OK == m_pSource->GetStreamInfo(i, pSrcStreamInfo) &&
            pSrcStreamInfo && pSrcStreamInfo->m_pStats &&
            pSrcStreamInfo->m_pStats->m_pRenderer)
          {
            pStatistics->InitializeStatistics(pSrcStreamInfo->m_pStats->m_pRenderer->m_ulRegistryID);
          }

          HX_RELEASE (pStatistics);
      }
    }
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
}

HX_RESULT         
SourceInfo::HandleRedirectRequest(char* pURL)
{
    if (m_pPlayer)
    {
      return m_pPlayer->HandleRedirectRequest(m_uGroupID, m_uTrackID, pURL);
    }

    return HXR_FAILED;
}

void
SourceInfo::ScheduleProcessCallback()
{
    if (!m_pProcessCallback->GetPendingCallback())
    {
        m_pProcessCallback->CallbackScheduled(
         m_pPlayer->m_pScheduler->RelativeEnter(m_pProcessCallback, 0));
    }
}

void 
SourceInfo::SetLiveSyncStartTime(HXSource* pSource, RendererInfo* pTmpRendInfo, 
                         UINT32 ulLowestTime)
{
    UINT32 ulLiveSyncStartTime = ulLowestTime;
    INT32  lTimeOffset = pSource->GetStartTime() - pTmpRendInfo->m_pStreamInfo->m_ulDelay;

    if (pTmpRendInfo->m_pStreamInfo->m_pHeader)
    {
      if (lTimeOffset < 0)
      {
          ulLiveSyncStartTime += (UINT32) (-lTimeOffset);
      }
      else
      {
          if (ulLiveSyncStartTime < (UINT32)lTimeOffset)
          {
            ulLiveSyncStartTime = 0;
          }
          else
          {
            ulLiveSyncStartTime -= (UINT32)lTimeOffset;
          }
      }

      pTmpRendInfo->m_pStreamInfo->m_pHeader->SetPropertyULONG32("LiveSyncStartTime", ulLiveSyncStartTime);
    }

    return;
}

BOOL
SourceInfo::AllOtherStreamsHaveEnded(STREAM_INFO* pThisStreamInfo)
{
    BOOL bResult = TRUE;
    CHXMapLongToObj::Iterator ndxRend = m_pRendererMap->Begin();
    for (; ndxRend != m_pRendererMap->End(); ++ndxRend)
    {
      RendererInfo* pRendInfo     = (RendererInfo*)(*ndxRend);
      STREAM_INFO*  pStreamInfo   = pRendInfo->m_pStreamInfo;

      /* 
       * check if any other stream is still active.
       * do not consider other "CanBeStoppedAnyTime" streams
       * as active streams
       */
      if (pStreamInfo != pThisStreamInfo &&
          !pStreamInfo->m_bCanBeStoppedAnyTime &&
          !pStreamInfo->m_bSrcInfoStreamDone)
      {
          bResult = FALSE;
          break;
      }
    }

    return bResult;
}

HX_RESULT
SourceInfo::AppendRepeatRequest(UINT16 uTrackID, IHXValues* pTrack)
{
#if defined(HELIX_FEATURE_SMIL_REPEAT)
    HX_RESULT         theErr = HXR_OK;
    BOOL        bLive = FALSE;
    BOOL        bDurationSet = FALSE;
    BOOL        bMaxDurationSet = FALSE;
    UINT32      ulStart = 0;
    UINT32      ulEnd = 0;
    UINT32      ulDelay = 0;
    UINT32      ulDuration = 0;   
    UINT32      ulMaxDuration = 0;
    UINT32      ulRepeatTag = RepeatUnknown;
    UINT32      ulRepeatInterval = 0;
    UINT32      ulLastDelay = 0;
    char        szId[] = "id";
    char        szStart[] = "Start";
    char        szEnd[] = "End";
    char        szDelay[] = "Delay";
    char        szDuration[] = "Duration";
    char        szMaxDuration[] = "maxduration";
    char        szRepeatTag[] = "repeatTag";
    IHXBuffer*        pBuffer = NULL;
    RepeatInfo*       pNewRepeatInfo = NULL;

    HX_ASSERT(m_bLeadingSource);    

    if (HXR_OK != pTrack->GetPropertyCString(szId, pBuffer))
    {
      HX_ASSERT(FALSE);
      theErr = HXR_UNEXPECTED;
      goto cleanup;
    }

    // repeated sources should share the same start/end timing attributes
    if (HXR_OK == pTrack->GetPropertyULONG32(szStart,ulStart))
    {
      HX_ASSERT(ulStart == m_pSource->GetStartTime());
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szEnd,ulEnd))
    {
      HX_ASSERT(ulEnd == m_pSource->GetEndTime());
    }

    if (HXR_OK != pTrack->GetPropertyULONG32(szDelay,ulDelay))
    {
      HX_ASSERT(FALSE);
      theErr = HXR_UNEXPECTED;
      goto cleanup;
    }
    
    ulLastDelay = m_pRepeatList?((RepeatInfo*)m_pRepeatList->GetTail())->ulDelay:m_pSource->GetDelay();
    if (ulDelay <= ulLastDelay)
    {
      goto cleanup;
    }
    
    if (HXR_OK == pTrack->GetPropertyULONG32(szDuration,ulDuration))
    {
      bDurationSet = TRUE;
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szMaxDuration, ulMaxDuration))
    {
      bMaxDurationSet = TRUE;
    }
    
    // skip this repeat if duration == 0
    if ((bDurationSet && 0 == ulDuration) ||
      (bMaxDurationSet && 0 == ulMaxDuration))
    {
      goto durationset;
    }

    if (HXR_OK != pTrack->GetPropertyULONG32(szRepeatTag, ulRepeatTag))
    {
      ulRepeatTag = RepeatUnknown;
    }

    if (!m_pRepeatList)
    {
      m_pRepeatList = new CHXSimpleList();

      pNewRepeatInfo = new RepeatInfo;
      pNewRepeatInfo->ulStart = m_pSource->GetStartTime();
      pNewRepeatInfo->ulEnd = m_pSource->GetEndTime();
      pNewRepeatInfo->ulDelay = m_pSource->GetDelay();
      pNewRepeatInfo->ulDuration = m_pSource->m_ulOriginalDuration;
      pNewRepeatInfo->uTrackID = m_uTrackID;    
      m_curPosition = m_pRepeatList->AddHead(pNewRepeatInfo);
    }

    pNewRepeatInfo = new RepeatInfo;
    pNewRepeatInfo->ulStart = ulStart?ulStart:m_pSource->GetStartTime();
    pNewRepeatInfo->ulEnd = ulEnd?ulEnd:m_pSource->GetEndTime();
    pNewRepeatInfo->ulDelay = ulDelay;
    pNewRepeatInfo->uTrackID = uTrackID;
    // if the duration is set
    if (bDurationSet)
    {
      pNewRepeatInfo->ulDuration = ulDuration;
    }
    // if max. duration is set, make sure its duration <= ulMaxDuration
    else if (bMaxDurationSet && ulMaxDuration < m_pSource->m_ulOriginalDuration)
    {
      pNewRepeatInfo->ulDuration = ulMaxDuration;
    }
    // set to its leading source's original duration by default
    else
    {
      pNewRepeatInfo->ulDuration = m_pSource->m_ulOriginalDuration;
    }

    m_pRepeatList->AddTail(pNewRepeatInfo);

    if (ulRepeatTag == RepeatIndefiniteOnGroup ||
      ulRepeatTag == RepeatIndefiniteOnMe)
    {
      m_bRepeatIndefinite = TRUE;       
      ulRepeatInterval = ulDelay - ulLastDelay;

      if (ulRepeatInterval > m_ulRepeatInterval)
      {
          m_ulRepeatInterval = ulRepeatInterval;
      }
      
      // recaculate the max. duration for repeat="indefinite"
      if (bMaxDurationSet)
      {         
          m_ulMaxDuration = ulMaxDuration + m_pSource->m_ulOriginalDuration;
          ulDuration = ulMaxDuration;
          if (pNewRepeatInfo->ulDuration > ulMaxDuration)
          {
            pNewRepeatInfo->ulDuration = ulMaxDuration;
          }
      }
      else
      {
          if (ulRepeatTag == RepeatIndefiniteOnGroup)
          {
            ulDuration = m_pSource->m_ulOriginalDuration;
          }
          else
          {
            ulDuration = MAX_UINT32;
            bLive = TRUE;
          }
      }

      if (m_pPeerSourceInfo)
      {
          m_pPeerSourceInfo->m_bRepeatIndefinite = m_bRepeatIndefinite;
          m_pPeerSourceInfo->m_ulRepeatInterval = m_ulRepeatInterval;
          m_pPeerSourceInfo->m_ulMaxDuration = m_ulMaxDuration;
      }
    }
    else
    {
      ulDuration = pNewRepeatInfo->ulDuration;
    }

durationset:

    if (m_pRendererAdviseSink)
    {
      m_pRendererAdviseSink->RepeatedTrackDurationSet((const char*)pBuffer->GetBuffer(),
                                          ulDuration,
                                          bLive);
    }

cleanup:

    HX_RELEASE(pBuffer);

    return theErr;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_SMIL_REPEAT */
}

BOOL        
SourceInfo::IsAdjustSeekNeeded(UINT32 ulSeekTime)
{
    BOOL bResult = TRUE;

    // after the repeated sources
    if (ulSeekTime > GetActiveDuration())
    {
      m_pPeerSourceInfo->Reset();
      bResult = FALSE;
    }
    // within the active source
    else if (ulSeekTime >= m_pSource->GetDelay() &&
           ulSeekTime < m_pSource->GetDuration())
    {
      bResult = FALSE;
    }

    return bResult;
}

SourceInfo*       
SourceInfo::DoAdjustSeek(UINT32 ulSeekTime)
{    
#if defined(HELIX_FEATURE_SMIL_REPEAT)
    BOOL        bRepeatDelayTimeOffsetAdjusted = FALSE;
    UINT32      ulOriginalDuration = 0;
    UINT32      ulOriginalDelay = 0;
    UINT32      ulActiveDuration = 0;
    UINT32      ulRepeatDelayTimeOffset = 0;
    SourceInfo*       pResult = NULL;
    RepeatInfo*       pRepeatInfo = NULL;
    RepeatInfo*       pRepeatInfoHead = NULL;
    RepeatInfo*       pRepeatInfoTail = NULL;
    CHXSimpleList*  pRepeatList = NULL;
    LISTPOSITION    pRepeatPos = 0;
   
    pRepeatPos = m_curPosition;
    ulOriginalDuration = m_pSource->m_ulOriginalDuration;
    ulOriginalDelay = m_pSource->m_ulOriginalDelay;
    ulActiveDuration = GetActiveDuration();
    pRepeatList = m_bLeadingSource?m_pRepeatList:m_pPeerSourceInfo->m_pRepeatList;

    // within the active source
    if (ulSeekTime >= m_pSource->GetDelay() &&
      ulSeekTime < m_pSource->GetDuration())
    {
      pResult = this;
      goto cleanup;
    }

    // after the repeated sources(exclude repeat="indefinite")
    if (!m_bRepeatIndefinite && ulSeekTime > ulActiveDuration)
    {
      pResult = this;
      goto cleanup;
    }

    // end the current source
    if (!m_pSource->IsSourceDone())
    {
      m_pSource->SetEndOfClip(TRUE);
    }
    m_bDone = TRUE;

    // seek to the next spawned source
    if (ulSeekTime >= m_pSource->GetDuration() &&
        ulSeekTime < m_pPeerSourceInfo->m_pSource->GetDuration())
    {
      pResult = m_pPeerSourceInfo;
      goto cleanup;
    }

    // seek before the repeated source
    if (ulSeekTime < ulOriginalDelay)
    {
      pResult = this;
      pResult->m_curPosition = pRepeatList->GetHeadPosition();
      
      if (pResult->m_ulRepeatDelayTimeOffset != 0)
      {
          pResult->m_ulRepeatDelayTimeOffset = 0;
          pResult->m_pPeerSourceInfo->m_ulRepeatDelayTimeOffset = 0;
          bRepeatDelayTimeOffsetAdjusted = TRUE;
      }
    }
    else
    {
      // need to figure out the exact iteration on repeat indefinite
      if (m_bRepeatIndefinite)
      {
          pRepeatInfoHead = (RepeatInfo*)pRepeatList->GetHead();
          pRepeatInfoTail = (RepeatInfo*)pRepeatList->GetTail();
          
          ulRepeatDelayTimeOffset = pRepeatInfoTail->ulDelay + m_ulRepeatInterval - pRepeatInfoHead->ulDelay;
      }

      // ahead of the current source
      if (ulSeekTime < m_pSource->GetDelay())
      {
          if (m_bRepeatIndefinite)
          {
            // need to figure out the exact iteration on repeat indefinite
            while (m_ulRepeatDelayTimeOffset + pRepeatInfoHead->ulDelay > ulSeekTime)
            {
                m_ulRepeatDelayTimeOffset -= ulRepeatDelayTimeOffset;
                bRepeatDelayTimeOffsetAdjusted = TRUE;
            }

            // start from its tail
            if (bRepeatDelayTimeOffsetAdjusted)
            {
                pRepeatPos = pRepeatList->GetTailPosition();
            }
          }

          pRepeatInfo = (RepeatInfo*)pRepeatList->GetAt(pRepeatPos);
          while (pRepeatPos != pRepeatList->GetHeadPosition())
          {
            if (ulSeekTime >= (pRepeatInfo->ulDelay + m_ulRepeatDelayTimeOffset))
            {
                break;
            }
            pRepeatInfo = (RepeatInfo*)pRepeatList->GetAtPrev(pRepeatPos);
          }
      }
      else
      {                     
          if (m_bRepeatIndefinite)
          {
            // need to figure out the exact iteration on repeat indefinite
            while (m_ulRepeatDelayTimeOffset + pRepeatInfoTail->ulDelay + ulOriginalDuration <
                   ulSeekTime)
            {
                m_ulRepeatDelayTimeOffset += ulRepeatDelayTimeOffset;
                bRepeatDelayTimeOffsetAdjusted = TRUE;
            }

            // start from its head
            if (bRepeatDelayTimeOffsetAdjusted)
            {
                pRepeatPos = pRepeatList->GetHeadPosition();
            }
          }

          pRepeatInfo = (RepeatInfo*)pRepeatList->GetAt(pRepeatPos);
          while (pRepeatPos != pRepeatList->GetTailPosition())
          {
            if (ulSeekTime <= (m_ulRepeatDelayTimeOffset + pRepeatInfo->ulDelay + ulOriginalDuration))
            {
                break;
            }
            pRepeatInfo = (RepeatInfo*)pRepeatList->GetAtNext(pRepeatPos);
          }
      }

      pResult = m_pPeerSourceInfo;
      pResult->m_curPosition = pRepeatPos;
      pResult->m_bTobeInitializedBeforeBegin = TRUE;
    }

    if (bRepeatDelayTimeOffsetAdjusted)
    {
      pResult->m_ulRepeatDelayTimeOffset = m_ulRepeatDelayTimeOffset;
      pResult->m_pPeerSourceInfo->m_ulRepeatDelayTimeOffset = m_ulRepeatDelayTimeOffset;  
      m_pPlayer->AdjustPresentationTime();
    }

    pResult->Reset();
    pResult->m_pSource->ReSetup();

cleanup:

    if (pRepeatPos == pRepeatList->GetTailPosition() ||
      ulSeekTime > ulActiveDuration)
    {
      pResult->m_pPeerSourceInfo->Reset();
    }

    pResult->m_bRepeatPending = FALSE;
    pResult->m_pPeerSourceInfo->m_bRepeatPending = TRUE;

    if (pResult != this)
    {
      pResult->m_bSeekPending = TRUE;
      pResult->m_ulSeekTime = ulSeekTime;
    }

    return pResult;
#else
    return NULL;
#endif /* HELIX_FEATURE_SMIL_REPEAT */
}

UINT32
SourceInfo::GetActiveDuration()
{
    UINT32      ulDuration = 0;
    RepeatInfo*       pRepeatInfo = NULL;
    CHXSimpleList*  pRepeatList = m_bLeadingSource?m_pRepeatList:m_pPeerSourceInfo->m_pRepeatList;

    if (m_ulTotalTrackDuration)
    {
      return m_ulTotalTrackDuration;
    }

    if (pRepeatList)
    {
      pRepeatInfo = (RepeatInfo*)pRepeatList->GetTail();    
      ulDuration = pRepeatInfo->ulDuration + pRepeatInfo->ulDelay + m_ulRepeatDelayTimeOffset;

      if (m_bRepeatIndefinite &&
          m_ulMaxDuration)
      {
          ulDuration = m_pSource->m_ulOriginalDelay + m_ulMaxDuration;
      }
    }
    else
    { 
      ulDuration = m_pSource->GetDuration();
    }
    
    return ulDuration;
}

BOOL        
SourceInfo::KeepSourceActive(void)
{
    BOOL bResult = TRUE;
    CHXSimpleList* pRepeatList = m_bLeadingSource?m_pRepeatList:m_pPeerSourceInfo->m_pRepeatList;
    
    if (pRepeatList)
    {
      // XXX HP re-exam
      // we should keep the repeated source active till the end of its duration
      if (m_bRepeatIndefinite)
      {
          if (m_ulMaxDuration &&
            m_pSource->GetDuration() >= m_pSource->m_ulOriginalDelay + m_ulMaxDuration)
          {
            bResult = FALSE;
            goto cleanup;
          }
      }
      else if (m_curPosition == pRepeatList->GetTailPosition())
      {
          bResult = FALSE;
          goto cleanup;
      }
    }
            
    if (m_pPlayer->IsAtSourceMap(this)    && 
      !m_pSource->IsPaused()        &&
      GetActiveDuration() < m_pPlayer->m_ulCurrentPlayTime)
    {
      bResult = FALSE;
      goto cleanup;
    }

cleanup:

    return bResult;
}

void SourceInfo::TimeSyncCallback(void* pParam)
{
    struct timeSyncParamStruct* pObj = (struct timeSyncParamStruct*)pParam;

    if (pObj)
    {
        HX_RESULT theErr = pObj->pSourceInfo->OnTimeSync(pObj->pRenderInfo);
        //{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p TimeSyncCallback::Func: Before False\n", this);::fclose(f1);}
        //{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p TimeSyncCallback::Func: Before OnTimeSync\n", this);::fclose(f1);}
        //{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p TimeSyncCallback::Func: After OnTimeSync\n", this);::fclose(f1);}
        if (theErr)
        {
            pObj->pSourceInfo->m_pPlayer->Report( HXLOG_ERR, theErr, 0, NULL, NULL );
        }
    }
}

void SourceInfo::ProcessCallback(void* pParam)
{
    HX_RESULT theErr = HXR_OK;
    SourceInfo* pObj = (SourceInfo*)pParam;

    if (pObj)
    {
      if (pObj->m_pSource)
      {
          theErr = pObj->m_pSource->ProcessIdle();
      }

      if (!theErr && 
            pObj->m_pPlayer && 
            pObj->m_pPlayer->IsInitialized() && 
            !pObj->IsInitialized())
      {
          theErr = pObj->InitializeAndSetupRendererSites();
      }
    }
}

Generated by  Doxygen 1.6.0   Back to index