/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxplay.cpp,v 1.64.2.5 2004/07/13 21:08:50 ehodge 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"
#if (defined( _WIN32 ) || defined( _WINDOWS )) && !defined(WIN32_PLATFORM_PSPC)
#include <winsock2.h>
#endif /* defined( _WIN32 ) || defined( _WINDOWS ) */
#include "hxcom.h"
#include "hxmime.h"
#include "dbcs.h"
#include "chxxtype.h"
#include "hxresult.h"

#ifndef _WINCE
#include "hlxclib/signal.h"
#endif

#include "conn.h"
#if defined( _WIN32 ) || defined( _WINDOWS )
#include "platform/win/win_net.h"
#elif defined (_MACINTOSH)
#include "mac_net.h"
#elif defined (_UNIX)
#include "unix_net.h"
#elif defined(__TCS__)
#include "platform/tm1/tm1_net.h"
#endif // defined( _WIN32 ) || defined( _WINDOWS )

#include "hxcomm.h"
#include "ihxpckts.h"
#include "hxfiles.h"
#include "hxformt.h"
#include "hxengin.h"
#include "hxcore.h"
#include "hxprefs.h"
#include "hxpref.h"
#include "hxclsnk.h"
#include "hxpends.h"
#include "hxhyper.h"
#include "playhpnv.h"
#include "hxmon.h"
#if defined(HELIX_FEATURE_ASM)
#include "hxasm.h"
#include "hxsmbw.h"
#include "createbwman.h"
#endif /* HELIX_FEATURE_ASM */
#include "hxplugn.h"
#include "chxeven.h"
#include "chxelst.h"
#include "strminfo.h"
#if defined(HELIX_FEATURE_MEDIAMARKER)
#include "hxmmrkr.h"
#endif /* #if defined(HELIX_FEATURE_MEDIAMARKER) */
#if defined(HELIX_FEATURE_EVENTMANAGER)
#include "hxinter.h"
#endif /* #if defined(HELIX_FEATURE_EVENTMANAGER) */

#include "hxslist.h"
#include "hxmap.h"
#include "hxstrutl.h"
//#include "plgnhand.h"
#include "hxrquest.h"
#include "chxelst.h"
#include "hxbsrc.h"
#include "hxsrc.h"
#include "hxflsrc.h"
#include "hxntsrc.h"
#include "hxrendr.h"
#include "hxwin.h"
#include "hxstrm.h"
#include "hxcleng.h"
#include "timeline.h"
#include "hxstring.h"
#include "timeval.h"
#include "hxerror.h"
#include "sinkctl.h"
#include "upgrdcol.h"
#include "chxphook.h"
#include "hxgroup.h"
#include "basgroup.h"
#include "advgroup.h"

// temporary
//#define DEBUG_LOG_INFO    1
#include "hxstat.h"
#include "auderrs.h"
#include "hxausvc.h"
#include "hxaudses.h"
#include "hxaudply.h"
#include "hxplay.h"
#include "hxplugn.h"
#include "hxtick.h"

#include "srcinfo.h"
#include "nxtgrmgr.h"
#include "prefmgr.h"
#include "srcinfo.h"
#include "errdbg.h"
#include "hxthread.h"
#include "hxxrsmg.h"
#include "hxresmgr.h"
#include "portaddr.h"
#if defined(HELIX_FEATURE_SMARTERNETWORK)
#include "preftran.h"
#endif /* HELIX_FEATURE_SMARTERNETWORK */
#include "cookies.h"
#include "viewport.h"
#if defined(HELIX_FEATURE_MEDIAMARKER)
#include "mediamrk.h"
#endif /* #if defined(HELIX_FEATURE_MEDIAMARKER) */
#if defined(HELIX_FEATURE_EVENTMANAGER)
#include "eventmgr.h"
#endif /* #if defined(HELIX_FEATURE_EVENTMANAGER) */
#include "hxtac.h"
#if defined(_STATICALLY_LINKED) || !defined(HELIX_FEATURE_PLUGINHANDLER2)
#include "hxpluginmanager.h"
#else
#include "plghand2.h"
#endif /* _STATICALLY_LINKED */
//#include "../dcondev/dcon.h"
//BOOL g_bRahulLog = FALSE;

#if defined(_MACINTOSH) || defined(_MAC_UNIX)
#include "platform/mac/hx_moreprocesses.h"
#endif

#ifdef _MACINTOSH
#include "hxmm.h"
#endif

#ifdef _UNIX
#include "unix_net.h"
#endif

#include "sitemgr.h"

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

#ifdef _WIN16
extern HINSTANCE g_hInstance;       // initialized in DLLMAIN.CPP(rmacore.dll)
#endif

#if defined(__TCS__)
#if defined(__cplusplus)
extern "C" {
#endif

void hookRealAudio_ReportError(int err, long errVal);

#ifdef __cplusplus
}
#endif
#endif

#define MIN_DELAYBEFORE_START       2000
#define BEGIN_SYNC_FUDGE_FACTOR     50
#define MAX_LOOP_EXE_TIME           300 //100
#define ALLFS                       0xFFFFFFFF


#define GOTOEXITONERROR(theErr, label)      if (theErr) goto label

/* Please add any variables to be re-initialized in the ResetPlayer()
 * function also.
 */
HXPlayer::HXPlayer() :
     m_pURL (0)
    ,m_lRefCount (0)
    ,m_pPreferences(0)
    ,m_pClientRequestSink(0)
    ,m_pHyperNavigate(0)
    ,m_pRegistry(0)
    ,m_pStats(0)
    ,m_pUpdateStatsCallback(0)
    ,m_ulStatsGranularity(1000)
    ,m_pEngine (0)
    ,m_pPlugin2Handler(0)
    ,m_pAudioPlayer (0)
    ,m_uNumSourcesActive(0)
    ,m_uNumCurrentSourceNotDone(0)
    ,m_bInitialized (FALSE)
    ,m_pPendingTrackList(NULL)
    ,m_ulCurrentPlayTime (0)
#if defined(_MACINTOSH) || defined(_MAC_UNIX)
    ,m_ulCurrentSystemPlayTime(0)
#endif
    ,m_ulPresentationDuration(0)
    ,m_ulTimeBeforeSeek (0)
    ,m_ulTimeAfterSeek (0)
    ,m_BufferingReason(BUFFERING_START_UP)
    ,m_pScheduler(0)
    ,m_bIsDone(TRUE)
    ,m_bIsPresentationDone(TRUE)
    ,m_bIsPresentationClosedToBeSent(FALSE)
    ,m_bCoreLocked(FALSE)
    ,m_bPaused(FALSE)
    ,m_bBeginPending(FALSE)
    ,m_pClient(0)
    ,m_ulLowestGranularity(DEFAULT_TIMESYNC_GRANULARITY)
    ,m_bTimelineToBeResumed (FALSE)
    ,m_bIsPlaying(FALSE)
    ,m_bNetInitialized(FALSE)
    ,m_bPrefTransportInitialized(FALSE)
    ,m_bIsFirstBegin(TRUE)
    ,m_bIsFirstBeginPending(FALSE)
    ,m_bIsLive(FALSE)
    ,m_bProcessEventsLocked(FALSE)
    ,m_bTimeSyncLocked(FALSE)
    ,m_bCurrentPresentationClosed(FALSE)
    ,m_LastError(HXR_OK)
    ,m_bInStop(FALSE)
    ,m_bPlayerWithoutSources(FALSE)
    ,m_ulMinimumAudioPreroll(0)
    ,m_ulMinimumTotalPreroll(0)
    ,m_bInternalPauseResume(FALSE)
    ,m_bInternalReset(FALSE)
    ,m_pErrorSinkControl(NULL)
    ,m_pAdviseSink(NULL)
    ,m_pSiteManager(NULL)
    ,m_pSiteSupplier(NULL)
    ,m_pHXPlayerCallback(0)
    ,m_pSetupCallback(0)
    ,m_pAuthenticationCallback(NULL)
    ,m_pHXPlayerInterruptCallback(NULL)
    ,m_nGroupCount(0)
    ,m_nCurrentGroup(0)
    ,m_bContactingDone(FALSE)
    ,m_pUpgradeCollection(NULL)
    ,m_pPacketHookManager(NULL)
    ,m_bIsFirstTimeSync(TRUE)
    ,m_ulFirstTimeSync(0)
    ,m_ulElapsedPauseTime(0)
    ,m_ulLiveSeekTime(0)
    ,m_ulTimeOfPause(0)
    ,m_bLiveSeekToBeDone(FALSE)
    ,m_bFastStartInProgress(FALSE)
    ,m_ulFSBufferingEndTime(0)
    ,m_bAllLocalSources(TRUE)
    ,m_bFSBufferingEnd(FALSE)
    ,m_pGroupManager(NULL)
    ,m_bPartOfNextGroup(FALSE)
    ,m_pNextGroupManager(NULL)
    ,m_pPrefetchManager(NULL)
    ,m_bLastGroup(FALSE)
    ,m_bNextGroupStarted(FALSE)
    ,m_bDidWeDeleteAllEvents(FALSE)
    ,m_bSetupLayoutSiteGroup(TRUE)
    ,m_pCurrentGroup(NULL)
    ,m_bBeginChangeLayoutTobeCalled(TRUE)
    ,m_b100BufferingToBeSent(TRUE)
    ,m_bUserHasCalledBegin(FALSE)
    ,m_bCloseAllRenderersPending(FALSE)
    ,m_uNumSourceToBeInitializedBeforeBegin(0)
    ,m_pCoreMutex(NULL)
    ,m_bSetupToBeDone(FALSE)
    ,m_bPostSetupToBeDone(FALSE)
    ,m_pRequest(NULL)
    ,m_pAltURLs(NULL)
    ,m_bActiveRequest(FALSE)
    ,m_bUseCoreThread(FALSE)
    ,m_bAddLayoutSiteGroupCalled(FALSE)
    ,m_pLastUserString(NULL)
    ,m_pLastMoreInfoURL(NULL)
    ,m_bForceStatsUpdate(FALSE)
#if defined(HELIX_FEATURE_ASM)
    ,m_pBandwidthMgr(NULL)
    ,m_pASM(NULL)
#endif
    ,m_pRedirectList(NULL)
    ,m_bPendingAudioPause(FALSE) // currently used ONLY on Mac
    ,m_bPlayStateNotified(FALSE)
    ,m_bResumeOnlyAtSystemTime(FALSE)
    ,m_bSourceMapUpdated(FALSE)
    ,m_pPreferredTransportManager(NULL)
    ,m_pNetInterfaces(NULL)
    ,m_pClientViewSource(NULL)
    ,m_pViewPortManager(NULL)
    ,m_pMediaMarkerManager(NULL)
    ,m_pEventManager(NULL)
    ,m_pClientViewRights(NULL)
    ,m_ulRepeatedRegistryID(0)
    ,m_ulNextGroupRegistryID(0)
    ,m_pCookies(NULL)
    ,m_pParentPlayer(NULL)
    ,m_pChildPlayerList(NULL)
    ,m_bSetModal(FALSE)
    ,m_pPersistentComponentManager(NULL)
    ,m_pAutheticationValues(NULL)
    ,m_bDoRedirect(FALSE)
    ,m_ulActiveSureStreamSource(0)
    ,m_bFastStartCheckDone(FALSE)
    ,m_bFastStart(FALSE)
    ,m_turboPlayOffReason(TP_OFF_BY_UNKNOWN)
    ,m_pMasterTAC(NULL)
#ifdef _WIN32
    ,m_bScreenSaverActive(0)
#endif
    ,m_pRecordService(NULL)
    ,m_bRecordServiceEnabled(FALSE)
/* Please add any variables to be re-initialized in the ResetPlayer()
 * function also.
 */
{
    m_pSourceMap = new CHXMapPtrToPtr;
    m_pSharedWallClocks = new CHXMapStringToOb;
    
#if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
         HXStaticStatLog::Open_Write("e:\\log.txt");
#endif // DEBUG_LOG_INFO

    ResetError();

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    m_pUpdateStatsCallback              = new UpdateStatsCallback;
    m_pUpdateStatsCallback->m_pPlayer   = this;
    m_pUpdateStatsCallback->AddRef();
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

#if defined (_WIN32) || defined (_MACINTOSH) || defined(THREADS_SUPPORTED)
    m_pHXPlayerCallback = new HXPlayerCallback((void*)this, (fGenericCBFunc)PlayerCallback);
    m_pHXPlayerInterruptCallback = new HXPlayerCallback((void*)this, (fGenericCBFunc)PlayerCallback);
    m_pSetupCallback = new HXPlayerCallback((void*)this, (fGenericCBFunc)SetupCallback);

    ((HXPlayerCallback*)m_pHXPlayerInterruptCallback)->m_bInterrupSafe  = TRUE;
    ((HXPlayerCallback*)m_pSetupCallback)->m_bInterrupSafe = TRUE;

#else
    m_pHXPlayerCallback = new CHXGenericCallback((void*)this, (fGenericCBFunc)PlayerCallback);
    m_pHXPlayerInterruptCallback = new CHXGenericCallback((void*)this, (fGenericCBFunc)PlayerCallback);
    m_pSetupCallback = new CHXGenericCallback((void*)this, (fGenericCBFunc)SetupCallback);
#endif
    m_pHXPlayerCallback->AddRef();
    m_pHXPlayerInterruptCallback->AddRef();
    m_pSetupCallback->AddRef();

#if defined(HELIX_FEATURE_AUTHENTICATION)
    m_pAuthenticationCallback = new CHXGenericCallback((void*)this, (fGenericCBFunc)AuthenticationCallback);
    m_pAuthenticationCallback->AddRef();
#endif /* HELIX_FEATURE_AUTHENTICATION */

#if defined(HELIX_FEATURE_SINKCONTROL)
    m_pErrorSinkControl     = new CHXErrorSinkControl;
    m_pAdviseSink           = new CHXAdviseSinkControl;
#endif /* HELIX_FEATURE_SINKCONTROL */
#if defined(HELIX_FEATURE_VIDEO)
    m_pSiteManager          = new CHXSiteManager();
#endif /* HELIX_FEATURE_VIDEO */
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    m_pGroupManager         = new HXAdvancedGroupManager(this);
#elif defined(HELIX_FEATURE_BASICGROUPMGR)
    m_pGroupManager         = new HXBasicGroupManager(this);
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR */
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    m_pNextGroupManager     = new NextGroupManager(this);
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
#if defined(HELIX_FEATURE_MASTERTAC)
    m_pMasterTAC            = new HXMasterTAC(m_pGroupManager);
#endif /* HELIX_FEATURE_MASTERTAC */
#if defined(HELIX_FEATURE_VIEWPORT)
    m_pViewPortManager      = new HXViewPortManager(this);
#endif /* HELIX_FEATURE_VIEWPORT */
#if defined(HELIX_FEATURE_MEDIAMARKER)
    m_pMediaMarkerManager   = new CHXMediaMarkerManager(this);
    if (m_pMediaMarkerManager) m_pMediaMarkerManager->AddRef();
#endif /* #if defined(HELIX_FEATURE_MEDIAMARKER) */
#if defined(HELIX_FEATURE_NESTEDMETA)
    m_pPersistentComponentManager = new HXPersistentComponentManager(this);
#endif /* HELIX_FEATURE_NESTEDMETA */

    HX_ADDREF(m_pErrorSinkControl);
    HX_ADDREF(m_pAdviseSink);
#if defined(HELIX_FEATURE_VIDEO)
    m_pSiteManager->AddRef();
#endif /* HELIX_FEATURE_VIDEO */
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    m_pGroupManager->AddRef();
    m_pGroupManager->AddSink(this);
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    HX_ADDREF(m_pMasterTAC);
#if defined(HELIX_FEATURE_VIEWPORT)
    m_pViewPortManager->AddRef();
#endif /* HELIX_FEATURE_VIEWPORT */

#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR) && defined(HELIX_FEATURE_MASTERTAC)
    if (m_pGroupManager && m_pMasterTAC)
    {
        m_pGroupManager->SetMasterTAC(m_pMasterTAC);
    }
#endif /* HELIX_FEATURE_ADVANCEDGROUPMGR && HELIX_FEATURE_MASTERTAC */

#if defined(HELIX_FEATURE_NESTEDMETA)
    m_pPersistentComponentManager->AddRef();
    if (m_pGroupManager)
    {
        m_pGroupManager->AddSink(m_pPersistentComponentManager);
    }
#endif /* HELIX_FEATURE_NESTEDMETA */

#if defined(HELIX_FEATURE_AUTOUPGRADE)
    m_pUpgradeCollection = new HXUpgradeCollection;
    m_pUpgradeCollection->AddRef();
#endif /* HELIX_FEATURE_AUTOUPGRADE */

#if defined(HELIX_FEATURE_EVENTMANAGER)
    // Get our own IUnknown interface
    IUnknown* pUnknown = NULL;
    QueryInterface(IID_IUnknown, (void**) &pUnknown);
    if (pUnknown)
    {
        // Initialize the renderer event manager
        m_pEventManager = new CRendererEventManager(pUnknown);
        if (m_pEventManager) m_pEventManager->AddRef();
    }
    HX_RELEASE(pUnknown);
#endif /* #if defined(HELIX_FEATURE_EVENTMANAGER) */
}

HXPlayer::~HXPlayer()
{
    CloseAllRenderers(m_nCurrentGroup);
    ResetPlayer();
    Close();
    HX_DELETE(m_pSourceMap);
    HX_DELETE(m_pSharedWallClocks);
}

/////////////////////////////////////////////////////////////////////////
//      Method:
//              IUnknown::QueryInterface
//      Purpose:
//              Implement this to export the interfaces supported by your
//              object.
//
STDMETHODIMP HXPlayer::QueryInterface(REFIID riid, void** ppvObj)
{
#if defined(HELIX_FEATURE_PACKETHOOKMGR)
    // create the following objects only if needed
    if (!m_pPacketHookManager && IsEqualIID(riid, IID_IHXPacketHookManager))
    {
        m_pPacketHookManager = new PacketHookManager(this);

        if (m_pPacketHookManager)
        {
            m_pPacketHookManager->AddRef();
        }
    }
#endif /* HELIX_FEATURE_PACKETHOOKMGR */

    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXPlayer), (IHXPlayer*)this },
            { GET_IIDHANDLE(IID_IHXPlayer2), (IHXPlayer2*)this },
            { GET_IIDHANDLE(IID_IHXPendingStatus), (IHXPendingStatus*)this },
#if defined(HELIX_FEATURE_AUTHENTICATION)
            { GET_IIDHANDLE(IID_IHXAuthenticationManager), (IHXAuthenticationManager*)this },
            { GET_IIDHANDLE(IID_IHXAuthenticationManager2), (IHXAuthenticationManager2*)this },
#endif /* HELIX_FEATURE_AUTHENTICATION */
            { GET_IIDHANDLE(IID_IHXGroupSink), (IHXGroupSink*)this },
            { GET_IIDHANDLE(IID_IHXAudioPlayerResponse), (IHXAudioPlayerResponse*)this },
            { GET_IIDHANDLE(IID_IHXRegistryID), (IHXRegistryID*)this },
            { GET_IIDHANDLE(IID_IHXErrorMessages), (IHXErrorMessages*)this },
            { GET_IIDHANDLE(IID_IHXLayoutSiteGroupManager), (IHXLayoutSiteGroupManager*)this },
#if defined(HELIX_FEATURE_NESTEDMETA)
            { GET_IIDHANDLE(IID_IHXPersistenceManager), (IHXPersistenceManager*)this },
#endif /* HELIX_FEATURE_NESTEDMETA */
            { GET_IIDHANDLE(IID_IHXDriverStreamManager), (IHXDriverStreamManager*)this },
            { GET_IIDHANDLE(IID_IHXRendererUpgrade), (IHXRendererUpgrade*)this },
            { GET_IIDHANDLE(IID_IHXInternalReset), (IHXInternalReset*)this },
            { GET_IIDHANDLE(IID_IHXPlayerState), (IHXPlayerState*)this },
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
            { GET_IIDHANDLE(IID_IHXPlayerNavigator), (IHXPlayerNavigator*)this },
#endif /* HELIX_FEATURE_PLAYERNAVIGATOR */
            { GET_IIDHANDLE(IID_IHXClientStatisticsGranularity), (IHXClientStatisticsGranularity*)this },
            { GET_IIDHANDLE(IID_IHXPlayerPresentation), (IHXPlayerPresentation*)this },
#if defined(HELIX_FEATURE_RECORDCONTROL)
            { GET_IIDHANDLE(IID_IHXRecordManager), (IHXRecordManager*)this },
#endif /* HELIX_FEATURE_RECORDCONTROL */
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXPlayer*)this },
            { GET_IIDHANDLE(IID_IHXOverrideDefaultServices), (IHXOverrideDefaultServices*)this },
        };
    HX_RESULT res = ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
    
    // if it succeeded, return immediately...
    if (res == HXR_OK)
    {
        return res;
    }
    // ...otherwise continue onward
    
    if (m_pClientViewSource &&
             IsEqualIID(riid, IID_IHXViewSourceCommand))
    {
        AddRef();
        *ppvObj = (IHXViewSourceCommand*)this;
        return HXR_OK;
    }
    else if (m_pErrorSinkControl &&
             m_pErrorSinkControl->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
    else if (m_pAdviseSink &&
             m_pAdviseSink->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
    else if (m_pAudioPlayer &&
             m_pAudioPlayer->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#if defined(HELIX_FEATURE_PREFERENCES)
    else if (m_pPreferences &&
             m_pPreferences->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_PREFERENCES */
#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
    else if (m_pHyperNavigate &&
             m_pHyperNavigate->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_HYPER_NAVIGATE */
#if defined(HELIX_FEATURE_ASM)
    /* m_pASM will be available on a per player basis ONLY under Load testing */
    else if (m_pASM &&
             m_pASM->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_ASM */
#if defined(HELIX_FEATURE_VIDEO)
    else if (m_pSiteManager &&
             m_pSiteManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_VIDEO */
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    else if (m_pUpgradeCollection &&
             m_pUpgradeCollection->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_AUTOUPGRADE */
#if defined(HELIX_FEATURE_PACKETHOOKMGR)
    else if (m_pPacketHookManager &&
             m_pPacketHookManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_PACKETHOOKMGR */
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    else if (m_pGroupManager &&
             m_pGroupManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */
    else if (m_pViewPortManager &&
             m_pViewPortManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#if defined(HELIX_FEATURE_MEDIAMARKER)
    else if (m_pMediaMarkerManager &&
             m_pMediaMarkerManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* #if defined(HELIX_FEATURE_MEDIAMARKER) */
#if defined(HELIX_FEATURE_EVENTMANAGER)
    else if (m_pEventManager &&
             m_pEventManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* #if defined(HELIX_FEATURE_EVENTMANAGER) */
#if defined(HELIX_FEATURE_NESTEDMETA)
    else if (m_pPersistentComponentManager &&
             m_pPersistentComponentManager->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
#endif /* HELIX_FEATURE_NESTEDMETA */
    else if (m_pPlugin2Handler &&
             m_pPlugin2Handler->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
    else if (m_pClient &&
             m_pClient->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
    else if (m_pEngine &&
             m_pEngine->QueryInterface(riid, ppvObj) == HXR_OK)
    {
        return HXR_OK;
    }
    /* DO NOT ADD ANY MROE QIs HERE. ADD IT BEFORE m_pClient QI*/

    *ppvObj = NULL;
    return HXR_NOINTERFACE;
}

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

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

    if(m_lRefCount == 0)
    {
        delete this;
    }
    return 0;
}

// *** IHXPlayer methods ***

/************************************************************************
 *      Method:
 *              IHXPlayer::GetClientEngine
 *      Purpose:
 *              Get the interface to the client engine object of which the player
 *              is a part of.
 *
 */
STDMETHODIMP HXPlayer::GetClientEngine(IHXClientEngine* &pEngine)
{
    pEngine = m_pEngine;

    if (pEngine)
    {
        pEngine->AddRef();
    }

    return HXR_OK;
}

/************************************************************************
 *      Method:
 *              IHXPlayer::Begin
 *      Purpose:
 *              Tell the player to begin playback of all its sources.
 *
 */
STDMETHODIMP HXPlayer::Begin(void)
{
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    theErr = BeginPlayer();
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return theErr;
}

HX_RESULT
HXPlayer::BeginPlayer(void)
{
    HX_RESULT   theErr = HXR_OK;

    m_bUserHasCalledBegin   = TRUE;
    m_bFastStartInProgress  = FALSE;

    if (!m_bInternalPauseResume && !m_bIsFirstBegin && !m_bPaused)
    {
        return HXR_OK;
    }

    if (m_bIsLive && m_bPaused && m_bLiveSeekToBeDone)
    {
        m_ulElapsedPauseTime = CALCULATE_ELAPSED_TICKS(m_ulTimeOfPause, HX_GET_TICKCOUNT());

        /* This is an internal seek due to live pause */
        theErr = SeekPlayer(m_ulLiveSeekTime + m_ulElapsedPauseTime);
    }

    m_bPaused = FALSE;

    if (m_bIsFirstBegin)
    {
        UpdateSourceActive();
    }

    if (!theErr)
    {
        theErr = UpdateStatistics();
    }

    if (!theErr)
    {
        UpdateCurrentPlayTime( m_pAudioPlayer->GetCurrentPlayBackTime() );
    }

    /* Unregister all the sources that are not currently active */
    UnregisterNonActiveSources();

    if (!m_bIsDone)
    {
        CheckSourceRegistration();

        CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
        /* Check if we are done. This may be TRUE for empty files */
        for (;  !theErr && ndxSources != m_pSourceMap->End(); ++ndxSources)
        {
            SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
            theErr = pSourceInfo->Begin();
        }
    }

    /* 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 (!theErr && !m_bIsFirstBegin && !m_bInternalPauseResume && !m_bInternalReset && m_pAdviseSink)
    {
        m_pAdviseSink->OnBegin(m_ulCurrentPlayTime);
    }

    m_bIsFirstBegin = FALSE;
    m_bBeginPending = TRUE;

    m_bFastStartInProgress  = FALSE;

    if (!m_ToBeginRendererList.IsEmpty())
    {
        CheckBeginList();
    }

    return (theErr);
}

/************************************************************************
 *      Method:
 *              IHXPlayer::Stop
 *      Purpose:
 *              Tell the player to stop playback of all its sources.
 *
 */
STDMETHODIMP HXPlayer::Stop(void)
{
    // we want to protect against the TLC opening another URL
    if (m_bSetModal)
    {
        return HXR_OK;
    }

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    StopPlayer(END_STOP);
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return HXR_OK;
}

void
HXPlayer::StopPlayer(EndCode endCode)
{
    StopAllStreams(endCode);
    /* Reset player condition */
    ResetPlayer();
}


/************************************************************************
 *      Method:
 *              IHXPlayer::Pause
 *      Purpose:
 *              Tell the player to pause playback of all its sources.
 *
 */
STDMETHODIMP HXPlayer::Pause(void)
{
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    theErr = PausePlayer();
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return theErr;
}

HX_RESULT
HXPlayer::PausePlayer(BOOL bNotifyTLC /* = TRUE*/)
{
    HX_RESULT theErr = HXR_OK;

    if (m_bIsDone)
    {
        return HXR_UNEXPECTED;
    }

    if (m_bPaused)
    {
        return HXR_OK;
    }

    m_bPaused = TRUE;

    if (m_bIsLive && !(m_bRecordServiceEnabled && m_pRecordService))
    {
        m_bLiveSeekToBeDone = TRUE;
        m_ulLiveSeekTime    = m_pAudioPlayer->GetCurrentPlayBackTime();
        m_ulTimeOfPause     = HX_GET_TICKCOUNT();
    }

    m_bIsPlaying            = FALSE;
    m_bTimelineToBeResumed  = TRUE;
    m_pAudioPlayer->Pause();

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();

    for (;  !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        theErr = pSourceInfo->Pause();
    }

    /* Send OnPause to advice sink ONLY if it is not an internal Pause */
    if (bNotifyTLC && !m_bInternalPauseResume && !m_bInternalReset && m_pAdviseSink)
    {
        m_pAdviseSink->OnPause(m_ulCurrentPlayTime);
    }

    return (theErr);
}

/************************************************************************
 *      Method:
 *              IHXPlayer::Seek
 *      Purpose:
 *              Tell the player to seek in the playback timeline of all its
 *              sources.
 *
 */
STDMETHODIMP HXPlayer::Seek(ULONG32    ulTime)
{
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    theErr = SeekPlayer(ulTime);
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return theErr;
}

HX_RESULT
HXPlayer::SeekPlayer(ULONG32    ulTime)
{
    HX_RESULT theErr = HXR_OK;

    if (m_bIsDone)
    {
        return HXR_UNEXPECTED;
    }

    // do not allow seeking till we have been initialized
    if (!m_bInitialized)
    {
        return HXR_NOT_INITIALIZED;
    }

    /* we do allow internal seek (done during resume after live pause)*/
    if ((m_bIsLive && !m_bLiveSeekToBeDone && !(m_bRecordServiceEnabled && m_pRecordService)) ||
        !AreAllSourcesSeekable())
    {
        /* Add error code for HXR_OPERATION_NOT_ALLOWED*/
        return HXR_FAILED;
    }

    /* Someone called Seek without calling Pause, So we will have to call
     * Pause and Resume internally
     */
    if (!m_bPaused)
    {
        m_bInternalPauseResume  = TRUE;
        PausePlayer();
    }

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    /* Stop prefetching */
    if (m_pNextGroupManager->GetNumSources() > 0)
    {
        m_pNextGroupManager->StopPreFetch();
        m_bLastGroup        = FALSE;
        m_bNextGroupStarted = FALSE;
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

    m_ulTimeBeforeSeek  = m_pAudioPlayer->GetCurrentPlayBackTime();
    m_ulTimeAfterSeek   = ulTime;

    UpdateCurrentPlayTime(ulTime);

    m_pAudioPlayer->Seek(ulTime);

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        pSourceInfo->Seek(ulTime);
    }

    if (m_pAdviseSink)
    {
        m_pAdviseSink->OnPreSeek(m_ulTimeBeforeSeek, m_ulTimeAfterSeek);
    }

    // change the state of buffering to seek
    if (m_bIsLive)
    {
        m_BufferingReason       = BUFFERING_LIVE_PAUSE;
    }
    else
    {
        m_BufferingReason       = BUFFERING_SEEK;
    }

    /* Send all pre-seek events to the renderers */
    SendPreSeekEvents();

    ndxSource = m_pSourceMap->Begin();
    for (; !theErr && ndxSource != m_pSourceMap->End();)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        HXSource * pSource = pSourceInfo->m_pSource;

        // since the map index could be screwed up by the removing of
        // the current node in AdjustSeekOnRepeatedSource()
        ++ndxSource;

        /* pSource should never be NULL */
        HX_ASSERT(pSource);
        if (pSourceInfo->m_bSeekPending || !pSourceInfo->IsInitialized())
        {
            continue;
        }

        /* This will pump all pre-seek packets to the renderer(s) */
        if (pSourceInfo->m_pPeerSourceInfo)
        {
            theErr = AdjustSeekOnRepeatedSource(pSourceInfo, ulTime);
        }
        else
        {
            theErr = pSource->DoSeek(ulTime);
        }
    }

    m_b100BufferingToBeSent = TRUE;

    // reset the player state
    UpdateSourceActive();
    m_bIsDone           = FALSE;

    if (!theErr)
    {
        if (m_bInternalPauseResume)
        {
            theErr = Begin();
            m_bInternalPauseResume = FALSE;
        }
        else
        {
            /* Start pre-fetch */
            theErr = StartDownload();
        }
    }

    return (theErr);
}


/************************************************************************
 *  Method:
 *    IHXPlayer::GetSourceCount
 *  Purpose:
 *    Returns the current number of source instances supported by
 *    this player instance.
 */
STDMETHODIMP_(UINT16) HXPlayer::GetSourceCount()
{
    /* We may have stopped the sources but not removed from the SourceMap
     * since we need to keep the renderers active till the next URL is
     * opened. In this case, report the current number of active sources
     * as zero.
     */
    if (m_bCloseAllRenderersPending)
    {
        return 0;
    }
    else
    {
        return (UINT16)m_pSourceMap->GetCount();
    }
}

/************************************************************************
 *  Method:
 *    IHXPlayer::GetSource
 *  Purpose:
 *    Returns the Nth source instance supported by this player.
 */
STDMETHODIMP HXPlayer::GetSource
(
    UINT16              nIndex,
    REF(IUnknown*)      pUnknown
)
{
    pUnknown = NULL;

    if (m_bCloseAllRenderersPending || nIndex >= m_pSourceMap->GetCount())
    {
        return HXR_INVALID_PARAMETER;
    }

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();

    for (UINT16 i = 0; i < nIndex; i++)
    {
        ++ndxSource;
    }

    SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
    HX_ASSERT(pSourceInfo);

    HXSource* pSource = pSourceInfo->m_pSource;
    if(!pSource)
    {
        pUnknown = NULL;
        return HXR_UNEXPECTED;
    }

    return pSource ? pSource->QueryInterface(IID_IUnknown,(void**)&pUnknown) : HXR_FAIL;
}

/************************************************************************
 *  Method:
 *    IHXPlayer::GetClientContext
 *  Purpose:
 *    Called by the get the client context for this player. This is
 *    traditionally to determine called by top level client application.
 */
STDMETHODIMP HXPlayer::GetClientContext
(
    REF(IUnknown*)      pUnknown
)
{
    pUnknown = m_pClient;
    if (m_pClient)
    {
        m_pClient->AddRef();
    }
    return HXR_OK;
}

/************************************************************************
 *  Method:
 *      IHXPlayer::SetClientContext
 *  Purpose:
 *      Called by the client to install itself as the provider of client
 *      services to the core. This is traditionally called by the top
 *      level client application.
 */
STDMETHODIMP HXPlayer::SetClientContext(IUnknown* pUnknown)
{
    if (m_pClient) return HXR_UNEXPECTED;
    if (!pUnknown) return HXR_UNEXPECTED;
    m_pClient = pUnknown;
    m_pClient->AddRef();

    /* Override Default objects */

#if defined(HELIX_FEATURE_PREFERENCES)
    IHXPreferences* pPreferences = 0;
    if (HXR_OK == m_pClient->QueryInterface(IID_IHXPreferences, (void**) &pPreferences) ||
        HXR_OK == m_pEngine->QueryInterface(IID_IHXPreferences, (void**) &pPreferences))
    {
        HX_RELEASE(m_pPreferences);
        m_pPreferences = pPreferences;
    }
#endif /* HELIX_FEATURE_PREFERENCES */

#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
    IHXHyperNavigate* pHyperNavigate = NULL;
    IHXHyperNavigateWithContext* pHyperNavigateWithContext = NULL;
    m_pClient->QueryInterface(IID_IHXHyperNavigateWithContext,
                                (void**) &pHyperNavigateWithContext);

    m_pClient->QueryInterface(IID_IHXHyperNavigate, (void**) &pHyperNavigate);
    if (pHyperNavigate == NULL)
    {
        m_pEngine->QueryInterface(IID_IHXHyperNavigate, (void**) &pHyperNavigate);
    }

    HX_ASSERT(pHyperNavigate != NULL);

    if (pHyperNavigate || pHyperNavigateWithContext)
    {
        HX_ASSERT(m_pHyperNavigate == NULL);
        HX_RELEASE(m_pHyperNavigate);

        //
        // Create new hypernaviate interface that knows how to interpret commands.
        //

        PlayerHyperNavigate* pPlayerHyperNavigate = new PlayerHyperNavigate;

        // override the default hypernavigate interface with one that can interpret commands.
        pPlayerHyperNavigate->AddRef();

        pPlayerHyperNavigate->Init((IHXPlayer*)this, pHyperNavigate, pHyperNavigateWithContext);

        m_pHyperNavigate = pPlayerHyperNavigate;

        // free memory
        HX_RELEASE(pHyperNavigate);
        HX_RELEASE(pHyperNavigateWithContext);
    }
#endif /* defined(HELIX_FEATURE_HYPER_NAVIGATE) */

#if defined(HELIX_FEATURE_VIDEO)
    IHXSiteSupplier*   pSiteSupplier = 0;
    if (HXR_OK == m_pClient->QueryInterface(IID_IHXSiteSupplier, (void**) &pSiteSupplier))
    {
        HX_RELEASE(m_pSiteSupplier);
        m_pSiteSupplier = pSiteSupplier;
    }
#endif /* HELIX_FEATURE_VIDEO */

    m_pClient->QueryInterface(IID_IHXClientRequestSink, (void**) &m_pClientRequestSink);

    /* For load testing, we have ASM Manager on a per player basis */
#if defined(HELIX_FEATURE_ASM)
    BOOL bLoadTest = FALSE;
    ReadPrefBOOL(m_pPreferences, "LoadTest", bLoadTest);

    if (bLoadTest)
    {
        HX_ASSERT(m_pASM == NULL);
        m_pASM = CreateBandwidthManager();

        if (m_pASM)
        {
            m_pASM->AddRef();

            HX_RELEASE(m_pBandwidthMgr);
            m_pASM->QueryInterface(IID_IHXBandwidthManager,
                                   (void**) &m_pBandwidthMgr);
        }
    }
#endif /* HELIX_FEATURE_ASM */

    return HXR_OK;
}




/************************************************************************
 *      Method:
 *              HXPlayer::Init
 *      Purpose:
 *              Get the interface to the client engine object of which the player
 *              is a part of.
 *
 */
STDMETHODIMP HXPlayer::Init(IHXClientEngine*  pEngine,
                             UINT32             unRegistryID,
                             CHXAudioPlayer*    pAudioPlayer)
{
    HX_RESULT   theErr = HXR_OK;
    IHXBuffer*  pPlayerRegName = NULL;

    m_pEngine   = (HXClientEngine *) pEngine;
    m_pAudioPlayer  = pAudioPlayer;
    m_pCoreMutex = m_pEngine->GetCoreMutex();

    m_pEngine->m_pPlugin2Handler->QueryInterface(IID_IHXPlugin2Handler,
                                                 (void**)&m_pPlugin2Handler);

    if (m_pEngine)
    {
        m_pEngine->AddRef();

#if defined(HELIX_FEATURE_SINKCONTROL)
        if (m_pAdviseSink)
        {
            m_pAdviseSink->Init(m_pEngine);
        }

        if (m_pErrorSinkControl)
        {
            m_pErrorSinkControl->Init(m_pEngine);
        }
#endif /* HELIX_FEATURE_SINKCONTROL */

        theErr = m_pEngine->QueryInterface(IID_IHXScheduler,
                                            (void**) &m_pScheduler);

#if defined(HELIX_FEATURE_ASM)

        m_pEngine->QueryInterface(IID_IHXBandwidthManager,
                                            (void**) &m_pBandwidthMgr);
#endif /* HELIX_FEATURE_ASM */

        m_pEngine->QueryInterface(IID_IHXClientViewSource,
                                            (void**)&m_pClientViewSource);

        m_pEngine->QueryInterface(IID_IHXClientViewRights,
                                            (void**)&m_pClientViewRights);

        m_pEngine->QueryInterface(IID_IHXPreferredTransportManager,
                                            (void**)&m_pPreferredTransportManager);

        m_pEngine->QueryInterface(IID_IHXNetInterfaces,
                                            (void**)&m_pNetInterfaces);

#if defined(HELIX_FEATURE_REGISTRY)
        // create registry entries
        if (HXR_OK != m_pEngine->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry))
        {
            m_pRegistry = NULL;
        }
        else
#endif /* HELIX_FEATURE_REGISTRY */
        {
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
            char        szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */

            m_pStats = new PLAYER_STATS(m_pRegistry, unRegistryID);
            m_pRegistry->AddInt("Statistics.StreamSwitchOccured", 0);

            if (m_pRegistry &&
                HXR_OK == m_pRegistry->GetPropName(unRegistryID, pPlayerRegName))
            {
                SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Repeat", pPlayerRegName->GetBuffer());
                m_ulRepeatedRegistryID = m_pRegistry->AddComp(szRegName);

                SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.NextGroup", pPlayerRegName->GetBuffer());
                m_ulNextGroupRegistryID = m_pRegistry->AddComp(szRegName);
            }
            HX_RELEASE(pPlayerRegName);
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

#if defined(HELIX_FEATURE_REGISTRY) && defined(HELIX_FEATURE_MASTERTAC)
            // create master TAC object
            UINT32 playerID = 0;
            GetID(playerID);
            m_pMasterTAC->SetRegistry(m_pRegistry,playerID);
#endif /* HELIX_FEATURE_REGISTRY && HELIX_FEATURE_MASTERTAC*/
        }

        m_pCookies = m_pEngine->GetCookies();
    }
    else
    {
        theErr = HXR_INVALID_PARAMETER;
    }

    if (m_pAudioPlayer && theErr == HXR_OK)
    {
        m_pAudioPlayer->AddRef();

        theErr = m_pAudioPlayer->Init((IUnknown*) (IHXPlayer*)this);
    }

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (m_pNextGroupManager)
    {
        m_pNextGroupManager->Init();
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

    return theErr;
}


/************************************************************************
 *      Method:
 *              IHXPlayer::IsDone
 *      Purpose:
 *              Ask the player if it is done with the current presentation
 *
 */
STDMETHODIMP_ (BOOL) HXPlayer::IsDone(void)
{
    return m_bIsPresentationDone;
}

/************************************************************************
 *      Method:
 *              IHXPlayer::IsLive
 *      Purpose:
 *              Ask the player whether it contains the live source
 *
 */
STDMETHODIMP_ (BOOL) HXPlayer::IsLive(void)
{
    return m_bIsLive;
}

/************************************************************************
 *      Method:
 *              IHXPlayer::GetCurrentPlayTime
 *      Purpose:
 *              Get the current time on the Player timeline
 *
 */
STDMETHODIMP_ (ULONG32) HXPlayer::GetCurrentPlayTime(void)
{
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    theErr = m_pAudioPlayer->GetCurrentPlayBackTime();
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return theErr;
}

/************************************************************************
 *      Method:
 *          IHXPlayer::AddAdviseSink
 *      Purpose:
 *          Call this method to add a client advise sink.
 *
 */
STDMETHODIMP HXPlayer::AddAdviseSink   (IHXClientAdviseSink*  pAdviseSink)
{
#if defined(HELIX_FEATURE_SINKCONTROL)
    if (m_pAdviseSink)
    {
        return m_pAdviseSink->AddAdviseSink(pAdviseSink);
    }
    else
#endif /* HELIX_FEATURE_SINKCONTROL */
    {
        return HXR_NOTIMPL;
    }
}

/************************************************************************
 *      Method:
 *          IHXPlayer::RemoveAdviseSink
 *      Purpose:
 *          Call this method to remove a client advise sink.
 */
STDMETHODIMP HXPlayer::RemoveAdviseSink(IHXClientAdviseSink*  pAdviseSink)
{
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
#if defined(HELIX_FEATURE_SINKCONTROL)
    if (m_pAdviseSink)
    {
        theErr = m_pAdviseSink->RemoveAdviseSink(pAdviseSink);
    }
#endif /* HELIX_FEATURE_SINKCONTROL */
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return theErr;
}

ULONG32 HXPlayer::GetInst(void)
{
#if defined(_WIN32)
    return (ULONG32)GetModuleHandle(NULL);
#elif defined(_WIN16)
    return (ULONG32)g_hInstance;
#else
    return 0;
#endif
}

HX_RESULT
HXPlayer::SetStatsGranularity
(
    ULONG32     ulGranularity
)
{
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    m_ulStatsGranularity = ulGranularity;

    if (m_pUpdateStatsCallback->m_bIsCallbackPending && ALLFS == m_ulStatsGranularity)
    {
        m_pUpdateStatsCallback->m_bIsCallbackPending = FALSE;
        m_pScheduler->Remove(m_pUpdateStatsCallback->m_PendingHandle);
        m_pUpdateStatsCallback->m_PendingHandle = 0;
    }
    else if (!m_pUpdateStatsCallback->m_bIsCallbackPending && ALLFS != m_ulStatsGranularity)
    {
        UpdateStatistics();
    }
    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
}

STDMETHODIMP
HXPlayer::ClosePresentation()
{
    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();

    // This stops the player if it is playing and cleans up the layout.
    StopPlayer(END_STOP);
    CloseAllRenderers(0);

#if defined(HELIX_FEATURE_VIDEO)
    if (m_pSiteSupplier && !m_bBeginChangeLayoutTobeCalled)
    {
        m_bBeginChangeLayoutTobeCalled  = TRUE;
        m_pSiteSupplier->DoneChangeLayout();
    }
#endif /* HELIX_FEATURE_VIDEO */

    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return HXR_OK;
}

STDMETHODIMP
HXPlayer::SetMinimumPreroll(UINT32 ulMinPreroll)
{
    HX_RESULT hr = HXR_OK;

    m_ulMinimumTotalPreroll = ulMinPreroll;

    return hr;
}

STDMETHODIMP
HXPlayer::GetMinimumPreroll(REF(UINT32) ulMinPreroll)
{
    HX_RESULT hr = HXR_OK;

    ulMinPreroll = m_ulMinimumTotalPreroll;

    return hr;
}

HX_RESULT
HXPlayer::UpdateStatistics(void)
{
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    BOOL                bUpdate = FALSE;
    ULONG32             ulPlayerTotal = 0;
    ULONG32             ulPlayerReceived = 0;
    ULONG32             ulPlayerNormal = 0;
    ULONG32             ulPlayerRecovered = 0;
    ULONG32             ulPlayerDuplicate = 0;
    ULONG32             ulPlayerOutOfOrder = 0;
    ULONG32             ulPlayerLost = 0;
    ULONG32             ulPlayerLate = 0;
    UINT32              ulPlayerTotal30 = 0;
    UINT32              ulPlayerLost30 = 0;
    ULONG32             ulPlayerResendRequested = 0;
    ULONG32             ulPlayerResendReceived = 0;

    ULONG32             ulPlayerBandwidth = 0;
    ULONG32             ulPlayerCurBandwidth = 0;
    ULONG32             ulPlayerAvgBandwidth = 0;

    INT32               lAvgLatency = 0;
    INT32               lHighLatency = 0;
    INT32               lLowLatency = 0xFFFF;

    ULONG32             ulStreamNumber = 0;

    SourceInfo*         pSourceInfo = NULL;
    RendererInfo*       pRenderInfo = NULL;
    IHXStatistics*     pStatistics = NULL;
    UINT16              uBufferingMode = 0;

    CHXMapPtrToPtr::Iterator    ndxSource;
    CHXMapLongToObj::Iterator   ndxRend;

    if (!m_bInitialized || m_bPaused)
    {
        goto exit;
    }

    // update statistics
    ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pSourceInfo = (SourceInfo*) (*ndxSource);

        // notify the renderer to update its statistics
        ndxRend = pSourceInfo->m_pRendererMap->Begin();
        for (; ndxRend != pSourceInfo->m_pRendererMap->End(); ++ndxRend)
        {
            pRenderInfo = (RendererInfo*)(*ndxRend);

            if (pRenderInfo->m_pRenderer &&
                HXR_OK == pRenderInfo->m_pRenderer->
                                QueryInterface(IID_IHXStatistics,
                                                (void**)&pStatistics))
            {
                pStatistics->UpdateStatistics();

                pStatistics->Release();
                pStatistics = NULL;
            }
        }

        // update each source
        if (pSourceInfo->m_pSource              &&
            HXR_OK == pSourceInfo->m_pSource->UpdateStatistics())
        {
            ulPlayerTotal           += pSourceInfo->m_pSource->m_pStats->m_pTotal->GetInt();
            ulPlayerReceived        += pSourceInfo->m_pSource->m_pStats->m_pReceived->GetInt();
            ulPlayerNormal          += pSourceInfo->m_pSource->m_pStats->m_pNormal->GetInt();
            ulPlayerRecovered       += pSourceInfo->m_pSource->m_pStats->m_pRecovered->GetInt();
            ulPlayerDuplicate       += pSourceInfo->m_pSource->m_pStats->m_pDuplicate->GetInt();
            ulPlayerOutOfOrder      += pSourceInfo->m_pSource->m_pStats->m_pOutOfOrder->GetInt();
            ulPlayerLost            += pSourceInfo->m_pSource->m_pStats->m_pLost->GetInt();
            ulPlayerLate            += pSourceInfo->m_pSource->m_pStats->m_pLate->GetInt();
            ulPlayerResendRequested += pSourceInfo->m_pSource->m_pStats->m_pResendRequested->GetInt();
            ulPlayerResendReceived  += pSourceInfo->m_pSource->m_pStats->m_pResendReceived->GetInt();

            ulPlayerTotal30         += pSourceInfo->m_pSource->m_pStats->m_pTotal30->GetInt();
            ulPlayerLost30          += pSourceInfo->m_pSource->m_pStats->m_pLost30->GetInt();

            ulPlayerBandwidth       += pSourceInfo->m_pSource->m_pStats->m_pClipBandwidth->GetInt();
            ulPlayerCurBandwidth    += pSourceInfo->m_pSource->m_pStats->m_pCurBandwidth->GetInt();
            ulPlayerAvgBandwidth    += pSourceInfo->m_pSource->m_pStats->m_pAvgBandwidth->GetInt();

            lAvgLatency             += pSourceInfo->m_pSource->m_pStats->m_pAvgLatency->GetInt();

            if (lHighLatency < pSourceInfo->m_pSource->m_pStats->m_pHighLatency->GetInt())
            {
                lHighLatency = pSourceInfo->m_pSource->m_pStats->m_pHighLatency->GetInt();
            }

            if (lLowLatency > pSourceInfo->m_pSource->m_pStats->m_pLowLatency->GetInt())
            {
                lLowLatency = pSourceInfo->m_pSource->m_pStats->m_pLowLatency->GetInt();
            }

            if (uBufferingMode < (UINT16) pSourceInfo->m_pSource->m_pStats->m_pBufferingMode->GetInt())
            {
                uBufferingMode = (UINT16) pSourceInfo->m_pSource->m_pStats->m_pBufferingMode->GetInt();
            }

            if (pSourceInfo->m_pSource->m_pStatsManager)
            {
                pSourceInfo->m_pSource->m_pStatsManager->Copy();
            }
        }
    }

    bUpdate = SetIntIfNecessary(m_pStats->m_pTotal, (INT32)ulPlayerTotal);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pReceived, (INT32)ulPlayerReceived);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pNormal, (INT32)ulPlayerNormal);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pRecovered, (INT32)ulPlayerRecovered);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pDuplicate, (INT32)ulPlayerDuplicate);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pOutOfOrder, (INT32)ulPlayerOutOfOrder);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pLost, (INT32)ulPlayerLost);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pLate, (INT32)ulPlayerLate);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pTotal30, (INT32)ulPlayerTotal30);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pLost30, (INT32)ulPlayerLost30);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pResendRequested, (INT32)ulPlayerResendRequested);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pResendReceived, (INT32)ulPlayerResendReceived);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pClipBandwidth, (INT32)ulPlayerBandwidth);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pCurBandwidth, (INT32)ulPlayerCurBandwidth);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pAvgBandwidth, (INT32)ulPlayerAvgBandwidth);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pAvgLatency, (INT32)lAvgLatency);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pHighLatency, (INT32)lHighLatency);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pLowLatency, (INT32)lLowLatency);
    bUpdate |= SetIntIfNecessary(m_pStats->m_pBufferingMode, (INT32)uBufferingMode);

    if (bUpdate || m_bForceStatsUpdate)
    {
        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnStatisticsChanged();
        }

        m_bForceStatsUpdate = FALSE;
    }

exit:
    if (!m_pUpdateStatsCallback->m_bIsCallbackPending && ALLFS != m_ulStatsGranularity)
    {
        m_pUpdateStatsCallback->m_bIsCallbackPending  = TRUE;
        m_pUpdateStatsCallback->m_PendingHandle = m_pScheduler->RelativeEnter(m_pUpdateStatsCallback,
                                                                m_ulStatsGranularity);
    }
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    return HXR_OK;
}


HX_RESULT
HXPlayer::SetupAudioPlayer()
{
    HX_RESULT theErr = HXR_OK;

    HX_ASSERT(m_bInitialized);

#if defined(THREADS_SUPPORTED) && !defined(_MAC_UNIX)
    if (m_bUseCoreThread && !m_pEngine->AtInterruptTime())
    {
        HX_ASSERT(m_pSetupCallback->GetPendingCallback() == 0);
        if (!m_pSetupCallback->GetPendingCallback())
        {
            m_pSetupCallback->CallbackScheduled(
            m_pScheduler->RelativeEnter(m_pSetupCallback, 0));
        }

        return HXR_OK;
    }
#endif /*_WIN32*/

    m_bSetupToBeDone = FALSE;

    PrepareAudioPlayer();

#if defined(THREADS_SUPPORTED) && !defined(_MAC_UNIX)
    if (m_bUseCoreThread && m_pEngine->AtInterruptTime())
    {
        m_pAudioPlayer->UseCoreThread();
    }
#endif
    theErr = m_pAudioPlayer->Setup(m_ulLowestGranularity);

    if (theErr)
    {
        SetLastError(theErr);
    }

    if (!theErr)
    {
        m_bPostSetupToBeDone = TRUE;
    }

    return theErr;
}

HX_RESULT
HXPlayer::PrepareAudioPlayer()
{
    return HXR_OK;
}

HX_RESULT HXPlayer::ProcessIdle(void)
{
    if ((!m_bInitialized || m_bPostSetupToBeDone ) && m_pEngine->AtInterruptTime())
    {
        return HXR_OK;
    }

    if (m_bCoreLocked)
    {
        SchedulePlayer();
        return HXR_OK;
    }

    m_pCoreMutex->Lock();

#if 0
#if defined(_WIN32) && defined(_DEBUG)
    GetChangesToWorkingSet();
#endif
#endif

    m_bCoreLocked   = TRUE;

    HX_RESULT           theErr              = HXR_OK;
    BOOL                bIsBuffering        = FALSE;
    UINT16              uLowestBuffering    = 100;

    SourceInfo*         pSourceInfo         = NULL;
    RendererInfo*       pRendInfo           = NULL;
    IHXRenderer*        pRenderer           = NULL;
    BOOL                bDone               = FALSE;
    BOOL                bIsFirst            = TRUE;
    BOOL                bReadyToUpgrade     = TRUE;
    BOOL                bSuppressErrorReporting = FALSE;
    UINT32              ulNumStreamsToBeFilled = 0;
    UINT32              ulLoopEntryTime     = 0;
    UINT16              unStatusCode        = 0;
    UINT16              unPercentDone       = 0;
    IHXBuffer*          pStatusDesc         = NULL;

    CHXMapPtrToPtr::Iterator    ndxSource;
    CHXMapLongToObj::Iterator   ndxRend;

    if (m_bIsDone || m_bSetupToBeDone)
    {
        goto exitRoutine;
    }

#ifdef _MACINTOSH
    /* check InternalPause() for details */
        if (m_bPendingAudioPause && !m_pEngine->AtInterruptTime())
        {
            m_pAudioPlayer->Pause();
        }
#endif

    ndxSource = m_pSourceMap->Begin();

    for (;!theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pSourceInfo     = (SourceInfo*)(*ndxSource);

        /* Do not call Process source at interrupt time unless
         * it is initialized.
         */
        if (pSourceInfo->m_pSource &&
            (pSourceInfo->m_pSource->IsInitialized() ||
            !m_pEngine->AtInterruptTime()))
        {
            // XXX HP may need to rework
            if (!pSourceInfo->m_bDone)
            {
                theErr = pSourceInfo->m_pSource->ProcessIdle();
                if( theErr == HXR_OUTOFMEMORY )
                {
                    goto exitRoutine;
                }
            }

            theErr = SpawnSourceIfNeeded(pSourceInfo);
            if( theErr == HXR_OUTOFMEMORY )
            {
                goto exitRoutine;
            }
            else
            {
                theErr = HXR_OK; // filter out HXR_NOTIMPL
            }
        }

        if (pSourceInfo->m_pPeerSourceInfo                      &&
            pSourceInfo->m_pPeerSourceInfo->m_pSource           &&
            !pSourceInfo->m_pPeerSourceInfo->m_bDone            &&
            (pSourceInfo->m_pPeerSourceInfo->m_pSource->IsInitialized() ||
            !m_pEngine->AtInterruptTime()))
        {
            theErr = pSourceInfo->m_pPeerSourceInfo->m_pSource->ProcessIdle();
            if( theErr == HXR_OUTOFMEMORY )
            {
                goto exitRoutine;
            }
        }
    }

#if defined(HELIX_FEATURE_PREFETCH)
    if (m_pPrefetchManager &&
        m_pPrefetchManager->GetNumSources() > 0)
    {
        m_pPrefetchManager->ProcessIdle();
    }
#endif /* HELIX_FEATURE_PREFETCH */

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (m_pNextGroupManager->GetNumSources() > 0)
    {
        m_pNextGroupManager->ProcessIdle();
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

    // check the status first
    if (!m_bContactingDone &&
        HXR_OK == GetStatus(unStatusCode, pStatusDesc, unPercentDone))
    {
        if (HX_STATUS_CONTACTING == unStatusCode && pStatusDesc && m_pAdviseSink)
        {
            m_pAdviseSink->OnContacting((const char*)pStatusDesc->GetBuffer());
        }
        else if (HX_STATUS_INITIALIZING != unStatusCode)
        {
            m_bContactingDone = TRUE;
        }
        HX_RELEASE(pStatusDesc);
    }

    // initialize renderes if not done yet..
    // this involves reading headers from source object
    // creating the right renderers for each stream and pass this
    // header to the renderer.
    if (!m_bInitialized)
    {
        /* A temporary hack till we change SMIL fileformat
         * to send Layout info in Header
         */
        BOOL    bIsSmilRenderer = m_bSetupLayoutSiteGroup;

        theErr = InitializeRenderers();

#if defined(HELIX_FEATURE_VIDEO)
        if (!theErr && m_bInitialized && !m_bPlayerWithoutSources)
        {
            SetupLayout(/*!m_bSetupLayoutSiteGroup*/ FALSE);
            if (bIsSmilRenderer == m_bSetupLayoutSiteGroup &&
                m_pSiteSupplier && !m_bBeginChangeLayoutTobeCalled)
            {
                m_bBeginChangeLayoutTobeCalled  = TRUE;
                m_pSiteSupplier->DoneChangeLayout();
            }
        }
#endif /* HELIX_FEATURE_VIDEO */

        if (!theErr && m_bInitialized)
        {
            AdjustPresentationTime();

            m_bSetupToBeDone = TRUE;

            theErr = SetupAudioPlayer();
        }
    }

    if (m_bPostSetupToBeDone)
    {
        m_bPostSetupToBeDone = FALSE;
        /* Initialize audio services */
        if (!theErr && m_bInitialized)
        {
            m_bIsPresentationClosedToBeSent = TRUE;
            if (m_pAdviseSink)
            {
                m_pAdviseSink->OnPresentationOpened();
            }
        }

        if (!theErr && m_bInitialized)
        {
            m_ulMinimumAudioPreroll = m_pAudioPlayer->GetInitialPushdown();
            SetMinimumPushdown();
        }

        if (!theErr && m_bInitialized && !m_bIsFirstBegin)
        {
            CheckSourceRegistration();

            ndxSource = m_pSourceMap->Begin();
            for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
            {
                SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSource);
                HXSource* pSource = pSourceInfo->m_pSource;
                
                if (pSource)
                {
                    theErr = pSource->DoResume();
                }
                else
                {
                    /* pSource should never be NULL */
                    HX_ASSERT(FALSE);
                }
            }
        }

        /* Start Downloading even if we have not been issued a
         * Begin() command
         */
        if (!theErr && m_bInitialized && m_bIsFirstBegin && !m_bIsDone)
        {
            theErr = StartDownload();
        }
    }

    // if it is still not initialized check error code and return
    if (theErr || !m_bInitialized)
    {
        // my first use of goto..!!
        goto exitRoutine;
    }

    /* try to fill up packets from the various source objects for
     * different streams so that all of them are upto their preroll
     * mark...
     */

    UpdateCurrentPlayTime( m_pAudioPlayer->GetCurrentPlayBackTime() );

    if (!m_ToBeginRendererList.IsEmpty())
    {
        CheckBeginList();
    }

    while (!theErr && !bDone && m_uNumSourcesActive > 0)
    {
        ndxSource = m_pSourceMap->Begin();
        for (;!theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
        {
            pSourceInfo = (SourceInfo*)(*ndxSource);

            theErr = pSourceInfo->ProcessIdle(bIsFirst, ulNumStreamsToBeFilled,
                                       bIsBuffering, uLowestBuffering);

            if (pSourceInfo->m_pPeerSourceInfo)
            {
                BOOL    tmp_bIsFirst = TRUE;
                BOOL    tmp_bIsBuffering = FALSE;
                UINT32  tmp_ulNumStreamsToBeFilled = 0;
                UINT16  tmp_uLowestBuffering = 100;

                pSourceInfo->m_pPeerSourceInfo->ProcessIdle(tmp_bIsFirst, tmp_ulNumStreamsToBeFilled,
                                                            tmp_bIsBuffering, tmp_uLowestBuffering);
            }

            /* Someone added a source during ProcessIdle.
             * Start all over again
             */
            if (m_bSourceMapUpdated)
            {
                break;
            }
        }

        if (bIsBuffering && !m_bIsPlaying)
        {
            if (!ulLoopEntryTime)
            {
                ulLoopEntryTime = HX_GET_TICKCOUNT();
            }

            ndxSource = m_pSourceMap->Begin();
            for (;!theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
            {
            pSourceInfo = (SourceInfo*)(*ndxSource);

            ndxRend = pSourceInfo->m_pRendererMap->Begin();

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

                if((pRendInfo->m_bInterruptSafe || !m_pEngine->AtInterruptTime())
                   && pRenderer)
                {
                    pRenderer->OnBuffering(m_BufferingReason, uLowestBuffering);
                }
            }
            }

            m_b100BufferingToBeSent = TRUE;
            if (m_pAdviseSink)
            {
                m_pAdviseSink->OnBuffering(m_BufferingReason, uLowestBuffering);
            }

            // free some CPU time if we stuck in this WHILE loop too long
            if (!theErr &&
                CALCULATE_ELAPSED_TICKS(ulLoopEntryTime, HX_GET_TICKCOUNT()) >= MAX_LOOP_EXE_TIME)
            {
                break;
            }

            if (!theErr)
            {
                theErr = ProcessCurrentEvents();
            }
        }

        if (theErr || m_bSourceMapUpdated)
        {
            m_bSourceMapUpdated = FALSE;
            goto exitRoutine;
        }

        bIsFirst = FALSE;

        if (ulNumStreamsToBeFilled == 0)
        {
            bDone = TRUE;
        }
    }

    // SPECIAL CASE:
    // the player received all the packets(m_uNumSourcesActive is 0) and
    // EndOfPacket() hasn't been sent to the renderer yet,
    // BUT the renderer still calls ReportRebufferStatus()
    // we need to make sure the rebuffering is done before calling resume.
    if (m_uNumSourcesActive == 0)
    {
        ndxSource = m_pSourceMap->Begin();
        for (;!theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
        {
            pSourceInfo = (SourceInfo*)(*ndxSource);

            if (!pSourceInfo->IsRebufferDone())
            {
                bIsBuffering = TRUE;
                break;
            }
        }
    }

    /* Stop Downloading if we have not been issued a
     * Begin() command and we are done with Buffering.
     */
    if (!theErr && !bIsBuffering && m_bFastStartInProgress && !m_bIsDone)
    {
        theErr = PauseDownload();
    }

    // Process Current Events Due...
    if (!theErr)
    {
        theErr = ProcessCurrentEvents();
    }

    // repeat source specific
    SwitchSourceIfNeeded();

    if (!theErr && !bIsBuffering &&
        (!m_bResumeOnlyAtSystemTime || !m_pEngine->AtInterruptTime()))
    {
        theErr = CheckForAudioResume();
    }

    if (!theErr && !m_bLastGroup && !m_bNextGroupStarted && !m_pEngine->AtInterruptTime())
    {
        CheckToStartNextGroup();
    }

    /* Check if live stream has ended */
    if (!theErr && m_bInitialized && !m_bPlayerWithoutSources &&
        ((!m_bIsLive && (!m_ulPresentationDuration ||
        (m_ulPresentationDuration < m_ulCurrentPlayTime))) ||
        (m_bIsLive && AreAllPacketsSent())) &&
        m_uNumSourcesActive == 0)
    {
        /* If there are any sources that MUST be initialized before playback
         * begins/stops, we should not end the presentation here. Instead, wait for
         * the stream headers to come down...
         */
        if ((m_uNumSourceToBeInitializedBeforeBegin > 0) &&
            m_ulPresentationDuration)
        {
            InternalPause();
        }
        else if (!m_ulPresentationDuration ||
                 (m_ulPresentationDuration < m_ulCurrentPlayTime))
        {
            if (ScheduleOnTimeSync())
            {
                // schedule a system callback to ensure
                // the renderers receive OnTimeSync() on its duration
                // AND the clip ends ASAP
                RemovePendingCallback(m_pHXPlayerCallback);
                m_pHXPlayerCallback->CallbackScheduled(
                        m_pScheduler->RelativeEnter(m_pHXPlayerCallback, 0));

                goto cleanup;
            }
            else
            {
                m_bIsDone = TRUE;

                m_pAudioPlayer->DonePlayback();

                /* This assert is to find bugs in fileformats which place invalid ts
                 * (ts > m_ulPresentationDuration) on the packets.
                 */
                HX_ASSERT(AreAllPacketsSent() == TRUE);
            }
        }
    }

exitRoutine:

#if defined(HELIX_FEATURE_AUTOUPGRADE)
    if(m_pUpgradeCollection && m_pUpgradeCollection->GetCount() > 0 && !m_pEngine->AtInterruptTime())
    {
        // Request an upgrade
        IHXUpgradeHandler* pUpgradeHandler = NULL;
        if(m_pClient)
            m_pClient->QueryInterface(IID_IHXUpgradeHandler, (void**)&pUpgradeHandler);
        if(!pUpgradeHandler)
        {
            // In case of clients with no IHXUpgradeHandler support
            // just remove all the upgrade collectopn components
            m_pUpgradeCollection->RemoveAll();
        theErr = HXR_MISSING_COMPONENTS;
        }
        else
        {
            // see if we should send an upgrade request only if all the sources
            // have been initialized...
            ndxSource = m_pSourceMap->Begin();
            for (;ndxSource != m_pSourceMap->End(); ++ndxSource)
            {
                pSourceInfo = (SourceInfo*)(*ndxSource);
                if (!pSourceInfo->m_bLoadPluginAttempted &&
                    pSourceInfo->m_pSource &&
                    pSourceInfo->m_pSource->GetLastError() == HXR_OK)
                {
                    bReadyToUpgrade = FALSE;
                    break;
                }
            }

            if (bReadyToUpgrade)
            {
                // Request an upgrade
                IHXUpgradeHandler* pUpgradeHandler = NULL;
                if(m_pClient)
                    m_pClient->QueryInterface(IID_IHXUpgradeHandler, (void**)&pUpgradeHandler);
                if(pUpgradeHandler)
                {
                    HX_RESULT hr = HXR_MISSING_COMPONENTS;
                    m_bIsPresentationClosedToBeSent = TRUE;

                    HX_RESULT nUpgradeResult = pUpgradeHandler->RequestUpgrade(m_pUpgradeCollection, FALSE);
                    if(nUpgradeResult == HXR_OK || nUpgradeResult == HXR_CANCELLED)
                    {
                        // We want to stop playback but we dont want error
                        // to be reported untill upgrade tries to fix situation.
                        hr = HXR_OK;
                        bSuppressErrorReporting = TRUE;
                    }

                    m_bIsDone = TRUE;
                    m_pAudioPlayer->DonePlayback();
                    m_LastError = hr;
                }

                HX_RELEASE(pUpgradeHandler);
                m_pUpgradeCollection->RemoveAll();
            }
            else
            {
                /* We are not done yet... Wait till all the sources have been
                 * attempted to load required plugins
                 */
                m_bIsDone = FALSE;
            }
        }
    }
#endif /* HELIX_FEATURE_AUTOUPGRADE */

    if (!theErr && m_pAltURLs && m_pAltURLs->GetCount() && !m_pEngine->AtInterruptTime())
    {
        theErr = DoAltURL();
    }

    if (!theErr && m_pRedirectList && m_pRedirectList->GetCount() && !m_pEngine->AtInterruptTime())
    {
        theErr = DoRedirect();
    }

    if (!theErr && m_bIsDone && !m_bTimeSyncLocked && !m_pEngine->AtInterruptTime())
    {
        if (m_LastError != HXR_OK)
        {
            m_bIsDone = FALSE;
            PausePlayer(FALSE);
            m_bIsDone = TRUE;
            ActualReport(m_LastSeverity, m_LastError,
                   m_ulLastUserCode, m_pLastUserString, m_pLastMoreInfoURL);
            ResetError();
        }

        PlayNextGroup();
    }

    if (!theErr)
    {
        ProcessIdleExt();
    }

    SchedulePlayer();

    /* this error is crucial...need to be reported upto ragui...*/
    if (theErr && !bSuppressErrorReporting)
    {
        SetLastError(theErr);
    }

cleanup:

    m_bCoreLocked   = FALSE;
    m_pCoreMutex->Unlock();

    return theErr;
}

HX_RESULT
HXPlayer::ProcessIdleExt(void)
{
    return HXR_OK;
}

HX_RESULT
HXPlayer::DoAltURL(void)
{
#if defined(HELIX_FEATURE_ALT_URL)
    HX_RESULT           hr                  = HXR_OK;
    BOOL                bDefault            = FALSE;
    char*               pAltURL             = NULL;
    SourceInfo*         pMainSourceInfo     = NULL;
    HXSource*          pSource             = NULL;

    ResetError();

    while (!hr && m_pAltURLs->GetCount())
    {
        pMainSourceInfo = (SourceInfo*) m_pAltURLs->RemoveHead();

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
        if (pMainSourceInfo->m_pSource->IsPartOfNextGroup())
        {
            m_pNextGroupManager->RemoveSource(pMainSourceInfo);
            m_bPartOfNextGroup = TRUE;
        }
        else
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
#if defined(HELIX_FEATURE_PREFETCH)
        if (pMainSourceInfo->m_pSource->IsPartOfPrefetchGroup())
        {
            m_pPrefetchManager->RemoveSource(pMainSourceInfo);
        }
        else
#endif /* HELIX_FEATURE_PREFETCH */
        {
            m_pSourceMap->RemoveKey(pMainSourceInfo->m_pSource);
            m_bSourceMapUpdated = TRUE;
        }

        if (pMainSourceInfo->m_bTobeInitializedBeforeBegin &&
            m_uNumSourceToBeInitializedBeforeBegin > 0)
        {
            m_uNumSourceToBeInitializedBeforeBegin--;
        }

        pAltURL = pMainSourceInfo->m_pSource->GetAltURL(bDefault);

        HX_ASSERT(pAltURL);

        pMainSourceInfo->Stop();
#if defined(HELIX_FEATURE_NESTEDMETA)
        HXPersistentComponent* pRootPersistentComponent = m_pPersistentComponentManager->m_pRootPersistentComponent;
        // only cleanup the layout if
        // * it's not a SMIL presentation OR
        // * the AltURL is on the root SMIL presentation itself
        // in other words
        // * don't cleanup the layout if the AltURL is on the tracks
        // * within the SMIL presentation
        UINT32                 ulPCID = pMainSourceInfo->m_ulPersistentComponentID;
        HXPersistentComponent* pPersistentComponent = NULL;
        PersistentType         SourceType = PersistentUnknown;
        
        m_pPersistentComponentManager->GetPersistentComponent(ulPCID,
                                                              (IHXPersistentComponent*&)pPersistentComponent
                                                              );
        if( pPersistentComponent )
            SourceType = (PersistentType)pPersistentComponent->m_ulPersistentType;
        
        HX_RELEASE(pPersistentComponent);
        
        if( !pRootPersistentComponent  ||
            SourceType != PersistentSMIL ||
            pRootPersistentComponent->m_pSourceInfo == pMainSourceInfo)
        {
            CleanupLayout();
            if (pRootPersistentComponent)
            {
                pRootPersistentComponent->m_bCleanupLayoutCalled = TRUE;
            }
        }
#endif /* HELIX_FEATURE_NESTEDMETA */
        pMainSourceInfo->CloseRenderers();

        if (pAltURL)
        {
            hr = DoAltURLOpen(pAltURL, bDefault, pMainSourceInfo);
        }

        m_bPartOfNextGroup = FALSE;

        HX_VECTOR_DELETE(pAltURL);
        HX_DELETE(pMainSourceInfo);
    }

    return hr;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_ALT_URL */
}

HX_RESULT
HXPlayer::DoRedirect(void)
{
    HX_RESULT               hr                          = HXR_OK;
    BOOL                    bNoRedirectSupport          = FALSE;
    BOOL                    bBegin                      = m_bUserHasCalledBegin;
    BOOL                    bRAMOnly                    = TRUE;
    SourceInfo*             pSourceInfo                 = NULL;
    RedirectInfo*           pRedirectInfo               = NULL;
    IHXValues*              pRequestHeaders             = NULL;
    HXPersistentComponent*  pRootPersistentComponent    = NULL;
    HXPersistentComponent*  pPersistentComponent        = NULL;

    m_bDoRedirect = TRUE;

    pRedirectInfo = (RedirectInfo*) m_pRedirectList->RemoveHead();

#if defined(HELIX_FEATURE_NESTEDMETA)
    pRootPersistentComponent = m_pPersistentComponentManager->m_pRootPersistentComponent;
    if (pRootPersistentComponent)
    {
        // no redirect support by default
        bNoRedirectSupport = TRUE;

        // except the live source within a RAM
        GetSourceInfo(pRedirectInfo->m_nGroupID, pRedirectInfo->m_nTrackID, pSourceInfo);
        if (pSourceInfo)
        {
            m_pPersistentComponentManager->GetPersistentComponent(pSourceInfo->m_ulPersistentComponentID,
                                                                 (IHXPersistentComponent*&)pPersistentComponent);

            // allow redirect on the root persistent component(i.e. SMIL/RAM)
            if (pPersistentComponent == pRootPersistentComponent)
            {
                bNoRedirectSupport = FALSE;
            }
            else
            {
                while (pPersistentComponent != pRootPersistentComponent)
                {
                    if (PersistentSMIL == pPersistentComponent->m_ulPersistentType)
                    {
                        bRAMOnly = FALSE;
                        break;
                    }
                    pPersistentComponent = pPersistentComponent->m_pPersistentParent;
                }

                if (pRootPersistentComponent->m_ulPersistentType == PersistentRAM   &&
                    bRAMOnly                                                        &&
                    pSourceInfo->m_pSource)
                {
                    bNoRedirectSupport = FALSE;
                }
            }
            HX_RELEASE(pPersistentComponent);
        }
        else
        {
            HX_ASSERT(FALSE);
        }
    }
#endif /* HELIX_FEATURE_NESTEDMETA */

    // no Redirect support for SMIL presentation for now
    // return HXR_SERVER_DISCONNECTED instead
    if (bNoRedirectSupport)
    {
        Report(HXLOG_ERR, HXR_SERVER_DISCONNECTED, HXR_OK, NULL, NULL);
        goto cleanup;
    }

    if (m_pRequest)
        m_pRequest->GetRequestHeaders(pRequestHeaders);

    // Set the redirecting property to true before calling stop so the TLC can tell if a redirect is going to occur
    if (pRequestHeaders)
        pRequestHeaders->SetPropertyULONG32("IsRedirecting", TRUE);

    StopPlayer(END_REDIRECT);
    CloseAllRenderers(m_nCurrentGroup);

    // Set the redirecting property to false before opening the new URL.
    if (pRequestHeaders)
    {
        pRequestHeaders->SetPropertyULONG32("IsRedirecting", FALSE);
        HX_RELEASE(pRequestHeaders);
    }

    hr = OpenRedirect(pRedirectInfo->m_pURL);

    if (hr == HXR_OK && bBegin)
    {
        Begin();
    }

cleanup:

    HX_DELETE(pRedirectInfo);

    m_bDoRedirect = FALSE;

    return hr;
}

HX_RESULT
HXPlayer::OpenRedirect(const char* pszURL)
{
    HX_RESULT   hr = HXR_OK;

    // we want to protect against the TLC opening another URL
    if (m_bSetModal)
    {
        return HXR_OK;
    }

    HX_RELEASE(m_pRequest);

    // get the compresses URL
    CHXURL url(pszURL);

    m_pRequest = new CHXRequest();
    if( m_pRequest )
    {
        m_pRequest->AddRef();

        m_pRequest->SetURL(url.GetURL());
        m_bActiveRequest = TRUE;

        hr = DoURLOpen(&url, NULL);
    }
    else
    {
        hr = HXR_OUTOFMEMORY;
    }

    return hr;
}

HX_RESULT
HXPlayer::StartDownload()
{
    HX_RESULT                   theErr = HXR_OK;
    CHXMapPtrToPtr::Iterator    ndxSource;

    if (!m_bIsDone)
    {
        CheckSourceRegistration();

        ndxSource = m_pSourceMap->Begin();

        /* Check if we are done. This may be TRUE for empty files */
        for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
        {
            SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSource);
            HXSource* pSource = pSourceInfo->m_pSource;
            
            if(pSource && pSource->CanBeResumed())
            {
                theErr = pSource->StartInitialization();
            }
        }
    }

    m_bFastStartInProgress  = TRUE;
    m_bFSBufferingEnd       = FALSE;

    return theErr;
}

HX_RESULT
HXPlayer::PauseDownload(void)
{
    HX_RESULT                   theErr = HXR_OK;
    CHXMapPtrToPtr::Iterator    ndxSource;

    if (!m_bFSBufferingEnd)
    {
        m_bFSBufferingEnd       = TRUE;
        m_ulFSBufferingEndTime  = HX_GET_TICKCOUNT();

        /* In network case, we want to buffer extra 2-3 seconds worth
         * of data. We renter this function over and over again in the
         * else clause and ultimately send 100% buffering message.
         * In local playback however, we want to send this message
         * right away. So do not return the function from here, instead fall
         * down below to return 100% buffering message instantly
         */
        if (!m_bAllLocalSources)
        {
            return HXR_OK;
        }
    }
    else
    {
        /* Buffer extra 3 seconds worth of data before pausing */
        if (CALCULATE_ELAPSED_TICKS(m_ulFSBufferingEndTime, HX_GET_TICKCOUNT())
            < 3000)
        {
            return HXR_OK;
        }
    }

    m_bFastStartInProgress  = FALSE;

    ndxSource = m_pSourceMap->Begin();

    /* Check if we are done. This may be TRUE for empty files */
    for (; !theErr && !m_bIsDone && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSource);

        HXSource* pSource = pSourceInfo->m_pSource;

        /* Do not pause a live source */
        if(!pSource || pSource->IsLive())
        {
            continue;
        }

        theErr = pSource->DoPause();
    }

    if (m_b100BufferingToBeSent)
    {
        m_b100BufferingToBeSent = FALSE;
        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnBuffering(m_BufferingReason, 100);
        }
    }

    return theErr;
}

void
HXPlayer::SchedulePlayer(void)
{
    if ((!m_bIsDone || m_LastError || m_pEngine->AtInterruptTime()) &&
        !m_pHXPlayerCallback->GetPendingCallback())
    {
        m_pHXPlayerCallback->CallbackScheduled(
            m_pScheduler->RelativeEnter(m_pHXPlayerCallback, 300));
    }

    if ((!m_bIsDone || m_LastError) &&
        !m_pHXPlayerInterruptCallback->GetPendingCallback())
    {
        m_pHXPlayerInterruptCallback->CallbackScheduled(
            m_pScheduler->RelativeEnter(m_pHXPlayerInterruptCallback, 100));
    }

}

HX_RESULT
HXPlayer::CheckForAudioResume(void)
{
    HX_RESULT theErr = HXR_OK;

    if (m_bInitialized && !m_bSetupToBeDone && !m_bPaused &&
        (m_bBeginPending || m_bTimelineToBeResumed) &&
        m_uNumSourceToBeInitializedBeforeBegin == 0)
    {
        if (m_b100BufferingToBeSent)
        {
            m_b100BufferingToBeSent = FALSE;
            if (m_pAdviseSink)
            {
                m_pAdviseSink->OnBuffering(m_BufferingReason, 100);
            }
        }

        /*
         * change the state of buffering since we have crossed
         * initial startup state...
         * BUFFERING_SEEK and BUFFERING_LIVE_PAUSE are handled in OnTimeSync
         */
        if (m_BufferingReason == BUFFERING_START_UP)
        {
            m_BufferingReason = BUFFERING_CONGESTION;
        }

        /* did someone pause/stop the player within 100% OnBuffering call?
         * if so, do not resume the timeline yet.
         */
        if (m_bPaused || !m_bInitialized)
        {
            return HXR_OK;
        }

        m_bIsPlaying            = TRUE;
        m_bBeginPending         = FALSE;
        m_bTimelineToBeResumed  = FALSE;
        m_bPendingAudioPause    = FALSE;

        DEBUG_OUT(this, DOL_TRANSPORT, (s,"Audio Resumed"));

        theErr = m_pAudioPlayer->Resume();
    }

    return theErr;
}

void HXPlayer::SetMinimumPushdown()
{
    UINT32 ulMinimumStartingPreroll = m_ulMinimumAudioPreroll;

#ifndef HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
    // This is removed for HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES
    // (MIN_HEAP) builds because this code will return a shorter
    // preroll value than is required for proper playback. This will cause
    // rebuffers with renderers that are driven by OnDryNotification()
    // because the core will not provide the renderer with packets early
    // enough. By removing this call the core will use the proper preroll
    // value and packets will be provided to the renderer in time to
    // satisfy all OnDryNotification() calls
    if (m_pAudioPlayer)
    {
        ulMinimumStartingPreroll = m_pAudioPlayer->GetInitialPushdown(TRUE);
    }
#endif /* HELIX_CONFIG_MIN_PCM_PUSHDOWN_BYTES */

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (;  ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);

        HXSource* pSource = pSourceInfo->m_pSource;

        pSource->SetMinimumPreroll(m_ulMinimumAudioPreroll, ulMinimumStartingPreroll);
    }
}

void
HXPlayer::ResetError(void)
{
    m_LastSeverity      = HXLOG_ERR;
    m_LastError         = HXR_OK;
    m_ulLastUserCode    = HXR_OK;

    HX_VECTOR_DELETE(m_pLastUserString);
    HX_VECTOR_DELETE(m_pLastMoreInfoURL);
}

void
HXPlayer::SetLastError(HX_RESULT theErr)
{
    if (theErr && !m_LastError)
    {
        m_LastError = theErr;
        m_bIsDone   = TRUE;
        m_pAudioPlayer->DonePlayback();
    }

    // Handle OOM errors as special case: we do not want to continue playback
    // any longer.
    // Add SLOW_MACHINE to the "Abort Now" category.
    if( theErr == HXR_OUTOFMEMORY || theErr == HXR_SLOW_MACHINE )
    {
        // ActualReport does not get called next time in ProcessIdle because
        // we Abort playback here, so have to call it manually.
        ActualReport(m_LastSeverity, m_LastError,
                     m_ulLastUserCode, m_pLastUserString, m_pLastMoreInfoURL);
        AbortPlayer();
    }
}

void
HXPlayer::ResetRedirectList(void)
{
    RedirectInfo*   pRedirectInfo = NULL;

    if (m_pRedirectList)
    {
        CHXSimpleList::Iterator  i = m_pRedirectList->Begin();

        for (; i != m_pRedirectList->End(); ++i)
        {
            pRedirectInfo = (RedirectInfo*) (*i);

            HX_DELETE(pRedirectInfo);
        }

        m_pRedirectList->RemoveAll();
    }
}

HX_RESULT
HXPlayer::HandleRedirectRequest(UINT16 nGroup, UINT16 nTrack, char* pURL)
{
    HX_RESULT       theErr = HXR_OK;
    RedirectInfo*   pRedirectInfo = NULL;

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

        if (!m_pRedirectList)
        {
            theErr = HXR_OUTOFMEMORY;
            goto cleanup;
        }
    }

    pRedirectInfo = new RedirectInfo;

    pRedirectInfo->m_pURL = new char[strlen(pURL)+1];
    strcpy(pRedirectInfo->m_pURL, pURL); /* Flawfinder: ignore */

    pRedirectInfo->m_nGroupID = nGroup;
    pRedirectInfo->m_nTrackID = nTrack;

    m_pRedirectList->AddTail(pRedirectInfo);

cleanup:

    return theErr;
}

BOOL
HXPlayer::IsAtSourceMap(SourceInfo* pSourceInfo)
{
    SourceInfo* pResult = NULL;

    return m_pSourceMap->Lookup(pSourceInfo->m_pSource, (void*&)pResult);
}

/*
* IHXErrorMessages methods
*/

STDMETHODIMP
HXPlayer::Report
(
    const UINT8 unSeverity,
    HX_RESULT   ulHXCode,
    const ULONG32       ulUserCode,
    const char* pUserString,
    const char* pMoreInfoURL
)
{
    /* Always pass through info and debug messages.
     * We use these severity levels for logging purposes and
     * do not consider them as errors
     */
    if (unSeverity == HXLOG_INFO    ||
        unSeverity == HXLOG_DEBUG   ||
        ulHXCode  == HXR_OK)
    {
        return ActualReport(unSeverity, ulHXCode, ulUserCode,
                            pUserString, pMoreInfoURL);
    }

    /* Do not override an error if it is already set.
     */
    if (m_LastError != HXR_OK)
    {
        m_bIsDone = TRUE;
        return HXR_OK;
    }

    m_LastSeverity      = unSeverity;
    m_ulLastUserCode    = ulUserCode;
    SetLastError(ulHXCode);

    if (pUserString != m_pLastUserString)
    {
        HX_VECTOR_DELETE(m_pLastUserString);

        if (pUserString && *pUserString)
        {
            m_pLastUserString = new char[strlen(pUserString) + 1];
            ::strcpy(m_pLastUserString, pUserString); /* Flawfinder: ignore */
        }
    }


    if (pMoreInfoURL != m_pLastMoreInfoURL)
    {
        HX_VECTOR_DELETE(m_pLastMoreInfoURL);

        if (pMoreInfoURL && *pMoreInfoURL)
        {
            m_pLastMoreInfoURL = new char[strlen(pMoreInfoURL) + 1];
            ::strcpy(m_pLastMoreInfoURL, pMoreInfoURL); /* Flawfinder: ignore */
        }
    }

    m_bIsDone                   = TRUE;
    m_bIsPresentationClosedToBeSent = TRUE;
    m_pAudioPlayer->DonePlayback();
    return HXR_OK;
}

HX_RESULT
HXPlayer::ActualReport
(
    const UINT8 unSeverity,
    HX_RESULT   ulHXCode,
    const ULONG32       ulUserCode,
    const char* pUserString,
    const char* pMoreInfoURL
)
{
#if defined(HELIX_FEATURE_SINKCONTROL)
    if (m_pErrorSinkControl)
    {
        m_pErrorSinkControl->ErrorOccurred(unSeverity, ulHXCode,
                                           ulUserCode, pUserString,
                                           pMoreInfoURL);
    }
#endif /* HELIX_FEATURE_SINKCONTROL */

    return HXR_OK;
}

STDMETHODIMP_ (IHXBuffer*)
HXPlayer::GetErrorText(HX_RESULT ulHXCode)
{
#if defined(HELIX_FEATURE_RESOURCEMGR)
    return m_pEngine->GetResMgr()->GetErrorString(ulHXCode);
#else
    return NULL;
#endif /* HELIX_FEATURE_RESOURCEMGR */
}


/************************************************************************
 *  Method:
 *      IHXAudioPlayerResponse::OnTimeSync
 *  Purpose:
 *      Notification interface provided by users of the IHXAudioPlayer
 *      interface. This method is called by the IHXAudioPlayer when
 *      audio playback occurs.
 */
STDMETHODIMP HXPlayer::OnTimeSync(ULONG32 /*IN*/ ulCurrentTime)
{
    HX_RESULT theErr = HXR_OK;
    CHXMapPtrToPtr::Iterator ndxSource;

    m_bCurrentPresentationClosed = FALSE;

    if (!m_bInitialized)
        return HXR_NOT_INITIALIZED;

    m_bTimeSyncLocked = TRUE;

    UpdateCurrentPlayTime( ulCurrentTime );

    if (m_bIsFirstTimeSync)
    {
        m_bIsFirstTimeSync  = FALSE;
        m_ulFirstTimeSync   = m_ulCurrentPlayTime;
    }

    //  dfprintf("buff", "OnTimesync: %lu %lu %lu\n", HX_GET_TICKCOUNT(), m_ulCurrentPlayTime, m_ulCurrentSystemPlayTime);
    theErr  = ProcessIdle();

    m_pCoreMutex->Lock();

    if (m_bCurrentPresentationClosed)
    {
        goto exit;
    }

#if defined(HELIX_FEATURE_NESTEDMETA)
    m_pPersistentComponentManager->OnTimeSync(m_ulCurrentPlayTime);
#endif /* HELIX_FEATURE_NESTEDMETA */

    ndxSource = m_pSourceMap->Begin();

    for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo *)(*ndxSource);
        pSourceInfo->OnTimeSync(m_ulCurrentPlayTime);

        if (pSourceInfo->m_pPeerSourceInfo &&
            pSourceInfo->m_pPeerSourceInfo->IsInitialized())
        {
            pSourceInfo->m_pPeerSourceInfo->OnTimeSync(m_ulCurrentPlayTime);
        }

        if (m_bCurrentPresentationClosed)
        {
            goto exit;
        }
    }

    if (m_BufferingReason == BUFFERING_SEEK || m_BufferingReason == BUFFERING_LIVE_PAUSE)
    {
        m_BufferingReason   = BUFFERING_CONGESTION;
        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnPostSeek(m_ulTimeBeforeSeek, m_ulTimeAfterSeek);
        }
    }

    if (m_pAdviseSink)
    {
        m_pAdviseSink->OnPosLength( (m_bIsLive ||
                                    m_ulCurrentPlayTime <= m_ulPresentationDuration) ?
                                    m_ulCurrentPlayTime : m_ulPresentationDuration,
                                    m_ulPresentationDuration);
    }

    m_bTimeSyncLocked = FALSE;

exit:
    m_pCoreMutex->Unlock();
    return theErr;
}

HX_RESULT   HXPlayer::DoURLOpen(CHXURL* pCHXURL, char* pMimeType)
{
    HX_RESULT       theErr = HXR_OK;
    char*           pAltURL = NULL;

    if (!pCHXURL)
    {
        return HXR_UNEXPECTED;
    }

    char* pURL = (char*) pCHXURL->GetURL();

    if (!pURL || !*pURL)
    {
        return HXR_UNEXPECTED;
    }

    ResetError();
    ResetRedirectList();

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();

#ifdef _RAHULDEBUG
    CHXURL::TestCompressURL(); // in chxurl.h
#endif

    /* Validate the URL */
    theErr = pCHXURL->GetLastError();

    if (theErr)
    {
        goto exit;
    }

    /* If we are not in a STOP state, do an internal stop */
    if (!m_bIsPresentationDone)
    {
//      m_bIsPresentationClosedToBeSent = FALSE;
        StopPlayer(END_STOP);
    }

    m_bIsDone   = FALSE;
    m_bIsPresentationDone = FALSE;
    m_bIsPresentationClosedToBeSent = TRUE;

#if defined(HELIX_FEATURE_AUTOUPGRADE)
    HX_RELEASE (m_pUpgradeCollection);
    m_pUpgradeCollection = new HXUpgradeCollection;
    m_pUpgradeCollection->AddRef();
#endif /* HELIX_FEATURE_AUTOUPGRADE */

#if defined(HELIX_FEATURE_RECORDCONTROL)
    m_bRecordServiceEnabled = IsRecordServiceEnabled();
#endif

    // all presentation started with one track in a group
    theErr = SetSingleURLPresentation(pCHXURL);

    if (m_LastError && !theErr)
    {
        theErr = m_LastError;
    }

    if (theErr)
    {
        m_bIsPresentationClosedToBeSent = FALSE;
        ResetPlayer();
#if defined(HELIX_FEATURE_VIDEO)
        /*
         * Let the site supplier know that we are done changing the layout.
         */
        if (m_pSiteSupplier && !m_bBeginChangeLayoutTobeCalled)
        {
            m_bBeginChangeLayoutTobeCalled      = TRUE;
            m_pSiteSupplier->DoneChangeLayout();
        }
#endif /* HELIX_FEATURE_VIDEO */
    }

    if (!theErr)
    {
        SchedulePlayer();
    }

exit:

    if (theErr)
    {
        /* If no one has set the last error and there is no user string,
         * copy URL to the user string
         */
        if (!m_LastError && !m_pLastUserString && pURL)
        {
            m_pLastUserString = new char[strlen(pURL) + 1];
            strcpy(m_pLastUserString, pURL); /* Flawfinder: ignore */
        }

        SetLastError(theErr);
    }

    if (m_LastError)
    {
        /* Schedule a ProcessIdle callback. That is where the error
         * would be reported/ auto-upgrade will be requested.
         */
        m_bIsDone = FALSE;
        SchedulePlayer();
        m_bIsDone = TRUE;
        theErr = HXR_OK;
    }
    else
    {
        if (!m_bPlayStateNotified && m_pEngine)
        {
            m_bPlayStateNotified = TRUE;
            m_pEngine->NotifyPlayState(m_bPlayStateNotified);
        }
    }

    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return (theErr);
}
/************************************************************************
 *  Method:
 *      IHXPlayer::OpenURL
 *  Purpose:
 *      Tell the player to open and URL.
 */
STDMETHODIMP HXPlayer::OpenURL(const char* pURL)
{
    // we want to protect against the TLC opening another URL
    if (m_bSetModal)
    {
        return HXR_OK;
    }

    HX_RESULT   hr = HXR_OK;

    HX_RELEASE(m_pRequest);

    // get the compresses URL
    CHXURL url(pURL);
    pURL = url.GetURL();

    m_pRequest = new CHXRequest();
    if( m_pRequest )
    {
        m_pRequest->AddRef();
        m_pRequest->SetURL(url.GetURL());
        m_bActiveRequest = TRUE;

        if (m_pClientRequestSink)
        {
            m_pClientRequestSink->OnNewRequest(m_pRequest);
        }

        hr = DoURLOpen(&url, NULL);
    }
    else
    {
        hr = HXR_OUTOFMEMORY;
    }

    return hr;
}

/************************************************************************
 *      Method:
 *          IID_IHXPlayer2::OpenRequest
 *      Purpose:
 *          Call this method to open the IHXRequest
 */
STDMETHODIMP HXPlayer::OpenRequest(IHXRequest* pRequest)
{
    // we want to protect against the TLC opening another URL
    if (m_bSetModal)
    {
        return HXR_OK;
    }

    HX_RESULT   hr = HXR_OK;
    const char* pURL = NULL;

    if (!pRequest)
    {
        return HXR_UNEXPECTED;
    }

    HX_RELEASE(m_pRequest);

    m_pRequest = pRequest;
    m_pRequest->AddRef();

    m_bActiveRequest = TRUE;

    // retrieve the URL
    if (HXR_OK != m_pRequest->GetURL(pURL))
    {
        return HXR_UNEXPECTED;
    }

    if (m_pClientRequestSink && m_pRequest)
    {
        m_pClientRequestSink->OnNewRequest(m_pRequest);
    }

    // get the compresses URL
    CHXURL url(pURL);
    pURL = url.GetURL();
    m_pRequest->SetURL(pURL);

    hr = DoURLOpen(&url, NULL);

    return hr;
}

/************************************************************************
 *     Method:
 *         IID_IHXPlayer2::GetRequest
 *     Purpose:
 *         Call this method to get the IHXRequest
 */
STDMETHODIMP HXPlayer::GetRequest(REF(IHXRequest*) pRequest)
{
    HX_RESULT  hr = HXR_OK;

    pRequest = NULL;

    if (!m_pRequest)
    {
        hr = HXR_UNEXPECTED;
        goto cleanup;
    }

    pRequest = m_pRequest;
    pRequest->AddRef();

cleanup:

    return hr;
}

////////////////////////////
//
HX_RESULT
HXPlayer::SetSingleURLPresentation(const CHXURL* pURL)
{
    HX_RESULT   theErr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;
    IHXGroup*   pGroup = NULL;
    IHXValues*  pProperties = NULL;
    CHXBuffer*  pValue = NULL;

    m_nGroupCount = 0;

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    // create group
    m_pGroupManager->CreateGroup(pGroup);

    // create track
    pProperties = new CHXHeader;
    pProperties->AddRef();

    pValue = new CHXBuffer();
    pValue->AddRef();

    char* url = (char*)pURL->GetEscapedURL();
    pValue->Set((BYTE*)url, strlen(url)+1);
    pProperties->SetPropertyCString("url", pValue);

    pGroup->AddTrack(pProperties);
    m_pGroupManager->AddGroup(pGroup);

    HX_RELEASE(pValue);
    HX_RELEASE(pProperties);
    HX_RELEASE(pGroup);

    m_pGroupManager->SetCurrentGroup(0);
#else
    HX_DELETE(m_pURL);

    CloseAllRenderers(0);

    m_pURL = new CHXURL(*pURL);
    if( m_pURL )
    {
        theErr = m_pURL->GetLastError();
    }
    else
    {
        theErr = HXR_OUTOFMEMORY;
    }

    if (HXR_OK == theErr)
    {
        pSourceInfo = NewSourceInfo();
        if (pSourceInfo)
        {
            theErr = AddURL(pSourceInfo, TRUE);
        }
        else
        {
            theErr = HXR_OUTOFMEMORY;
        }
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    if (HXR_OK == theErr)
    {
        // At this point, we setup the number of active streams to be the
        // number of sctreams described in the SourceList!
        UpdateSourceActive();

        if (m_bIsFirstBeginPending)
        {
            m_bIsFirstBeginPending = FALSE;
            Begin();
        }
    }
    else
    {
        HX_DELETE(m_pURL);
    }

    return theErr;
};

/************************************************************************
 *  Method:
 *      IHXPlayer::AddURL
 *  Purpose:
 *      Tell the player to add an URL to the current source list.
 */
HX_RESULT HXPlayer::AddURL(SourceInfo*& /*OUT*/ pSourceInfo, BOOL bAltURL)
{
    HX_RESULT   theErr = HXR_OK;
    HXSource*   pSource = NULL;

    theErr = CreateSourceInfo(pSourceInfo, bAltURL);

    if (theErr != HXR_OK)
    {
        goto cleanup;
    }

    pSource = pSourceInfo->m_pSource;

    /* add to the list of sources for this player... */
    if (pSource)
    {
        if (!m_bPartOfNextGroup)
        {
#if defined(HELIX_FEATURE_PREFETCH)
            if (pSourceInfo->m_bPrefetch)
            {
                if (!m_pPrefetchManager)
                {
                    m_pPrefetchManager = new PrefetchManager(this);
                }

                m_pPrefetchManager->AddSource(pSourceInfo);
                pSourceInfo->m_pSource->PartOfPrefetchGroup(TRUE);
            }
            else
#endif /* HELIX_FEATURE_PREFETCH */
            {
                m_pSourceMap->SetAt((void*) pSourceInfo->m_pSource,
                                  (void*) pSourceInfo);

                if (pSource->GetDelay() >= m_ulCurrentPlayTime &&
                    pSource->GetDelay() - m_ulCurrentPlayTime <= MIN_DELAYBEFORE_START)
                {
                    pSourceInfo->m_bTobeInitializedBeforeBegin = TRUE;
                    m_uNumSourceToBeInitializedBeforeBegin++;
                }

                m_bPlayerWithoutSources = FALSE;
                m_bSourceMapUpdated = TRUE;
                m_bForceStatsUpdate = TRUE;
            }
        }
        else
        {
            if (pSource->GetDelay() <= MIN_DELAYBEFORE_START)
            {
                pSourceInfo->m_bTobeInitializedBeforeBegin = TRUE;
                /* We will increment the
                 * m_uNumSourceToBeInitializedBeforeBegin value
                 * once we start this next group
                 */
                //m_uNumSourceToBeInitializedBeforeBegin++;
            }
        }
    }

    /* Are we adding more sources mid presentation ? */
    if (!m_bPartOfNextGroup && !pSourceInfo->m_bPrefetch)
    {
        m_uNumSourcesActive++;
        m_uNumCurrentSourceNotDone++;
    }

cleanup:

    return (theErr);
}

HX_RESULT
HXPlayer::CreateSourceInfo(SourceInfo*& pSourceInfo, BOOL bAltURL)
{
    HX_RESULT   theErr = HXR_OK;
    HXSource*   pSource = NULL;

    if (m_pURL->IsNetworkProtocol())
    {
        theErr = InitializeNetworkDrivers();

        if (!theErr)
        {
            theErr = DoNetworkOpen(pSourceInfo, bAltURL);
        }
    }
    else
    {
        // Only send in URL now.
        theErr = DoFileSystemOpen(pSourceInfo, bAltURL);
    }

    pSource = pSourceInfo->m_pSource;
    if (!theErr && pSource)
    {
        pSourceInfo->m_bInitialized = FALSE;

        if (HXR_OK != pSource->QueryInterface(IID_IHXPendingStatus,
                                            (void**)&(pSourceInfo->m_pStatus)))
        {
            pSourceInfo->m_pStatus = NULL;
        }
    }

    if (HXR_OK != theErr)
    {
        HX_DELETE(pSourceInfo);
    }

    return (theErr);
}

HX_RESULT
HXPlayer::PrepareSourceInfo(IHXValues* pTrack, SourceInfo*& pSourceInfo)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT       rc = HXR_OK;
    char            szMaxDuration[] = "maxduration";
    char            szIndefiniteDuration[] = "indefiniteduration";
    char            szPrefetchType[] = "PrefetchType";
    char            szPrefetchValue[] = "PrefetchValue";
    char            szSoundLevel[] = "soundLevel";
    char            szAudioDeviceReflushHint[] = "audioDeviceReflushHint";
    char            szPersistentComponentID[] = "PersistentComponentID";
    char            szFill[] = "fill";
    UINT32          ulValue = 0;
#ifdef SEQ_DEPENDENCY
    char            szTrack_hint[] = "track-hint";
#endif

    pSourceInfo->m_bAudioDeviceReflushHint = FALSE;
    pSourceInfo->m_uSoundLevel = 100;
    pSourceInfo->m_bIndefiniteDuration = FALSE;
    pSourceInfo->m_ulMaxDuration = 0;
    pSourceInfo->m_ulPersistentComponentID = MAX_UINT32;
    pSourceInfo->m_ulPersistentComponentSelfID = MAX_UINT32;

#if defined(HELIX_FEATURE_PREFETCH)
    // read prefetch info
    if (HXR_OK == pTrack->GetPropertyULONG32(szPrefetchType, ulValue) && ulValue)
    {
        pSourceInfo->m_bPrefetch = TRUE;
        pSourceInfo->m_prefetchType = (PrefetchType)ulValue;

        if (HXR_OK == pTrack->GetPropertyULONG32(szPrefetchValue, ulValue) && ulValue)
        {
            pSourceInfo->m_ulPrefetchValue = ulValue;
        }
    }
#endif /* HELIX_FEATURE_PREFETCH */

    // read audioDeviceReflushHint
    if (HXR_OK == pTrack->GetPropertyULONG32(szAudioDeviceReflushHint, ulValue) && ulValue)
    {
        pSourceInfo->m_bAudioDeviceReflushHint = TRUE;
    }

    // read soundLevel
    if (HXR_OK == pTrack->GetPropertyULONG32(szSoundLevel, ulValue))
    {
        pSourceInfo->m_uSoundLevel = (UINT16)ulValue;
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szIndefiniteDuration, ulValue) && ulValue)
    {
        pSourceInfo->m_bIndefiniteDuration = TRUE;
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szMaxDuration, ulValue))
    {
        pSourceInfo->m_ulMaxDuration = ulValue;
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szPersistentComponentID, ulValue))
    {
        pSourceInfo->m_ulPersistentComponentID = ulValue;
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szFill, ulValue))
    {
        pSourceInfo->m_fillType = (FillType)ulValue;
    }

#ifdef SEQ_DEPENDENCY
    IHXBuffer* pDependency = NULL;
    pTrack->GetPropertyCString(szTrack_hint,pDependency);

    if (pDependency && *(pDependency->GetBuffer()))
    {
        pSourceInfo->SetDependency(pDependency);
    }

    HX_RELEASE(pDependency);
#endif /*SEQ_DEPENDENCY*/

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

/************************************************************************
 *      Method:
 *          IHXPendingStatus::GetStatus
 *      Purpose:
 *          Called by the user to get the current pending status from an object
 */
STDMETHODIMP
HXPlayer::GetStatus
(
    REF(UINT16) uStatusCode,
    REF(IHXBuffer*) pStatusDesc,
    REF(UINT16) ulPercentDone
)
{
    HX_RESULT           hResult = HXR_OK;
    UINT16              statusCode = 0;
    UINT16              percentDone = 0;
    UINT16              totalPercentDone = 0;
    BOOL                bIsContacting = FALSE;
    BOOL                bIsBuffering = FALSE;
    BOOL                bIsReady = FALSE;
    BOOL                bInitializing = FALSE;
    IHXPendingStatus*   pStatus = NULL;

    // initialize(default)
    uStatusCode = HX_STATUS_READY;
    pStatusDesc = NULL;
    ulPercentDone = 0;

    // collect info from all the sources
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();

    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        pStatus = pSourceInfo->m_pStatus;

        if (pStatus && HXR_OK == pStatus->GetStatus(statusCode, pStatusDesc, percentDone))
        {
            if (HX_STATUS_CONTACTING == statusCode)
            {
                bIsContacting = TRUE;
                break;
            }
            else if (HX_STATUS_BUFFERING == statusCode)
            {
                bIsBuffering = TRUE;
                totalPercentDone += percentDone;
            }
            else if (HX_STATUS_READY == statusCode)
            {
                bIsReady = TRUE;
                totalPercentDone += 100;
            }
            else if (HX_STATUS_INITIALIZING == statusCode)
            {
                bInitializing = TRUE;
            }
        }
    }

    if (bInitializing)
    {
        uStatusCode = HX_STATUS_INITIALIZING;
        ulPercentDone = 0;
    }
    else if (bIsContacting)
    {
        uStatusCode = HX_STATUS_CONTACTING;
        ulPercentDone = 0;
    }
    else if (bIsBuffering)
    {
        uStatusCode = HX_STATUS_BUFFERING;
        pStatusDesc = NULL;
        ulPercentDone = totalPercentDone / m_pSourceMap->GetCount();
    }
    else if (bIsReady)
    {
        uStatusCode = HX_STATUS_READY;
        pStatusDesc = NULL;
        ulPercentDone = 0;
    }

    return hResult;
}

HX_RESULT
HXPlayer::DoOpenGroup(UINT16 nGroupNumber)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    HX_RESULT   theErr = HXR_OK;
    IHXGroup*   pGroup = 0;

    HX_VERIFY((theErr = m_pGroupManager->GetGroup(nGroupNumber, pGroup)) == HXR_OK);
    if (theErr)
    {
        return theErr;
    }

    if (!m_bPartOfNextGroup)
    {
        m_bInitialized = FALSE; //so that we InitializeRenderers for this group

        m_bIsPresentationClosedToBeSent = FALSE;
        StopAllStreams(END_STOP);
        ResetGroup();
        CloseAllRenderers(m_nCurrentGroup); //kill all currently open renderers
        m_bIsDone   = FALSE;
    }

    // add all the tracks in the group to the player's source list
    UINT16          nTrackCount = pGroup->GetTrackCount();
    IHXValues*      pTrack = NULL;
    IHXPrefetch*    pPrefetch = NULL;
    HX_RESULT       theErrToReturn = HXR_OK;

    for (UINT16 nTrackIndex = 0; nTrackIndex < nTrackCount; nTrackIndex++)
    {
        if ((theErr = pGroup->GetTrack(nTrackIndex,pTrack)) == HXR_OK)
        {
            theErr = OpenTrack(pTrack, nGroupNumber, nTrackIndex);

            if (theErr && !theErrToReturn)
            {
                theErrToReturn = theErr;
            }

            HX_RELEASE(pTrack);
        }
    }

#if defined(HELIX_FEATURE_PREFETCH)
    if (HXR_OK == pGroup->QueryInterface(IID_IHXPrefetch, (void**)&pPrefetch))
    {
        nTrackCount = pPrefetch->GetPrefetchTrackCount();

        for (UINT16 nTrackIndex = 0; nTrackIndex < nTrackCount; nTrackIndex++)
        {
            if ((theErr = pPrefetch->GetPrefetchTrack(nTrackIndex,pTrack)) == HXR_OK &&
                pTrack)
            {
                theErr = OpenTrack(pTrack, nGroupNumber, nTrackIndex);

                if (theErr && !theErrToReturn)
                {
                    theErrToReturn = theErr;
                }

                HX_RELEASE(pTrack);
            }
        }
    }
#endif /* HELIX_FEATURE_PREFETCH */

    HX_RELEASE(pPrefetch);
    HX_RELEASE(pGroup);

    return theErrToReturn;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

HX_RESULT
HXPlayer::DoAltURLOpen(char* pAltURL, BOOL bDefault, SourceInfo* pMainSourceInfo)
{
#if defined(HELIX_FEATURE_ALT_URL)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    m_bIsDone   = FALSE;
    ResetActiveRequest();

    HX_DELETE(m_pURL);

    m_pURL = new CHXURL(pAltURL);
    if( m_pURL )
    {
        pAltURL = (char*) m_pURL->GetURL();
        hr = m_pURL->GetLastError();
    }
    else
    {
        hr = HXR_OUTOFMEMORY;
    }

    if (hr)
    {
        HX_DELETE(m_pURL);
        goto cleanup;
    }

    pSourceInfo = NewSourceInfo();
    if (pSourceInfo)
    {
        pSourceInfo->m_uGroupID = pMainSourceInfo->m_uGroupID;
        pSourceInfo->m_uTrackID = pMainSourceInfo->m_uTrackID;
        pSourceInfo->m_bPrefetch = pMainSourceInfo->m_bPrefetch;
        pSourceInfo->m_id = pMainSourceInfo->m_id;

        pSourceInfo->m_bAltURL = TRUE;
        pSourceInfo->m_lastErrorFromMainURL = pMainSourceInfo->m_lastErrorFromMainURL;
        pSourceInfo->m_lastErrorStringFromMainURL = pMainSourceInfo->m_lastErrorStringFromMainURL;
        pSourceInfo->m_ulPersistentComponentID = pMainSourceInfo->m_ulPersistentComponentID;
    }
    else
    {
        hr = HXR_OUTOFMEMORY;
        goto cleanup;
    }

    hr = AddURL(pSourceInfo, TRUE);
    if (HXR_OK == hr && pSourceInfo->m_pSource)
    {
        pSourceInfo->m_pSource->SetAltURLType(bDefault);
    }

    SchedulePlayer();

cleanup:

    return hr;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_ALT_URL */
}

HX_RESULT
HXPlayer::SpawnSourceIfNeeded(SourceInfo* pSourceInfo)
{
#if defined(HELIX_FEATURE_SMIL_REPEAT)
    HX_RESULT   theErr = HXR_OK;
    RepeatInfo* pRepeatInfo = NULL;

    // spawned the source if it is repeated
    if (pSourceInfo->m_pRepeatList                  &&
        !pSourceInfo->m_pPeerSourceInfo             &&
        pSourceInfo->m_pSource->IsInitialized())
    {
        SourceInfo* pPeerSourceInfo = NewSourceInfo();
        if( !pPeerSourceInfo )
        {
            return HXR_OUTOFMEMORY;
        }

        CHXURL*     pURL = m_pURL;
        const char* pszURL = pSourceInfo->m_pSource->GetURL();
        m_pURL = new CHXURL(pszURL);
        if( !m_pURL )
        {
            HX_DELETE(pSourceInfo);
            return HXR_OUTOFMEMORY;
        }

        pPeerSourceInfo->m_curPosition = pSourceInfo->m_curPosition;
        pRepeatInfo = (RepeatInfo*)pSourceInfo->m_pRepeatList->GetAtNext(pPeerSourceInfo->m_curPosition);

        if (pRepeatInfo->ulStart)
        {
            m_pURL->AddOption("Start", pRepeatInfo->ulStart);
        }

        if (pRepeatInfo->ulEnd)
        {
            m_pURL->AddOption("End", pRepeatInfo->ulEnd);
        }

        m_pURL->AddOption("Delay", pRepeatInfo->ulDelay);
        m_pURL->AddOption("Duration", pRepeatInfo->ulDuration);

        pPeerSourceInfo->m_bLeadingSource = FALSE;
        pPeerSourceInfo->m_bRepeatIndefinite = pSourceInfo->m_bRepeatIndefinite;
        pPeerSourceInfo->m_ulRepeatInterval = pSourceInfo->m_ulRepeatInterval;
        pPeerSourceInfo->m_ulMaxDuration = pSourceInfo->m_ulMaxDuration;
        pPeerSourceInfo->m_bTrackStartedToBeSent = pSourceInfo->m_bTrackStartedToBeSent;
        pPeerSourceInfo->m_uGroupID = pSourceInfo->m_uGroupID;
        pPeerSourceInfo->m_uTrackID = pRepeatInfo->uTrackID;
        pPeerSourceInfo->m_ulPersistentComponentID = pSourceInfo->m_ulPersistentComponentID;
        pPeerSourceInfo->m_ulTotalTrackDuration = pSourceInfo->m_ulTotalTrackDuration;

        theErr = CreateSourceInfo(pPeerSourceInfo, FALSE);

        if(pPeerSourceInfo && pPeerSourceInfo->m_pSource)
        {
            pPeerSourceInfo->m_pSource->m_ulOriginalDelay = pSourceInfo->m_pSource->m_ulOriginalDelay;

            pSourceInfo->m_pPeerSourceInfo = pPeerSourceInfo;
            pPeerSourceInfo->m_pPeerSourceInfo = pSourceInfo;
        }

        HX_DELETE(m_pURL);
        m_pURL = pURL;
    }

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

HX_RESULT
HXPlayer::SwitchSourceIfNeeded(void)
{
#if defined(HELIX_FEATURE_SMIL_REPEAT)
    // swapping the repeated sources if it's time
    HX_RESULT   theErr = HXR_OK;
    UINT32      ulTotalTrackDuration = 0;
    UINT32      ulPeerSourceDuration = 0;
    UINT32      ulPeerSourceDelay = 0;
    SourceInfo* pSourceInfo = NULL;
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();

    for (;!theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pSourceInfo = (SourceInfo*)(*ndxSource);

        if (!pSourceInfo->m_pPeerSourceInfo ||
            !pSourceInfo->m_pPeerSourceInfo->m_pSource)
        {
            continue;
        }

        ulTotalTrackDuration = pSourceInfo->GetActiveDuration();
        ulPeerSourceDuration = pSourceInfo->m_pPeerSourceInfo->m_pSource->GetDuration();
        ulPeerSourceDelay = pSourceInfo->m_pPeerSourceInfo->m_pSource->GetDelay();

        if (ulTotalTrackDuration > m_ulCurrentPlayTime              &&
            ulPeerSourceDelay > pSourceInfo->m_pSource->GetDelay()  &&
            ulPeerSourceDelay <= m_ulCurrentPlayTime)
        {
            if (ulPeerSourceDuration > ulTotalTrackDuration)
            {
                pSourceInfo->m_pPeerSourceInfo->UpdateDuration(ulTotalTrackDuration - ulPeerSourceDelay);
            }

            m_pSourceMap->RemoveKey(pSourceInfo->m_pSource);

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

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

            m_pSourceMap->SetAt((void*) pSourceInfo->m_pPeerSourceInfo->m_pSource,
                              (void*) pSourceInfo->m_pPeerSourceInfo);

            m_bSourceMapUpdated = TRUE;
            m_bForceStatsUpdate = TRUE;

            break;
        }
    }

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

HX_RESULT
HXPlayer::OpenTrack(IHXValues* pTrack, UINT16 uGroupID, UINT16 uTrackID)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    HX_RESULT           theErr = HXR_OK;
    IHXBuffer*          pBuffer = NULL;
    IHXBuffer*          pID = NULL;
    SourceInfo*         pSourceInfo = NULL;
    const char*         pURL = NULL;

    char                szID[] = "id";
    char                szUrl[] = "url";
    char                szSrc[] = "src";
    char                szStart[] = "Start";
    char                szEnd[] = "End";
    char                szDelay[] = "Delay";
    char                szDuration[] = "Duration";
    UINT32              ulValue = 0;

    theErr = pTrack->GetPropertyCString(szUrl,pBuffer);

    /*
     * Make sure everyone is setting url property (and not the
     * src property) for consistency.
     */

    /* temp - for now support both "src" & "url" */
    if (theErr)
    {
        theErr = pTrack->GetPropertyCString(szSrc,pBuffer);
    }

    if (theErr)
    {
        theErr = HXR_INVALID_PATH;
        goto cleanup;
    }

    pURL = (const char*)pBuffer->GetBuffer();

    if (!pURL || !*pURL)
    {
        theErr = HXR_INVALID_PATH;
        goto cleanup;
    }

    // Cleanup any url object!
    HX_DELETE(m_pURL);

    m_pURL = new CHXURL(pURL); //parse the url
    if (!m_pURL)
    {
        theErr = HXR_OUTOFMEMORY;
        goto cleanup;
    }

    theErr = m_pURL->GetLastError();

    if (theErr)
    {
        goto cleanup;
    }

    theErr = OpenTrackExt();

    //temp - DoNetworkOpen/DoFSOpen extract these properties from m_pURL
    if (HXR_OK == pTrack->GetPropertyULONG32(szStart,ulValue))
    {
        m_pURL->AddOption(szStart, ulValue);
    }
    //pProperty = NULL;
    if (HXR_OK == pTrack->GetPropertyULONG32(szEnd,ulValue))
    {
        m_pURL->AddOption(szEnd, ulValue);
    }
    if (HXR_OK == pTrack->GetPropertyULONG32(szDelay,ulValue))
    {
        m_pURL->AddOption(szDelay, ulValue);
    }

    if (HXR_OK == pTrack->GetPropertyULONG32(szDuration,ulValue))
    {
        m_pURL->AddOption(szDuration, ulValue);
    }

    pSourceInfo = NewSourceInfo();
    if(pSourceInfo)
    {
        pSourceInfo->m_uGroupID = uGroupID;
        pSourceInfo->m_uTrackID = uTrackID;

        if (HXR_OK == pTrack->GetPropertyCString(szID, pID))
        {
            pSourceInfo->m_id = (const char*)pID->GetBuffer();
        }

        PrepareSourceInfo(pTrack, pSourceInfo);
    }
    else
    {
        theErr = HXR_OUTOFMEMORY;
        goto cleanup;
    }

    theErr = AddURL(pSourceInfo, FALSE);

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (HXR_OK == theErr    &&
        m_bPartOfNextGroup  &&
        pSourceInfo->m_pSource)
    {
        m_pNextGroupManager->AddSource(pSourceInfo);
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

cleanup:

    HX_RELEASE(pBuffer);
    HX_RELEASE(pID);

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

HX_RESULT
HXPlayer::OpenTrackExt()
{
    return HXR_OK;
}

/* called from ProcessIdle when done playing current group */
void HXPlayer::PlayNextGroup()
{
    UINT16 uNextGroup = 0;

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    m_pGroupManager->GetNextGroup(uNextGroup);
#else
    uNextGroup = m_nGroupCount;
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    m_nCurrentGroup = uNextGroup;

    if (m_nCurrentGroup >= m_nGroupCount)
    {
        // Stop completely...
        m_bIsPresentationClosedToBeSent = TRUE;
        m_bIsDone = TRUE;

        StopPlayer(END_DURATION);

#if defined(HELIX_FEATURE_VIDEO)
        /*
         * Let the site supplier know that we are done changing the layout.
         */
        if (m_pSiteSupplier && !m_bBeginChangeLayoutTobeCalled)
        {
            m_bBeginChangeLayoutTobeCalled      = TRUE;
            m_pSiteSupplier->DoneChangeLayout();
        }
#endif /* HELIX_FEATURE_VIDEO */
    }
    else
    {
        // build the group's source list
        m_bIsPresentationClosedToBeSent = FALSE;

        StopAllStreams(END_DURATION);
        m_bIsPresentationClosedToBeSent = TRUE;

        ResetGroup();

#if defined(HELIX_FEATURE_BASICGROUPMGR)
        m_pGroupManager->SetCurrentGroup((UINT16) m_nCurrentGroup);
#endif /* HELIX_FEATURE_BASICGROUPMGR */
    }

    m_bForceStatsUpdate = TRUE;
}

/************************************************************************
 *      Method:
 *          HXPlayer::CheckTrackAndSourceOnTrackStarted
 *      Purpose:
 *           Passthrough to allow SourceInfo to call Master TAC manager
 *
 */
BOOL HXPlayer::CheckTrackAndSourceOnTrackStarted(INT32 nGroup,
                                                  INT32 nTrack,
                                                  UINT32 sourceID)
{
#if defined(HELIX_FEATURE_MASTERTAC)
    return (!m_pMasterTAC ?TRUE :m_pMasterTAC->CheckTrackAndSourceOnTrackStarted(nGroup, nTrack, sourceID));
#else
    return TRUE;
#endif /* HELIX_FEATURE_MASTERTAC */
}


/*
 *      IHXRegistryID methods
 */

/************************************************************************
 *      Method:
 *          IHXRegistryID::GetID
 *      Purpose:
 *          Get registry ID(hash_key) of the objects(player, source and stream)
 *
 */
STDMETHODIMP HXPlayer::GetID(REF(UINT32) /*OUT*/ ulRegistryID)
{
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    (m_pStats)?(ulRegistryID = m_pStats->m_ulRegistryID):(ulRegistryID = 0);

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

HX_RESULT HXPlayer::DoNetworkOpen(SourceInfo*& pSourceInfo, BOOL bAltURL)
{
#if defined(HELIX_FEATURE_PLAYBACK_NET)
    HX_RESULT   theErr = HXR_OK;
    HXSource*   pSource = NULL;
    IHXValues*  pURLProperties = NULL;
    IHXBuffer* pBuffer = NULL;
    UINT32      ulRegistryID = 0;
    char*       pszHost = NULL;
    char*       pszResource = NULL;
    const char* pszURL = NULL;
    ULONG32     ulPort = 0;
    IHXBuffer* pszParentName = NULL;

    m_bAllLocalSources = FALSE;

#if defined(HELIX_FEATURE_SMARTERNETWORK)
    if (!m_bPrefTransportInitialized && m_pPreferredTransportManager)
    {
        // re-load proxy/subnet preferences
        m_bPrefTransportInitialized = TRUE;

        if (m_pNetInterfaces)
        {
            m_pNetInterfaces->UpdateNetInterfaces();
        }
        m_pPreferredTransportManager->Initialize();
    }
#endif /* HELIX_FEATURE_SMARTERNETWORK */

    pSource = pSourceInfo->m_pSource = NewNetSource();
    if (!pSource)
    {
        return( HXR_OUTOFMEMORY );
    }
    pSource->AddRef();

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    // registry setting
    if (m_pRegistry && m_pStats)
    {
        char        szSourceName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */

        if (m_bPartOfNextGroup &&
            HXR_OK == m_pRegistry->GetPropName(m_ulNextGroupRegistryID, pszParentName))
        {
            SafeSprintf(szSourceName, MAX_DISPLAY_NAME, "%s.Source%ld", pszParentName->GetBuffer(),
                    pSourceInfo->m_uTrackID);
        }
        else if (HXR_OK == m_pRegistry->GetPropName(m_pStats->m_ulRegistryID, pszParentName))
        {
            SafeSprintf(szSourceName, MAX_DISPLAY_NAME, "%s.Source%ld", pszParentName->GetBuffer(),
                    pSourceInfo->m_uTrackID);
        }
        else
        {
            HX_ASSERT(FALSE);
        }

        /* does this ID already exists ? */
        ulRegistryID = m_pRegistry->GetId(szSourceName);
        if (!ulRegistryID)
        {
            ulRegistryID = m_pRegistry->AddComp(szSourceName);
        }
    }
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    HX_RELEASE(pszParentName);

    pSource->SetSourceInfo(pSourceInfo);
    pSource->Init(this, ulRegistryID);

    UINT32 ulStart = 0, ulEnd = HX_EOF_TIME, ulDelay = 0, ulDuration = 0;    
    GetTimingFromURL(m_pURL, ulStart, ulEnd, ulDelay, ulDuration);

    if (!(pURLProperties = m_pURL->GetProperties()))
    {
        theErr = HXR_FAILED;
        goto cleanup;
    }

    pURLProperties->GetPropertyULONG32(PROPERTY_PORT, ulPort);

    if (HXR_OK == pURLProperties->GetPropertyBuffer(PROPERTY_HOST, pBuffer))
    {
        pszHost = (char*)pBuffer->GetBuffer();
        pBuffer->Release();
    }

    if (HXR_OK == pURLProperties->GetPropertyBuffer(PROPERTY_RESOURCE, pBuffer))
    {
        pszResource = (char*)pBuffer->GetBuffer();
        pBuffer->Release();
    }

    pszURL = m_pURL->GetURL();

    pSource->SetPlayTimes(ulStart, ulEnd, ulDelay, ulDuration);

    pSource->PartOfNextGroup(m_bPartOfNextGroup);

#if defined(HELIX_FEATURE_PREFETCH)
    if (pSourceInfo->m_bPrefetch)
    {
        pSource->EnterPrefetch(pSourceInfo->m_prefetchType, pSourceInfo->m_ulPrefetchValue);
    }
#endif /* HELIX_FEATURE_PREFETCH */

    theErr = ((HXNetSource*)pSource)->Setup(pszHost, pszResource, (UINT16)ulPort, TRUE, m_pURL, bAltURL);

cleanup:

    HX_RELEASE(pURLProperties);

    // cleanup...
    if(theErr && pSource)
    {
        pSource->DoCleanup();
        HX_RELEASE(pSource);
    }

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

HX_RESULT HXPlayer::DoFileSystemOpen(SourceInfo*& pSourceInfo, BOOL bAltURL)
{
#if defined(HELIX_FEATURE_PLAYBACK_LOCAL)
    HX_RESULT   theErr = HXR_OK;
    HXSource*   pSource = NULL;
    IHXValues*  pURLProperties = NULL;
    UINT32      ulRegistryID = 0;
    IHXBuffer* pszParentName = NULL;

    pSource = pSourceInfo->m_pSource = NewFileSource();
    if (!pSource)
    {
        return( HXR_OUTOFMEMORY );
    }
    pSource->AddRef();

    UINT32 ulStart = 0, ulEnd = HX_EOF_TIME, ulDelay = 0, ulDuration = 0;    
    GetTimingFromURL(m_pURL, ulStart, ulEnd, ulDelay, ulDuration);

    if (m_pURL)
    {
        if (!(pURLProperties = m_pURL->GetProperties()))
        {
            theErr = HXR_FAILED;
            goto cleanup;
        }
    }

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    // registry setting
    if (m_pRegistry && m_pStats)
    {
        HX_RESULT res    = HXR_OK;
        UINT32    nRegID = 0;

        if(m_bPartOfNextGroup)
            nRegID = m_ulNextGroupRegistryID;
        else
            nRegID = m_pStats->m_ulRegistryID;

        res = m_pRegistry->GetPropName(nRegID, pszParentName);
        if ( HXR_OK == res && pszParentName )
        {
            char        szSourceName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
            SafeSprintf(szSourceName, MAX_DISPLAY_NAME, "%s.Source%u", pszParentName->GetBuffer(),
                    pSourceInfo->m_uTrackID);

            // does this ID already exist?
            ulRegistryID = m_pRegistry->GetId(szSourceName);
            if ( !ulRegistryID )
            {
                ulRegistryID = m_pRegistry->AddComp(szSourceName);
            }
            HX_RELEASE(pszParentName);
        }
        else
        {
            HX_ASSERT(FALSE);
        }

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

    pSource->SetSourceInfo(pSourceInfo);
    pSource->Init(this, ulRegistryID);

    pSource->SetPlayTimes(ulStart, ulEnd, ulDelay, ulDuration);

    pSource->PartOfNextGroup(m_bPartOfNextGroup);

    theErr = ((HXFileSource*)pSource)->Setup(m_pURL, bAltURL);

cleanup:

    HX_RELEASE(pURLProperties);

    // cleanup...
    if(theErr && pSource)
    {
        pSource->DoCleanup();
        HX_RELEASE(pSource);
    }

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

HX_RESULT
HXPlayer::UnRegisterCurrentSources()
{
    HX_RESULT theErr = HXR_OK;
    
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        theErr = pSourceInfo->UnRegister();
    }

    return theErr;
}

HX_RESULT HXPlayer::InitializeRenderers(void)
{
    HX_RESULT theErr        = HXR_OK;
    HX_RESULT thefinalErr   = HXR_OK;

    SourceInfo*     pSourceInfo = NULL;
    BOOL            bSourceInitialized = TRUE;

    // assume everything will be initialized in this pass...
    BOOL            bAllInitialized = TRUE;

    UINT16 uInitialSourceCount = m_pSourceMap->GetCount();
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pSourceInfo = (SourceInfo*)(*ndxSource);

        if (pSourceInfo->m_bInitialized)
            continue;

        theErr = pSourceInfo->InitializeRenderers(bSourceInitialized);

        if (theErr && !thefinalErr)
        {
            thefinalErr = theErr;
        }

        if (!bSourceInitialized)
        {
            bAllInitialized      = FALSE;
        }

        /* Someone added a source during ProcessIdle.
         * Start all over again
         */
        if (uInitialSourceCount != m_pSourceMap->GetCount())
        {
            bAllInitialized = FALSE;
            break;
        }
    }

    if (!thefinalErr && bAllInitialized)
    {
        m_bInitialized = TRUE;

        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnPosLength( m_ulCurrentPlayTime,
                                        m_ulPresentationDuration);
            m_pAdviseSink->OnBegin(m_ulCurrentPlayTime);
        }
    }

    if (!thefinalErr && m_bInitialized && m_pSourceMap->GetCount() == 0)
    {
        m_bPlayerWithoutSources = TRUE;
    }

#if defined(HELIX_FEATURE_PREFETCH)
    if (!thefinalErr && m_bInitialized)
    {
        while (m_pPendingTrackList && m_pPendingTrackList->GetCount() > 0)
        {
            PendingTrackInfo* pPendingTrackInfo =
                        (PendingTrackInfo*) m_pPendingTrackList->RemoveHead();

            theErr = OpenTrack(pPendingTrackInfo->m_pTrack,
                               pPendingTrackInfo->m_uGroupIndex,
                               pPendingTrackInfo->m_uTrackIndex);

            if (theErr && !thefinalErr)
            {
                thefinalErr = theErr;
            }

            delete pPendingTrackInfo;
        }

        if (thefinalErr)
        {
            ReportError(NULL, thefinalErr, NULL);
        }
    }
#endif /* HELIX_FEATURE_PREFETCH */

    return thefinalErr;
}

// get all packets from event queue and send them to the various renders
HX_RESULT
HXPlayer::ProcessCurrentEvents()
{
    HX_RESULT   theErr  = HXR_OK;
    BOOL        bDone   = FALSE;
    LISTPOSITION listpos = NULL;

    CHXEvent*  pEvent = 0;

    /*
     * check for m_bLiveSeekToBeDone && m_bPaused is so that we do not issue
     * a seek (and start sending packets) before the user has issued a Begin()
     * after Pausing a live stream.
     *
     * Should work for now. Need to be re-visited when Live Pause support
     * is refined in the core.
     *
     * XXXRA
     */
    if (m_bProcessEventsLocked || (m_bLiveSeekToBeDone && m_bPaused))
    {
        return HXR_OK;
    }

    m_bDidWeDeleteAllEvents = FALSE;
    m_bProcessEventsLocked  = TRUE;

    if (m_EventList.GetNumEvents() > 0)
    {
        pEvent = m_EventList.GetHead();
        listpos = m_EventList.GetHeadPosition();
    }

    UINT32  ulEndFillTime = m_ulCurrentPlayTime + 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.
         */
        ulEndFillTime += ADDITIONAL_PREDELIVERY_TIME;
#endif


    /* If we are in a buffering state, then keep pushing packets
     * This is required due to ReportRebufferStatus()
     */

    if (!m_bIsPlaying && !m_bPaused && pEvent)
    {
        UINT32 ulNewEndFillTime = pEvent->GetTimeStartPos() + 1000;
        ulEndFillTime = ulNewEndFillTime > ulEndFillTime ?
                        ulNewEndFillTime : ulEndFillTime;
    }

    while (!theErr && pEvent && !bDone)
    {
        // due?
        /* Do not hold back any packets for live streams */
//{FILE* f1 = ::fopen("c:\\temp\\onpacket.txt", "a+"); ::fprintf(f1, "startPos: %lu endFillTime: %lu\n", pEvent->GetTimeStartPos(), ulEndFillTime);::fclose(f1);}

        if (pEvent->GetTimeStartPos() <= ulEndFillTime)
        {
            IHXPacket* pPacket = pEvent->GetPacket();

            /* since packet's time may be different from player's time, send
             * renderer the offset */
#if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
            HXStaticStatLog::StatPrintf("Packet Time: %lu\n",
                                        pPacket->GetTime());
#endif // DEBUG_LOG_INFO

            BOOL bAtInterrupt = m_pEngine->AtInterruptTime();

            if (m_bLiveSeekToBeDone && !pEvent->IsPreSeekEvent())
            {
                /* Audio device was earlier seeked  based on the last timesync
                 * + pause duration. The actual first packet time we get after
                 * Pause may be different from the seek time. This is because
                 * at pause time, packets may have been given in advance to
                 * the renderers due to preroll. Also, they may be stored in
                 * resend buffer at protocol level. So the only way to kind
                 * of know what time we should have actually seeked to is based
                 * on the first packet time. Even this may result in initial
                 * re-buffering. This is still a hack. We probably need a
                 * better live pause solution.
                 */
                m_bLiveSeekToBeDone = FALSE;
                UINT32 ulCurTime = m_pAudioPlayer->GetCurrentPlayBackTime();
                /* make sure we have sent ATLEAST one ontimesync to the renderer.
                 * otherwise, we cannot rely on the m_ulTimeAfterSeek value since it is based on
                 * m_ulTimeDiff which only gets set in the first ontimesync call.
                 * Needed to fix pause during inital buffering of live playback
                 */
                if (!pEvent->m_pRendererInfo->m_bIsFirstTimeSync &&
                    pPacket->GetTime() > pEvent->m_pRendererInfo->m_pStreamInfo->m_ulTimeAfterSeek)
                {

#if defined(_MACINTOSH) || defined(_MAC_UNIX)
                    /* Cannot call audio player Seek() at interrupt time. It results
                     * in audio device Reset() which issues DoImmediate commands
                     */
                    if (bAtInterrupt)
                    {
                        if (m_pHXPlayerCallback)
                        {
                            RemovePendingCallback(m_pHXPlayerCallback);
                            m_pHXPlayerCallback->CallbackScheduled(
                            m_pScheduler->RelativeEnter(m_pHXPlayerCallback, 0));
                        }

                        bDone = TRUE;
                        continue;
                    }
#endif
                    UINT32 ulTimeDiff = 0;
                    ulTimeDiff = pPacket->GetTime() -
                                 pEvent->m_pRendererInfo->m_pStreamInfo->m_ulTimeAfterSeek;
                    m_pAudioPlayer->Seek(ulCurTime + ulTimeDiff);
                }
            }

            if (!bAtInterrupt || pEvent->m_pRendererInfo->m_bInterruptSafe)
            {
                if (!pEvent->IsPreSeekEvent())
                {
                    SendPostSeekIfNecessary(pEvent->m_pRendererInfo);
                }

                // remove this event from the packet list...
                listpos = m_EventList.RemoveAt(listpos);

                theErr = SendPacket(pEvent);

                /* A renderer may call SetCurrentGroup OR Stop() from within
                * OnPacket call. If so, we delete all the pending events
                */
                if (m_bDidWeDeleteAllEvents)
                {
                    delete pEvent;
                    bDone = TRUE;
                    break;
                }

                HX_ASSERT(pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued > 0);

                pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued--;

                if (pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued == 0 &&
                    pEvent->m_pRendererInfo->m_pStreamInfo->m_bSrcInfoStreamDone)
                {
                    SendPostSeekIfNecessary(pEvent->m_pRendererInfo);
                    pEvent->m_pRendererInfo->m_bOnEndOfPacketSent = TRUE;
                    pEvent->m_pRendererInfo->m_pRenderer->OnEndofPackets();
                }

                // cleanup this event...
                delete pEvent;
                pEvent = NULL;

                // and get the next event...
                if (m_EventList.GetNumEvents() > 0)
                {
                    pEvent = m_EventList.GetAt(listpos);
                }
            }
            else
            {
                pEvent = m_EventList.GetAtNext(listpos); //skip over event - *++listpos
            }
        }
        else
        {
            bDone = TRUE;
        }
    }

    m_bDidWeDeleteAllEvents = FALSE;
    m_bProcessEventsLocked  = FALSE;
    return theErr;
}

HX_RESULT HXPlayer::SendPreSeekEvents()
{
    HX_RESULT theErr = HXR_OK;
    LISTPOSITION listpos = m_EventList.GetHeadPosition();
    while (listpos && (m_EventList.GetNumEvents() != 0))
    {
        CHXEvent*  pEvent = m_EventList.GetAt(listpos);

        BOOL bAtInterrupt = m_pEngine->AtInterruptTime();
        if (!bAtInterrupt || pEvent->m_pRendererInfo->m_bInterruptSafe)
        {
            listpos = m_EventList.RemoveAt(listpos);
            theErr = SendPacket(pEvent);

            HX_ASSERT(pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued > 0);
            pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued--;
            delete pEvent;
        }
        else
        {
            pEvent->SetPreSeekEvent();
            m_EventList.GetNext(listpos);
        }
    }

    SendPreSeekEventsExt();

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; !theErr && ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        if (pSourceInfo->m_pSource && pSourceInfo->m_pSource->m_PacketBufferList.GetCount() > 0)
        {
            CHXSimpleList* pPacketList = &pSourceInfo->m_pSource->m_PacketBufferList;

            LISTPOSITION pos = pPacketList->GetHeadPosition();
            while (pos != NULL)
            {
                CHXEvent* pTempEvent  = (CHXEvent*) pPacketList->GetNext(pos);
                pTempEvent->SetPreSeekEvent();
            }
        }
    }


    return theErr;
}

HX_RESULT HXPlayer::DeleteAllEvents()
{
    while (m_EventList.GetNumEvents() != 0)
    {
        CHXEvent*  pEvent = m_EventList.RemoveHead();
        /* If these packets belong to a persistent source,
         * pass them over.
         */
        if (pEvent->m_pRendererInfo->m_bIsPersistent)
        {
            BOOL bAtInterrupt = m_pEngine->AtInterruptTime();
            if (!bAtInterrupt || pEvent->m_pRendererInfo->m_bInterruptSafe)
            {
                SendPacket(pEvent);
            }
        }
        delete pEvent;
    }

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        if (pSourceInfo->m_pSource)
        {
            pSourceInfo->m_pSource->DeleteAllEvents();
        }
    }

    m_bDidWeDeleteAllEvents = TRUE;
    return HXR_OK;
}

HX_RESULT
HXPlayer::EventReady(HXSource* pSource, CHXEvent* pEvent)
{
    HX_RESULT theErr = HXR_OK;

    SourceInfo*     pSourceInfo = NULL;
    RendererInfo*   pRendInfo   = NULL;

    if (!m_pSourceMap->Lookup(pSource, (void*&) pSourceInfo))
    {
        HX_ASSERT(FALSE);
        return HXR_INVALID_PARAMETER;
    }

    if (!pSourceInfo->m_pRendererMap->Lookup((pEvent->GetPacket())->GetStreamNumber(), (void*&) pRendInfo))
    {
        HX_ASSERT(FALSE);
        return HXR_INVALID_PARAMETER;
    }

    pEvent->m_pRendererInfo = pRendInfo;

    BOOL bOkToSend = (!m_pEngine->AtInterruptTime() ||
                      pEvent->m_pRendererInfo->m_bInterruptSafe);
    if (pEvent->IsPreSeekEvent() && bOkToSend)
    {
        SendPacket(pEvent);
        delete pEvent;
    }
    else
    {
        m_EventList.InsertEvent(pEvent);
        pEvent->m_pRendererInfo->m_ulNumberOfPacketsQueued++;
    }

    return theErr;
}

HX_RESULT HXPlayer::SendPacket(CHXEvent* pEvent)
{
    HX_RESULT retVal = pEvent->m_pRendererInfo->m_pRenderer->OnPacket(pEvent->GetPacket(),
                                                          pEvent->GetTimeOffset());

    if( retVal == HXR_OUTOFMEMORY )
    {
        Report( HXLOG_ERR, retVal, HXR_OK, "Ran out of memory in SendPacket", NULL );
    }
    return retVal;
}

BOOL
HXPlayer::AreAllPacketsSent()
{
    BOOL bAllSent = TRUE;
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        if (pSourceInfo->m_pSource && pSourceInfo->m_pSource &&
            pSourceInfo->m_pSource->m_PacketBufferList.GetCount() > 0)
        {
            bAllSent = FALSE;
            break;
        }
    }

    bAllSent = bAllSent & (m_EventList.GetNumEvents() == 0);
    return bAllSent;
}


void
HXPlayer::StopAllStreams(EndCode endCode)
{
    /* If we do not have access to engine any more, it means it is the final
     * destruction and everything has been deleted by now
     */
    if (!m_pEngine)
        return;

    StopAllStreamsExt(endCode);

    m_bIsDone = TRUE;

    if (m_bInStop)
        return;

    m_bInStop = TRUE;

    m_bIsPlaying = FALSE;

    /* stop timeline */
    m_pAudioPlayer->Stop(TRUE);
    m_bPendingAudioPause = FALSE;

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    if (m_pUpdateStatsCallback->m_bIsCallbackPending)
    {
        m_pUpdateStatsCallback->m_bIsCallbackPending = FALSE;
        m_pScheduler->Remove(m_pUpdateStatsCallback->m_PendingHandle);
        m_pUpdateStatsCallback->m_PendingHandle = 0;
    }
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    RemovePendingCallback(m_pHXPlayerCallback);
    RemovePendingCallback(m_pHXPlayerInterruptCallback);
    RemovePendingCallback(m_pSetupCallback);

#if defined(HELIX_FEATURE_AUTHENTICATION)
    ClearPendingAuthenticationRequests();
#endif /* HELIX_FEATURE_AUTHENTICATION */

    m_bCloseAllRenderersPending     = TRUE;

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo *) (*ndxSource);

//{FILE* f1 = ::fopen("c:\\temp\\ts.txt", "a+"); ::fprintf(f1, "%p pSourceInfo::Stop, ThreadID: %lu\n", pSourceInfo, GetCurrentThreadId());::fclose(f1);}

        pSourceInfo->Stop(endCode);

        if (pSourceInfo->m_pPeerSourceInfo)
        {
            pSourceInfo->m_pPeerSourceInfo->Stop(endCode);
        }
    }

    DeleteAllEvents();

    if (m_bIsPresentationClosedToBeSent)
    {
        m_bIsPresentationClosedToBeSent = FALSE;
        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnStop();
            m_pAdviseSink->OnPresentationClosed();
        }
    }
    m_bInStop = FALSE;

    m_bCurrentPresentationClosed    = TRUE;
}

HX_RESULT
HXPlayer::StopAllStreamsExt(EndCode endCode)
{
    return HXR_OK;
}

HX_RESULT
HXPlayer::SendPreSeekEventsExt()
{
    return HXR_OK;
}

SourceInfo*
HXPlayer::NewSourceInfo(void)
{
    return (new SourceInfo(this));
}

HXFileSource*
HXPlayer::NewFileSource(void)
{
#if defined(HELIX_FEATURE_PLAYBACK_LOCAL)
    return (new HXFileSource());
#else
    return NULL;
#endif /* #if defined(HELIX_FEATURE_PLAYBACK_LOCAL) */
}

HXNetSource*
HXPlayer::NewNetSource(void)
{
#if defined(HELIX_FEATURE_PLAYBACK_NET)
    return (new HXNetSource());
#else
    return NULL;
#endif /* #if defined(HELIX_FEATURE_PLAYBACK_NET) */
}

void
HXPlayer::CloseAllRenderers(INT32 nGroupSwitchTo)
{
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);

        if (pSourceInfo->m_pPeerSourceInfo)
        {
            pSourceInfo->m_pPeerSourceInfo->CloseRenderers();
            HX_DELETE(pSourceInfo->m_pPeerSourceInfo);
        }

        if (pSourceInfo->CloseRenderers() == HXR_OK)
        {
            HX_DELETE(pSourceInfo);
        }
    }

    m_pSourceMap->RemoveAll();
    m_bSourceMapUpdated = TRUE;

#if defined(HELIX_FEATURE_NESTEDMETA)
    if (m_pPersistentComponentManager)
    {
        m_pPersistentComponentManager->CloseAllRenderers(nGroupSwitchTo);
    }
#else
    CleanupLayout();
#endif /* HELIX_FEATURE_NESTEDMETA */

#ifdef _MACINTOSH
    unsigned long lastFree = ::TempFreeMem();
    long deltaFree = 1;
    long iterationCount = 0;
    while (deltaFree > 0 && iterationCount < 5)
    {
        HXMM_COMPACT();
        unsigned long curFree = ::TempFreeMem();
        deltaFree = curFree - lastFree;
        lastFree = curFree;
        iterationCount++;
    }
#endif

    m_bCloseAllRenderersPending = FALSE;
}

/* Reset the player condition
 * Remove all sources and re-initialize all variables...
 */
void
HXPlayer::ResetPlayer(void)
{
    if (m_pCookies)
    {
#if defined(HELIX_FEATURE_COOKIES)
        m_pCookies->SyncRMCookies(TRUE);
#endif /* defined(HELIX_FEATURE_COOKIES) */
    }

    EmptyBeginList();
    ResetGroup();

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

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (m_pGroupManager && m_pGroupManager->GetGroupCount() > 0)
    {
        m_pGroupManager->RemoveAllGroup();
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (m_pNextGroupManager)
    {
        m_pNextGroupManager->Cleanup();
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

#if defined(HELIX_FEATURE_PREFETCH)
    if (m_pPrefetchManager)
    {
        m_pPrefetchManager->Cleanup();
    }
#endif /* HELIX_FEATURE_PREFETCH */

#if defined(HELIX_FEATURE_NESTEDMETA)
    if (m_pPersistentComponentManager)
    {
        m_pPersistentComponentManager->Reset();
    }
#endif /* HELIX_FEATURE_NESTEDMETA */

    m_bSetupLayoutSiteGroup = TRUE;

    m_bIsDone               = TRUE;
    m_bIsPresentationDone   = TRUE;
    m_bPlayerWithoutSources = FALSE;

    m_bPartOfNextGroup      = FALSE;
    m_bLastGroup            = FALSE;
    m_bNextGroupStarted     = FALSE;
    m_bUserHasCalledBegin   = FALSE;
    m_bSourceMapUpdated     = FALSE;
    m_bPrefTransportInitialized = FALSE;
    m_bAddLayoutSiteGroupCalled = FALSE;

    if (!m_bDoRedirect && !m_bBeginChangeLayoutTobeCalled)
    {
        m_bBeginChangeLayoutTobeCalled = TRUE;
#if defined(HELIX_FEATURE_VIDEO)
        if (m_pSiteSupplier)
        {
            m_pSiteSupplier->DoneChangeLayout();
        }
#endif /* HELIX_FEATURE_VIDEO */
    }

#if defined(HELIX_FEATURE_ASM)
    if (m_pBandwidthMgr)
    {
        m_pBandwidthMgr->PresentationDone();
    }
#endif /* HELIX_FEATURE_ASM */

    if (m_bPlayStateNotified && m_pEngine)
    {
        m_bPlayStateNotified = FALSE;
        m_pEngine->NotifyPlayState(m_bPlayStateNotified);
    }

#if defined(HELIX_FEATURE_VIDEO)
    if (m_pSiteManager)
    {
        m_pSiteManager->NeedFocus(FALSE);
    }
#endif /* HELIX_FEATURE_VIDEO */

#if defined(HELIX_FEATURE_PLAYBACK_NET) && !defined(_SYMBIAN) && !defined(_OPENWAVE)
    /* Clean DNS cache */
    conn::clear_cache();
#endif /* HELIX_FEATURE_PLAYBACK_NET */

    /* Compact memory pools now that we are done with a presentation */
#ifdef _MACINTOSH
    unsigned long lastFree = ::TempFreeMem();
    long deltaFree = 1;
    long iterationCount = 0;
    while (deltaFree > 0 && iterationCount < 5)
    {
        HXMM_COMPACT();
        unsigned long curFree = ::TempFreeMem();
        deltaFree = curFree - lastFree;
        lastFree = curFree;
        iterationCount++;
    }
#endif
}

/* Before playing the next group
 * reset everything ResetPlayer does except .
 */
void
HXPlayer::ResetGroup(void)
{
    m_uNumSourcesActive     = 0;
    m_uNumCurrentSourceNotDone = 0;
    m_bInitialized          = FALSE;
    m_bSetupLayoutSiteGroup = TRUE;
    m_ulCurrentPlayTime     = 0;
#if defined(_MACINTOSH)
    m_ulCurrentSystemPlayTime = 0;
#endif
    m_ulPresentationDuration  = 0;
    m_ulTimeBeforeSeek      = 0;
    m_ulTimeAfterSeek       = 0;
    m_BufferingReason       = BUFFERING_START_UP;
    m_bIsDone               = FALSE;
    m_bPaused               = FALSE;
    m_bBeginPending         = FALSE;
    m_bTimelineToBeResumed  = FALSE;
    m_bIsPlaying            = FALSE;
    m_bSetupToBeDone        = FALSE;
    m_bPostSetupToBeDone    = FALSE;

    /* default DEFAULT_TIMESYNC_GRANULARITY ms timesyncs are
     * given to renderers
     */
    m_ulLowestGranularity   = DEFAULT_TIMESYNC_GRANULARITY;

    m_bIsFirstBegin         = TRUE;
    m_bIsLive               = FALSE;
    m_LastError             = HXR_OK;
    m_ulMinimumAudioPreroll = 0;
    m_bInternalPauseResume  = FALSE;
    m_bInternalReset        = FALSE;
    m_bContactingDone       = FALSE;

    m_bIsFirstTimeSync      = TRUE;
    m_ulFirstTimeSync       = 0;

    m_ulElapsedPauseTime    = 0;
    m_ulLiveSeekTime        = 0;
    m_ulTimeOfPause         = 0;
    m_bLiveSeekToBeDone     = FALSE;
    m_bFastStartInProgress  = FALSE;
    m_ulFSBufferingEndTime  = 0;
    m_bFSBufferingEnd       = FALSE;
    m_b100BufferingToBeSent = TRUE;
    m_uNumSourceToBeInitializedBeforeBegin = 0;
    m_bAllLocalSources      = TRUE;
    m_bResumeOnlyAtSystemTime = FALSE;

#if defined(HELIX_FEATURE_PREFETCH)
    if (m_pPrefetchManager)
    {
        m_pPrefetchManager->Cleanup();
        HX_DELETE(m_pPrefetchManager);
    }
#endif /* HELIX_FEATURE_PREFETCH */

    HX_RELEASE(m_pCurrentGroup);

    while (m_pPendingTrackList && m_pPendingTrackList->GetCount() > 0)
    {
        PendingTrackInfo* pPendingTrackInfo =
                    (PendingTrackInfo*) m_pPendingTrackList->RemoveHead();

        delete pPendingTrackInfo;
    }
}

/************************************************************************
 *      Method:
 *              HXPlayer::ReportError
 *      Purpose:
 *              The source object reports of any fatal errors.
 *
 */
void
HXPlayer::ReportError
(
    HXSource*  pSource,
    HX_RESULT   theErr,
    const char* pUserString
)
{
    SourceInfo* pSourceInfo = NULL;
    BOOL        bDefault = FALSE;
    char*       pAltURL = NULL;
    CHXURL*     pURL = NULL;

    if (pSource && theErr != HXR_DNR && theErr != HXR_PROXY_DNR)
    {
        pURL = pSource->GetCHXURL();

        // Alt-URL only in network playback mode
        if (pURL                                                    &&
            (m_pSourceMap->Lookup(pSource, (void*&)pSourceInfo))
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
            || (m_pNextGroupManager                                 &&
            m_pNextGroupManager->Lookup(pSource, pSourceInfo))
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
#if defined(HELIX_FEATURE_PREFETCH)
            || (m_pPrefetchManager                                  &&
            m_pPrefetchManager->Lookup(pSource, pSourceInfo))
#endif /* HELIX_FEATURE_PREFETCH */
            )
        {
            if (pSourceInfo && pSourceInfo->m_bAltURL)
            {
                ResetError();
                /* If this error is for the next group, we do not want to
                 * display the error in the current group playback. Instead,
                 * pass it to the next group manager (by falling out of this
                 * if condition) so that it can be displayed when the next
                 * group is played
                 */
                if (!pSourceInfo->m_pSource ||
                    (!pSourceInfo->m_pSource->IsPartOfNextGroup() &&
                     !pSourceInfo->m_pSource->IsPartOfPrefetchGroup()))
                {
                    // return the last error from the main URL instead
                    Report(HXLOG_ERR, pSourceInfo->m_lastErrorFromMainURL,
                           HXR_OK, pSourceInfo->m_lastErrorStringFromMainURL, NULL);
                    goto cleanup;
                }
                else
                {
                    /* Use the error from the main URL even for the next group */
                    theErr = pSourceInfo->m_lastErrorFromMainURL;
                    pUserString = pSourceInfo->m_lastErrorStringFromMainURL;
                    /* Fall through to report this error to the
                     * next group manager
                     */
                }
            }
#if defined(HELIX_FEATURE_ALT_URL)
            // switch to Alt-URL when:
            // * the network playback has succeeded in this session or
            //   the network playback is in HTTP Cloaking mode
            //   AND
            // * the pSource is at SourceMap OR
            // * the pSource is at the NextGroupManager
            else if ((theErr != HXR_NOT_AUTHORIZED) &&
                     !IS_SERVER_ALERT(theErr)       &&
                     pURL->IsNetworkProtocol()      &&
                     (pAltURL = pSource->GetAltURL(bDefault)))
            {
                if (!m_pAltURLs)
                {
                    m_pAltURLs  = new CHXSimpleList();
                }

                if (!m_pAltURLs->Find(pSourceInfo))
                {
                    pSourceInfo->m_lastErrorFromMainURL = theErr;
                    pSourceInfo->m_lastErrorStringFromMainURL = pUserString;

                    m_pAltURLs->AddTail(pSourceInfo);
                }
                goto cleanup;
            }
#endif /* HELIX_FEATURE_ALT_URL */
        }
    }

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    /* Check if this error is for the next group */
    if (m_pNextGroupManager &&
        m_pNextGroupManager->ReportError(pSource, theErr, pUserString))
    {
        goto cleanup;
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

    Report(HXLOG_ERR, theErr, HXR_OK, pUserString, NULL);

cleanup:

    HX_VECTOR_DELETE(pAltURL);

    return;
}

HX_RESULT HXPlayer::InitializeNetworkDrivers(void)
{
#if defined(HELIX_FEATURE_PLAYBACK_NET)
    if (!m_bNetInitialized)
    {

#if defined( _WIN32 ) || defined( _WINDOWS )
        //  Have we been able to load and initialize the winsock stuff yet?
        m_bNetInitialized = win_net::IsWinsockAvailable(this);
#elif defined (_MACINTOSH)
        m_bNetInitialized = (conn::init_drivers(NULL) == HXR_OK);
#elif defined(_UNIX) || defined(_SYMBIAN) || defined(__TCS__) || defined(_OPENWAVE)
        m_bNetInitialized = TRUE;
#endif

    }

    return (m_bNetInitialized) ? HXR_OK : HXR_GENERAL_NONET;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_PLAYBACK_NET */
}

void
HXPlayer::EventOccurred(HXxEvent* pEvent)
{
  // Note: Unix player does not go through here.
  // calls for UNIX go directly from Client Engine to
  // Site Window class
#if defined (_MACINTOSH) || defined(_MAC_UNIX)

//    if (HXMM_RAHUL_CHECK())
//    {
//        DebugStr("\pEventOccurred SYSTEM Task ENTER;g");
//    }

#ifdef _MACINTOSH
    extern ULONG32         gTIMELINE_MUTEX;

    InterlockedIncrement(&gTIMELINE_MUTEX);
#endif

    if (pEvent->event == nullEvent && m_bIsPlaying)
    {
        ULONG32 ulAudioTime = m_pAudioPlayer->GetCurrentPlayBackTime();
        if ( m_ulCurrentSystemPlayTime != ulAudioTime )
        {
            OnTimeSync( ulAudioTime );
        }
    }

#ifdef _MACINTOSH
    InterlockedDecrement(&gTIMELINE_MUTEX);
#endif

//    if (HXMM_RAHUL_CHECK())
//    {
//        DebugStr("\pEventOccurred SYSTEM Task LEAVE;g");
//    }
#endif
}

#ifdef _UNIX
void
HXPlayer::CollectSelectInfo(INT32* n,
                             fd_set* readfds,
                             fd_set* writefds,
                             fd_set* exceptfds,
                             struct timeval* tv)
{
}

void
HXPlayer::ProcessSelect(INT32* n,
                         fd_set* readfds,
                         fd_set* writefds,
                         fd_set* exceptfds,
                         struct timeval* tv)
{
}
#endif

void
HXPlayer::SetGranularity(ULONG32 ulGranularity)
{
    if (m_ulLowestGranularity > ulGranularity)
    {
        m_ulLowestGranularity = ulGranularity;
    }
    /* sanity check */
    if (m_ulLowestGranularity < MINIMUM_TIMESYNC_GRANULARITY)
    {
        m_ulLowestGranularity = MINIMUM_TIMESYNC_GRANULARITY;
    }
}

HX_RESULT
HXPlayer::SetGranularity(HXSource* pSource, UINT16 uStreamNumber,
                          UINT32 ulGranularity)
{
    SourceInfo*     pSourceInfo = pSource->m_pSourceInfo;
    RendererInfo*   pRendInfo   = NULL;

    HX_ASSERT(pSourceInfo);

    if (!pSourceInfo->m_pRendererMap->Lookup((LONG32) uStreamNumber, (void*&) pRendInfo))
    {
        HX_ASSERT(FALSE);
        return HXR_INVALID_PARAMETER;
    }

    pRendInfo->m_ulGranularity  = ulGranularity;

    /* sanity check */
    if (pRendInfo->m_ulGranularity < MINIMUM_TIMESYNC_GRANULARITY)
    {
        pRendInfo->m_ulGranularity = MINIMUM_TIMESYNC_GRANULARITY;
    }

    return HXR_OK;
}


/************************************************************************
 *      Method:
 *              HXPlayer::ClosePlayer
 *      Purpose:
 *              Just adding a lock around calls to Close()
 *
 */
void HXPlayer::ClosePlayer(void)
{
    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    Close();
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;
}

void
HXPlayer::AbortPlayer(void)
{
    // Stop completely...
    m_bIsPresentationClosedToBeSent = TRUE;
    m_bIsDone = TRUE;

    StopPlayer(END_ABORT);

#if defined(HELIX_FEATURE_VIDEO)
    /*
     * Let the site supplier know that we are done changing the layout.
     */
    if (m_pSiteSupplier && !m_bBeginChangeLayoutTobeCalled)
    {
        m_bBeginChangeLayoutTobeCalled  = TRUE;
        m_pSiteSupplier->DoneChangeLayout();
    }
#endif /* HELIX_FEATURE_VIDEO */
}

void
HXPlayer::Close()
{
    StopPlayer(END_STOP);
    CloseAllRenderers(m_nCurrentGroup);

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    if (m_pRegistry)
    {
        // delete player stats
        if (m_pStats && m_pStats->m_ulRegistryID)
        {
            m_pRegistry->DeleteById(m_pStats->m_ulRegistryID);
        }
        HX_DELETE(m_pStats);

        // delete repeat stats
        if (m_ulRepeatedRegistryID)
        {
            m_pRegistry->DeleteById(m_ulRepeatedRegistryID);
            m_ulRepeatedRegistryID = 0;
        }

        // delete nextgroup stats
        if (m_ulNextGroupRegistryID)
        {
            m_pRegistry->DeleteById(m_ulNextGroupRegistryID);
            m_ulNextGroupRegistryID = 0;
        }
    }

    if (m_pUpdateStatsCallback)
    {
        if (m_pUpdateStatsCallback->m_bIsCallbackPending)
        {
            m_pUpdateStatsCallback->m_bIsCallbackPending = FALSE;
            m_pScheduler->Remove(m_pUpdateStatsCallback->m_PendingHandle);
            m_pUpdateStatsCallback->m_PendingHandle = 0;
        }

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

    if (m_bIsPresentationClosedToBeSent)
    {
        m_bIsPresentationClosedToBeSent = FALSE;
        if (m_pAdviseSink)
        {
            m_pAdviseSink->OnStop();
            m_pAdviseSink->OnPresentationClosed();
        }
    }
    HX_RELEASE (m_pAdviseSink);

    RemovePendingCallback(m_pHXPlayerCallback);
    HX_RELEASE(m_pHXPlayerCallback);

    RemovePendingCallback(m_pHXPlayerInterruptCallback);
    HX_RELEASE(m_pHXPlayerInterruptCallback);

    RemovePendingCallback(m_pSetupCallback);
    HX_RELEASE(m_pSetupCallback);

#if defined(HELIX_FEATURE_AUTHENTICATION)
    if (m_pAuthenticationCallback)
    {
        ClearPendingAuthenticationRequests();
        HX_RELEASE(m_pAuthenticationCallback);
    }
#endif /* HELIX_FEATURE_AUTHENTICATION */

    HX_RELEASE(m_pAutheticationValues);

    HX_RELEASE(m_pRequest);

    ResetRedirectList();
    HX_DELETE (m_pRedirectList);
    HX_DELETE (m_pURL);
    HX_DELETE (m_pAltURLs);

#if defined(HELIX_FEATURE_REGISTRY)
    HX_RELEASE (m_pRegistry);
#endif /* HELIX_FEATURE_REGISTRY */

    HX_RELEASE (m_pEngine);
    HX_RELEASE (m_pClient);
    HX_RELEASE (m_pScheduler);

    if (m_pErrorSinkControl)
    {
#if defined(HELIX_FEATURE_SINKCONTROL)
        m_pErrorSinkControl->Close();
#endif /* HELIX_FEATURE_SINKCONTROL */
        HX_RELEASE (m_pErrorSinkControl);
    }

    HX_RELEASE(m_pClientRequestSink);

#if defined(HELIX_FEATURE_PREFERENCES)
    HX_RELEASE (m_pPreferences);
#endif /* HELIX_FEATURE_PREFERENCES */

#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
    if (m_pHyperNavigate)
    {
#if defined(HELIX_FEATURE_HYPER_NAVIGATE)
        m_pHyperNavigate->Close();
#endif /* defined(HELIX_FEATURE_HYPER_NAVIGATE) */
        HX_RELEASE (m_pHyperNavigate);
    }
#endif /* HELIX_FEATURE_HYPER_NAVIGATE */

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (m_pGroupManager)
    {
        m_pGroupManager->RemoveSink(this);
#if defined(HELIX_FEATURE_NESTEDMETA)
        m_pGroupManager->RemoveSink(m_pPersistentComponentManager);
#endif /* HELIX_FEATURE_NESTEDMETA */
        HX_RELEASE(m_pGroupManager);
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

#if defined(HELIX_FEATURE_VIDEO)
    HX_RELEASE (m_pSiteManager);
    HX_RELEASE (m_pSiteSupplier);
#endif /* HELIX_FEATURE_VIDEO */
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    HX_RELEASE (m_pUpgradeCollection);
#endif /* HELIX_FEATURE_AUTOUPGRADE */
#if defined(HELIX_FEATURE_PACKETHOOKMGR)
    HX_RELEASE (m_pPacketHookManager);
#endif /* HELIX_FEATURE_PACKETHOOKMGR */
#if defined(HELIX_FEATURE_SMARTERNETWORK)
    HX_RELEASE (m_pPreferredTransportManager);
#endif /* HELIX_FEATURE_SMARTERNETWORK */
    HX_RELEASE (m_pNetInterfaces);
    HX_RELEASE (m_pClientViewSource);
    HX_RELEASE (m_pViewPortManager);
    HX_RELEASE (m_pClientViewRights);

#if defined(HELIX_FEATURE_MEDIAMARKER)
    if (m_pMediaMarkerManager)
    {
        m_pMediaMarkerManager->Close();
        HX_RELEASE(m_pMediaMarkerManager);
    }
#endif /* #if defined(HELIX_FEATURE_MEDIAMARKER) */

#if defined(HELIX_FEATURE_EVENTMANAGER)
    if (m_pEventManager)
    {
        m_pEventManager->Close();
        HX_RELEASE(m_pEventManager);
    }
#endif /* #if defined(HELIX_FEATURE_EVENTMANAGER) */

#if defined(HELIX_FEATURE_NESTEDMETA)
    if (m_pPersistentComponentManager)
    {
        m_pPersistentComponentManager->Close();
        HX_RELEASE (m_pPersistentComponentManager);
    }
#endif /* HELIX_FEATURE_NESTEDMETA */

#if defined(HELIX_FEATURE_AUDIO)
    if (m_pAudioPlayer)
    {
        CHXAudioSession* pAudioSession = m_pAudioPlayer->GetOwner();
        if (pAudioSession)
        {
            pAudioSession->CloseAudioPlayer(m_pAudioPlayer);
        }

        HX_RELEASE (m_pAudioPlayer);
    }
#endif /* HELIX_FEATURE_AUDIO */

    if (m_pMasterTAC)
    {
#if defined(HELIX_FEATURE_MASTERTAC)
        m_pMasterTAC->Close();
#endif /* HELIX_FEATURE_MASTERTAC */
        HX_RELEASE(m_pMasterTAC);
    }

#if defined(HELIX_FEATURE_PREFETCH)
    HX_DELETE(m_pPrefetchManager);
#endif /* HELIX_FEATURE_PREFETCH */

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    HX_DELETE(m_pNextGroupManager);
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

#if defined(HELIX_FEATURE_ASM)
    if (m_pBandwidthMgr)
    {
        m_pBandwidthMgr->PresentationDone();
        HX_RELEASE(m_pBandwidthMgr);
    }
#endif /* HELIX_FEATURE_ASM */

#if defined(HELIX_FEATURE_ASM)
    HX_RELEASE(m_pASM);
#endif /* HELIX_FEATURE_ASM */

    HX_ASSERT(!m_pPendingTrackList || m_pPendingTrackList->IsEmpty());
    HX_DELETE(m_pPendingTrackList);

    if (m_pChildPlayerList)
    {
        CHXSimpleList::Iterator i = m_pChildPlayerList->Begin();
        for (; i != m_pChildPlayerList->End(); ++i)
        {
            IHXPlayer* pChildPlayer = (IHXPlayer*)(*i);
            HX_RELEASE(pChildPlayer);
        }
        HX_DELETE(m_pChildPlayerList);
    }

    HX_RELEASE(m_pParentPlayer);

#if defined(HELIX_FEATURE_PLAYBACK_NET)
    if (m_bNetInitialized)
    {
        m_bNetInitialized = FALSE;
#if defined( _WIN32 ) || defined( _WINDOWS )
        win_net::ReleaseWinsockUsage(this);
#endif /* defined( _WIN32 ) || defined( _WINDOWS ) */
    }
#endif /* HELIX_FEATURE_PLAYBACK_NET */

#if defined(_DEBUG) && defined(DEBUG_LOG_INFO)
     HXStaticStatLog::Close();
#endif // DEBUG_LOG_INFO

    HX_RELEASE(m_pPlugin2Handler);

#if defined(HELIX_FEATURE_RECORDCONTROL)
    UnloadRecordService();
#endif /* HELIX_FEATURE_RECORDCONTROL */

    ResetError();
}

void
HXPlayer::ProcessPendingAuthentication(void)
{
#if defined(HELIX_FEATURE_AUTHENTICATION)
    IHXAuthenticationManager2* pAuthenticationManagerClient2 = NULL;

    if (HXR_OK == m_pClient->QueryInterface(IID_IHXAuthenticationManager2,
                             (void**)&pAuthenticationManagerClient2))
    {
        HX_ASSERT(pAuthenticationManagerClient2);

        if (pAuthenticationManagerClient2)
        {
            pAuthenticationManagerClient2->HandleAuthenticationRequest2(this, m_pAutheticationValues);
        }

        HX_RELEASE(pAuthenticationManagerClient2);
        return;
    }

    // otherwise continue with the old-fashioned authentication manager

    IHXAuthenticationManager* pAuthenticationManagerClient = NULL;

    m_pClient->QueryInterface(IID_IHXAuthenticationManager,
                             (void**)&pAuthenticationManagerClient);

    HX_ASSERT(pAuthenticationManagerClient);
    if (pAuthenticationManagerClient)
    {
        pAuthenticationManagerClient->HandleAuthenticationRequest(this);
    }

    HX_RELEASE(pAuthenticationManagerClient);
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

void
HXPlayer::ClearPendingAuthenticationRequests(void)
{
#if defined(HELIX_FEATURE_AUTHENTICATION)
    m_AuthenticationRequestsPending.ClearPendingList();
    RemovePendingCallback(m_pAuthenticationCallback);

    /* Remove all pending authentication requests TBD */
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

STDMETHODIMP
HXPlayer::HandleAuthenticationRequest(
    IHXAuthenticationManagerResponse* pResponse)
{
#if defined(HELIX_FEATURE_AUTHENTICATION)
    return HandleAuthenticationRequest2( pResponse, NULL );
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

STDMETHODIMP
HXPlayer::HandleAuthenticationRequest2(
    IHXAuthenticationManagerResponse* pResponse, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_AUTHENTICATION)
    IHXValues*                  pHeader = NULL;
    IHXBuffer*                  pUserName = NULL;
    IHXBuffer*                  pPassword = NULL;
    ULONG32                     ulAuthenticationAttempts = 0;

    HX_RELEASE(m_pAutheticationValues);
    m_pAutheticationValues = pValues;
    if (m_pAutheticationValues)
    {
        m_pAutheticationValues->AddRef();
    }

    /* Username/Password in the url will not work for tracks within
     * SMIL/RAM files.
     * This is because the m_pURL points to the last opened track
     * in the presentation and may not point to the URL for which
     * the authentication has been requested for.
     * This is tricky to fix --- post B2 - XXXRA
     */
    // Get info about the URL
    if (m_pURL)
    {
        pHeader = m_pURL->GetProperties();
    }
    if (pHeader)
    {
        // Try to get the username and password from the URL
        pHeader->GetPropertyBuffer(PROPERTY_USERNAME, pUserName);
        pHeader->GetPropertyBuffer(PROPERTY_PASSWORD, pPassword);

        // Try to get the number of times we've tried to authenticate
        // already based on this name and password
        HX_RESULT res = pHeader->GetPropertyULONG32("AUTHENTICATION_ATTEMPTS", ulAuthenticationAttempts);
    }

    // First check to see if a username and/or password were supplied in the URL.  If they were there is no need to pass
    // this on to the client to display any UI.
    // (And in case the wrong name/password were supplied, don't let them try too many times.)
    if (pUserName && pPassword && (ulAuthenticationAttempts < 3))
    {
        if (pHeader)
        {
            pHeader->SetPropertyULONG32("AUTHENTICATION_ATTEMPTS", ulAuthenticationAttempts + 1);
        }

        pResponse->AuthenticationRequestDone(HXR_OK, (const char*)pUserName->GetBuffer(), (const char*)pPassword->GetBuffer());
    }
    else
    {
#ifndef _WIN16
        m_AuthenticationRequestsPending.Add(this, pResponse, pValues);
#else
        IHXAuthenticationManager2* pAuthenticationManagerClient2 = NULL;

        if (HXR_OK == m_pClient->QueryInterface(IID_IHXAuthenticationManager2, (void**)&pAuthenticationManagerClient2))
        {
            pAuthenticationManagerClient2->HandleAuthenticationRequest2
                (
                    pResponse, pValues
                );

            HX_RELEASE(pAuthenticationManagerClient2);
        }

        else

        {
            // if the new authentication manager isn't available, use the old authentication manager.
            IHXAuthenticationManager* pAuthenticationManagerClient = NULL;

            m_pClient->QueryInterface
                (
                    IID_IHXAuthenticationManager,
                    (void**)&pAuthenticationManagerClient
                );

            pAuthenticationManagerClient->HandleAuthenticationRequest
                (
                    pResponse
                );

            HX_RELEASE(pAuthenticationManagerClient);

        }

#endif /* _WIN16 */
    }


    HX_RELEASE(pUserName);
    HX_RELEASE(pPassword);
    HX_RELEASE(pHeader);
#endif /* HELIX_FEATURE_AUTHENTICATION */

    return HXR_OK;
}

// IHXAuthenticationManagerResponse
STDMETHODIMP
HXPlayer::AuthenticationRequestDone
(
    HX_RESULT result,
    const char* user,
    const char* password
)
{
#if !defined(_WIN16) && defined(HELIX_FEATURE_AUTHENTICATION)
    return m_AuthenticationRequestsPending.SatisfyPending
    (
        result,
        user,
        password
    );
#else
    return HXR_NOTIMPL;
#endif /* _WIN16 */
}

/*
 *      IHXViewSourceCommand::CanViewSouce
 */
STDMETHODIMP_(BOOL)
HXPlayer::CanViewSource(IHXStreamSource* pStream)
{
#if defined(HELIX_FEATURE_VIEWSOURCE)
    BOOL bRet = TRUE;
    HX_RESULT ret = HXR_OK;
    if ( m_pClientViewSource == NULL && m_pEngine )
    {
        m_pEngine->QueryInterface(IID_IHXClientViewSource,
            (void**)&m_pClientViewSource);
    }
    if ( m_pClientViewSource )
    {
        if ( pStream )
        {
            bRet = m_pClientViewSource->CanViewSource(pStream);
        }
        else
        {
            IHXStreamSource* pStrmSource = NULL;
            if ( GetViewSourceStream(pStrmSource) )
            {
                bRet = m_pClientViewSource->CanViewSource(pStrmSource);
            }
            else
            {
                bRet = FALSE;
            }
            HX_RELEASE(pStrmSource);
        }
    }
    else
    {
        bRet = FALSE;
    }
    return bRet;
#else
    return FALSE;
#endif
}

/*
 *      IHXViewSourceCommand::DoViewSouce
 */
STDMETHODIMP
HXPlayer::DoViewSource(IHXStreamSource* pStream)
{
#if defined(HELIX_FEATURE_VIEWSOURCE)
    HX_RESULT ret = HXR_OK;
    if ( m_pClientViewSource == NULL && m_pEngine )
    {
        m_pEngine->QueryInterface(IID_IHXClientViewSource,
            (void**)&m_pClientViewSource);
    }
    if ( m_pClientViewSource )
    {
        if ( pStream )
        {
            ret = m_pClientViewSource->DoViewSource((IUnknown*)(IHXPlayer*)this, pStream);
        }
        else
        {
            IHXStreamSource* pStrmSource = NULL;
            if ( GetViewSourceStream(pStrmSource) )
            {
                ret = m_pClientViewSource->DoViewSource((IUnknown*)(IHXPlayer*)this,
                    pStrmSource);
            }
            else
            {
                // pass null for the stream source -
                // will cause a no source error to be shown.
                ret = m_pClientViewSource->DoViewSource(
                    (IUnknown*)(IHXPlayer*)this, NULL);
            }

            HX_RELEASE(pStrmSource);
        }
    }
    else
    {
        ret = HXR_NOT_INITIALIZED;
    }
    return ret;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/*
 *      IHXViewSourceCommand::GetViewSourceURL
 */
STDMETHODIMP
HXPlayer::GetViewSourceURL(IHXStreamSource* pStream, IHXViewSourceURLResponse* pResp)
{
#if defined(HELIX_FEATURE_VIEWSOURCE)
    HX_RESULT ret = HXR_OK;
    if ( m_pClientViewSource == NULL && m_pEngine )
    {
        m_pEngine->QueryInterface(IID_IHXClientViewSource,
            (void**)&m_pClientViewSource);
    }
    if ( m_pClientViewSource )
    {
        if ( pStream )
        {
            ret = m_pClientViewSource->GetViewSourceURL(
                (IUnknown*)(IHXPlayer*)this, pStream, pResp);
        }
        else
        {
            IHXStreamSource* pStrmSource = NULL;
            if ( GetViewSourceStream(pStrmSource) )
            {
                ret = m_pClientViewSource->GetViewSourceURL(
                    (IUnknown*)(IHXPlayer*)this, pStrmSource, pResp);
            }
            else
            {
                ret = HXR_FAIL;
            }
            HX_RELEASE(pStrmSource);
        }
    }
    else
    {
        ret = HXR_NOT_INITIALIZED;
    }
    return ret;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_VIEWSOURCE */
}

BOOL
HXPlayer::GetViewSourceStream(REF(IHXStreamSource*) pStrmSource)
{
    BOOL bRet = FALSE;

#if defined(HELIX_FEATURE_VIEWSOURCE)
#if defined(HELIX_FEATURE_NESTEDMETA)
        HXPersistentComponent* pPersistentComponent = m_pPersistentComponentManager->m_pRootPersistentComponent;

        // not a persistent playback
        if (!pPersistentComponent)
        {
            HX_ASSERT(m_pSourceMap->GetCount() <= 1);
            if ( m_pSourceMap->GetCount() > 0 )
            {
                CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
                SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
                HX_ASSERT(pSourceInfo);

                HXSource* pSource = pSourceInfo->m_pSource;
                if( pSource )
                {
                    HX_RELEASE(pStrmSource);
                    if ( SUCCEEDED(pSource->QueryInterface(IID_IHXStreamSource,
                        (void**)&pStrmSource)) )
                    {
                        bRet = TRUE;
                    }
                }
            }
        }
        else
        {
            HXSource* pSource = pPersistentComponent->m_pSourceInfo->m_pSource;
            if ( pSource )
            {
                HX_RELEASE(pStrmSource);
                if ( SUCCEEDED(pSource->QueryInterface(IID_IHXStreamSource,
                    (void**)&pStrmSource)) )
                {
                    bRet = TRUE;
                }
            }
        }
#else
        HX_ASSERT(m_pSourceMap->GetCount() <= 1);
        if ( m_pSourceMap->GetCount() > 0 )
        {
            CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
            SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
            HX_ASSERT(pSourceInfo);

            HXSource* pSource = pSourceInfo->m_pSource;
            if( pSource )
            {
                HX_RELEASE(pStrmSource);
                if ( SUCCEEDED(pSource->QueryInterface(IID_IHXStreamSource,
                    (void**)&pStrmSource)) )
                {
                    bRet = TRUE;
                }
            }
        }
#endif /* HELIX_FEATURE_NESTEDMETA */
#endif /* HELIX_FEATURE_VIEWSOURCE */

    return bRet;
}

HX_RESULT
HXPlayer::GetSourceInfo(UINT16 uGroupIndex, UINT16 uTrackIndex, SourceInfo*& pSourceInfo)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pTempSourceInfo = NULL;
    CHXMapPtrToPtr::Iterator ndxSource;

    pSourceInfo = NULL;

    if (uGroupIndex != m_nCurrentGroup)
    {
        hr = HXR_UNEXPECTED;
        goto cleanup;
    }

    // find the sourceinfo
    ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pTempSourceInfo = (SourceInfo*)(*ndxSource);

        if (pTempSourceInfo->m_uTrackID == uTrackIndex)
        {
            pSourceInfo = pTempSourceInfo;
            break;
        }
    }

    if (!pSourceInfo)
    {
        hr = HXR_FAILED;
    }

cleanup:

    return hr;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

HX_RESULT
HXPlayer::CopyRegInfo(UINT32 ulFromRegID, UINT32 ulToRegID)
{
#if defined(HELIX_FEATURE_REGISTRY)
    HX_RESULT       hr = HXR_OK;
    const char*     pPropName = NULL;
    ULONG32          ulPropId = 0;
    UINT32          ulRegId = 0;
    IHXBuffer*      pFromRegName = NULL;
    IHXBuffer*      pToRegName = NULL;
    IHXValues*      pValues = NULL;
    char            szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */

    m_pRegistry->GetPropName(ulFromRegID, pFromRegName);
    m_pRegistry->GetPropName(ulToRegID, pToRegName);

    // Get the IHXValues under this id.
    m_pRegistry->GetPropListById(ulFromRegID, pValues);

    // PT_COMPOSITE without child
    if (!pValues)
    {
        return HXR_OK;
    }

    // iterate through the child list
    hr = pValues->GetFirstPropertyULONG32(pPropName, ulPropId);
    while (hr == HXR_OK)
    {
        HXPropType type = m_pRegistry->GetTypeById(ulPropId);

        SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.%s", pToRegName->GetBuffer(),
                pPropName + pFromRegName->GetSize());

        if (type == PT_COMPOSITE)
        {
            ulRegId = m_pRegistry->AddComp(szRegName);
            CopyRegInfo(ulPropId, ulRegId);
        }
        else
        {
            switch(type)
            {
                case PT_INTEGER:
                {
                    INT32 val;
                    if(HXR_OK == m_pRegistry->GetIntById(ulPropId, val))
                    {
                        m_pRegistry->AddInt(szRegName, val);
                    }
                    break;
                }
                case PT_STRING:
                {
                    IHXBuffer* pBuffer = NULL;
                    if(HXR_OK == m_pRegistry->GetStrById(ulPropId,
                                                       pBuffer))
                    {
                        m_pRegistry->AddStr(szRegName, pBuffer);
                    }
                    HX_RELEASE(pBuffer);
                    break;
                }
                case PT_BUFFER:
                {
                    IHXBuffer* pBuffer = NULL;
                    if(HXR_OK == m_pRegistry->GetBufById(ulPropId,
                                                       pBuffer))
                    {
                        m_pRegistry->AddBuf(szRegName, pBuffer);
                    }
                    HX_RELEASE(pBuffer);
                    break;
                }
                default:
                    break;
            }
        }

        hr = pValues->GetNextPropertyULONG32(pPropName, ulPropId);
    }

    HX_RELEASE(pFromRegName);
    HX_RELEASE(pToRegName);
    HX_RELEASE(pValues);
#endif /* HELIX_FEATURE_REGISTRY */

    return HXR_OK;
}

HX_RESULT
HXPlayer::UpdateTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    UINT16      uCurrentGroup = 0;
    UINT16      uNewTrackIndex = 0;
    UINT32      ulTempNewTrackIndex = 0;
    UINT32      ulParentRegId = 0;
    SourceInfo* pSourceInfo = NULL;
    IHXGroup*  pGroup = NULL;

    if (HXR_OK == pValues->GetPropertyULONG32("TrackIndex", ulTempNewTrackIndex))
    {
        // /Fixes PR 121880 on Mac and other Big-endian machines, upcasting of UINT16
        // to UINT32 in GetProp...() causes the wrong 2 bytes of the 4-byte prop to get
        // used, so we pass in a temp UINT32 and copy from that:
        uNewTrackIndex = (UINT16)ulTempNewTrackIndex; 
        if (uGroupIndex == m_nCurrentGroup &&
            HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
        {
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
            ulParentRegId = m_pStats->m_ulRegistryID;
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
        }
#if defined (HELIX_FEATURE_NEXTGROUPMGR)
        else if (m_bNextGroupStarted                                                &&
                 m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pGroup) == HXR_OK  &&
                 uCurrentGroup == uGroupIndex)
        {
            m_pNextGroupManager->GetSource(uTrackIndex, pSourceInfo);
            ulParentRegId = m_ulNextGroupRegistryID;
        }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

        if (pSourceInfo)
        {
            hr = UpdateSourceInfo(pSourceInfo,
                                  ulParentRegId,
                                  uNewTrackIndex);
        }
    }

#if defined(HELIX_FEATURE_NESTEDMETA)
    m_pPersistentComponentManager->TrackUpdated(uGroupIndex, uTrackIndex, pValues);
#endif /* HELIX_FEATURE_NESTEDMETA */

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

HX_RESULT
HXPlayer::RemoveTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    UINT16      uCurrentGroup = 0;
    SourceInfo* pSourceInfo = NULL;
    IHXGroup*  pGroup = NULL;

    // track removed from the current group
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        // remove source from the current group
        m_pSourceMap->RemoveKey(pSourceInfo->m_pSource);

        pSourceInfo->Remove();
        HX_DELETE(pSourceInfo);

        AdjustPresentationTime();

        m_bSourceMapUpdated = TRUE;
        m_bForceStatsUpdate = TRUE;
    }
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    // track removed from the next group being prefetched
    else if (m_bNextGroupStarted                                                    &&
             m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pGroup) == HXR_OK  &&
             uCurrentGroup == uGroupIndex)
    {
        if (HXR_OK == m_pNextGroupManager->GetSource(uTrackIndex, pSourceInfo))
        {
            m_pNextGroupManager->RemoveSource(pSourceInfo);

            pSourceInfo->Remove();
            HX_DELETE(pSourceInfo);
        }
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

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

HX_RESULT
HXPlayer::AddPrefetchTrack(UINT16 uGroupIndex,
                            UINT16 uPrefetchTrackIndex,
                            IHXValues* pTrack)
{
#if defined(HELIX_FEATURE_PREFETCH)
    HX_RESULT   theErr = HXR_OK;
    char        szDelay[] = "Delay";
    UINT32      ulDelay = 0;
    IHXGroup*   pGroup = NULL;

    if (m_pGroupManager)
    {
        theErr = m_pGroupManager->GetGroup(uGroupIndex, pGroup);
    }

    /* Check if a track is added to the group currently played */
    if (uGroupIndex == m_nCurrentGroup && pGroup == m_pCurrentGroup)
    {
        /* If we are not yet initialized, add tracks to the current source
         * map only if the track is within the fudge factor.
         *
         * This is to fix a bug in SMIL file with multiple sources in seq
         * with outer par.
         * The expected behavior is to start the first source
         * in seq and then initialize the remaining sources. Since we were
         * adding additional tracks to the source map, the player was not
         * getting initialized until ALL the sources in the seq have been
         * initialized. This resulted in massive startup delays.
         */
        if (!m_bInitialized)
        {
            if ((HXR_OK != pTrack->GetPropertyULONG32(szDelay,ulDelay)) ||
                (ulDelay <= m_ulCurrentPlayTime + MIN_DELAYBEFORE_START))
            {
                theErr = OpenTrack(pTrack, uGroupIndex, uPrefetchTrackIndex);
            }
            else
            {
                if (!m_pPendingTrackList)
                {
                    m_pPendingTrackList = new CHXSimpleList;
                }

                PendingTrackInfo* pPendingTrackInfo =
                    new PendingTrackInfo(uGroupIndex, uPrefetchTrackIndex, pTrack);

                m_pPendingTrackList->AddTail(pPendingTrackInfo);
            }
        }
        else
        {
            theErr = OpenTrack(pTrack, uGroupIndex, uPrefetchTrackIndex);
        }

        if (theErr)
        {
            ReportError(NULL, theErr, NULL);
        }
    }
    // we don't support prefetch for the next group
    else
    {
        HX_ASSERT(FALSE);
    }

    HX_RELEASE(pGroup);

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

HX_RESULT
HXPlayer::UpdatePrefetchTrack(UINT16 uGroupIndex,
                               UINT16 uPrefetchTrackIndex,
                               IHXValues* pValues)
{
#if defined(HELIX_FEATURE_PREFETCH)
    HX_RESULT   hr = HXR_OK;
    UINT16      uCurrentGroup = 0;
    UINT16      uNewTrackIndex = 0;
    UINT32      ulTempNewTrackIndex = 0;

    SourceInfo* pSourceInfo = NULL;
    IHXGroup*  pGroup = NULL;

    if (!m_pPrefetchManager)
    {
        hr = HXR_FAILED;
        goto cleanup;
    }

    if (HXR_OK == pValues->GetPropertyULONG32("TrackIndex", ulTempNewTrackIndex))
    {
        // /On Mac and other Big-endian machines, upcasting of UINT16 to UINT32& in
        // GetProp...() causes the wrong 2 bytes of the 4-byte prop to get used, so
        // we pass in a temp UINT32 and copy from that:
        uNewTrackIndex = (UINT16)ulTempNewTrackIndex; 
        if (uGroupIndex == m_nCurrentGroup &&
            HXR_OK == m_pPrefetchManager->GetSource(uNewTrackIndex, pSourceInfo))
        {
            HX_ASSERT(pSourceInfo->m_uTrackID == uNewTrackIndex);
        }
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
        else if (m_bNextGroupStarted                                                &&
                 m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pGroup) == HXR_OK  &&
                 uCurrentGroup == uGroupIndex)
        {
            hr = HXR_NOTIMPL;
        }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
    }

cleanup:

    return hr;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_PREFETCH */
}

HX_RESULT
HXPlayer::RemovePrefetchTrack(UINT16 uGroupIndex,
                               UINT16 uPrefetchTrackIndex,
                               IHXValues* pValues)
{
#if defined(HELIX_FEATURE_PREFETCH)
    HX_RESULT   theErr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    if (m_pPrefetchManager &&
        m_pPrefetchManager->Lookup(pValues, pSourceInfo))
    {
        theErr = m_pPrefetchManager->RemoveSource(pSourceInfo);

        // cleanup if the prefetch track has not been activated
        if (pSourceInfo->m_pSource->IsPartOfPrefetchGroup())
        {
            pSourceInfo->Remove();
            HX_DELETE(pSourceInfo);
        }
    }

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

HX_RESULT
HXPlayer::PrefetchTrackDone(UINT16 uGroupIndex, UINT16 uPrefetchTrackIndex, HX_RESULT status)
{
#if defined(HELIX_FEATURE_PREFETCH)
    IHXGroup*           pGroup = NULL;
    IHXPrefetchSink*   pPrefetchSink = NULL;

    if (m_pGroupManager && HXR_OK == m_pGroupManager->GetGroup(uGroupIndex, pGroup))
    {
        if (HXR_OK == pGroup->QueryInterface(IID_IHXPrefetchSink, (void**)&pPrefetchSink))
        {
            pPrefetchSink->PrefetchTrackDone(uGroupIndex, uPrefetchTrackIndex, status);
        }
        HX_RELEASE(pPrefetchSink);
    }
    HX_RELEASE(pGroup);
#endif /* HELIX_FEATURE_PREFETCH */

    return HXR_OK;
}

HX_RESULT
HXPlayer::BeginTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    // begin on the current group only
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        hr = pSourceInfo->BeginTrack();
    }
    else
    {
        hr = HXR_UNEXPECTED;
    }

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

HX_RESULT
HXPlayer::PauseTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    // pause on the current group only
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        hr = pSourceInfo->PauseTrack();
    }
    else
    {
        hr = HXR_UNEXPECTED;
    }

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

HX_RESULT
HXPlayer::SeekTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues, UINT32 ulSeekTime)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    // seek on the current group only
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        hr = pSourceInfo->SeekTrack(ulSeekTime);
    }
    else
    {
        hr = HXR_UNEXPECTED;
    }

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

HX_RESULT
HXPlayer::StopTrack(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pValues)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR)
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    // stop on the current group only
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        hr = pSourceInfo->StopTrack();
    }
    else
    {
        hr = HXR_UNEXPECTED;
    }

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

HX_RESULT
HXPlayer::SetSoundLevel(UINT16 uGroupIndex, UINT16 uTrackIndex, UINT16 uSoundLevel, BOOL bReflushAudioDevice)
{
    HX_RESULT   hr = HXR_OK;
    SourceInfo* pSourceInfo = NULL;

    // set on the current group only
    if (uGroupIndex == m_nCurrentGroup &&
        HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        hr = pSourceInfo->SetSoundLevel(uSoundLevel, bReflushAudioDevice);
    }
    else
    {
        hr = HXR_UNEXPECTED;
    }

    return hr;
}
    
void
HXPlayer::CheckSourceRegistration(void)
{
    BOOL bAtLeastOneRegister = FALSE;

    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    /* Check if we are done. This may be TRUE for empty files */
    for (; ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        if (pSourceInfo->m_pSource && pSourceInfo->m_pSource->CanBeResumed())
        {
            pSourceInfo->Register();
            bAtLeastOneRegister = TRUE;
        }
    }

    if (bAtLeastOneRegister)
    {
        RegisterSourcesDone();
    }
}

void
HXPlayer::GetTimingFromURL(CHXURL* pURL, UINT32& ulStart, 
                           UINT32& ulEnd, UINT32& ulDelay, UINT32& ulDuration)
{
    IHXValues* pURLOptions = NULL;

    ulStart = 0;
    ulEnd = HX_EOF_TIME;
    ulDelay = 0;
    ulDuration = 0;

    if (pURL)
    {
        pURLOptions = pURL->GetOptions();
        if (pURLOptions)
        {
            pURLOptions->GetPropertyULONG32("Start", ulStart);
            pURLOptions->GetPropertyULONG32("End", ulEnd);
            pURLOptions->GetPropertyULONG32("Delay", ulDelay);
            pURLOptions->GetPropertyULONG32("Duration", ulDuration);
        }
        HX_RELEASE(pURLOptions);
    }
}

/************************************************************************
 *  Method:
 *      IHXOverrideDefaultServices::OverrideServices
 *  Purpose:
 *      Override default services provided by the G2 system.
 *
 */
STDMETHODIMP
HXPlayer::OverrideServices(IUnknown* pContext)
{
    if (!pContext)
    {
        return HXR_UNEXPECTED;
    }

#if defined(HELIX_FEATURE_PREFERENCES)
    /* override IHXPreferences */
    IHXPreferences* pPreferences = NULL;
    if (pContext->QueryInterface(IID_IHXPreferences, (void**) &pPreferences)
            == HXR_OK)
    {
        HX_RELEASE(m_pPreferences);
        m_pPreferences = pPreferences;
    }
#endif /* HELIX_FEATURE_PREFERENCES */

    /* override IHXPlugin2Handler */
    IHXPlugin2Handler* pPlugin2Handler = NULL;
    if (pContext->QueryInterface(IID_IHXPlugin2Handler, (void**) &pPlugin2Handler)
            == HXR_OK)
    {
        HX_RELEASE(m_pPlugin2Handler);
        m_pPlugin2Handler = pPlugin2Handler;
    }

    return HXR_OK;
}

/*
 * IHXPlayerNavigator methods
 */

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::AddChildPlayer
 *      Purpose:
 *          Add child player to the current player
 */
STDMETHODIMP
HXPlayer::AddChildPlayer(IHXPlayer* pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    if (!m_pChildPlayerList)
    {
        m_pChildPlayerList = new CHXSimpleList();
    }

    if (m_pChildPlayerList &&
        !m_pChildPlayerList->Find(pPlayer))
    {
        pPlayer->AddRef();
        m_pChildPlayerList->AddTail(pPlayer);
    }

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::RemoveChildPlayer
 *      Purpose:
 *          Remove child player from the current player
 */
STDMETHODIMP
HXPlayer::RemoveChildPlayer(IHXPlayer* pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    if (m_pChildPlayerList)
    {
        LISTPOSITION lPosition = m_pChildPlayerList->Find(pPlayer);

        if (lPosition)
        {
            m_pChildPlayerList->RemoveAt(lPosition);
            HX_RELEASE(pPlayer);
        }
    }

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::GetNumChildPlayer
 *      Purpose:
 *          Get number of the child players
 */
STDMETHODIMP_(UINT16)
HXPlayer::GetNumChildPlayer()
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    return m_pChildPlayerList ? m_pChildPlayerList->GetCount() : 0;
#else
    return 0;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::GetChildPlayer
 *      Purpose:
 *          Get Nth child player
 */
STDMETHODIMP
HXPlayer::GetChildPlayer(UINT16 uPlayerIndex,
                          REF(IHXPlayer*) pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    HX_RESULT       rc = HXR_OK;
    LISTPOSITION    lPosition;

    pPlayer = NULL;

    if (!m_pChildPlayerList)
    {
        rc = HXR_FAILED;
        goto cleanup;
    }

    lPosition = m_pChildPlayerList->FindIndex(uPlayerIndex);

    if (!lPosition)
    {
        rc = HXR_FAILED;
        goto cleanup;
    }

    pPlayer = (IHXPlayer*)m_pChildPlayerList->GetAt(lPosition);
    pPlayer->AddRef();

cleanup:

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

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::SetParentPlayer
 *      Purpose:
 *          Set the parent player
 */
STDMETHODIMP
HXPlayer::SetParentPlayer(IHXPlayer* pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    HX_ASSERT(!m_pParentPlayer);
    HX_RELEASE(m_pParentPlayer);

    m_pParentPlayer = pPlayer;
    pPlayer->AddRef();

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::RemoveParentPlayer
 *      Purpose:
 *          Remove the parent player
 */
STDMETHODIMP
HXPlayer::RemoveParentPlayer(IHXPlayer* pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    HX_ASSERT(pPlayer == m_pParentPlayer);
    HX_RELEASE(m_pParentPlayer);

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

/************************************************************************
 *      Method:
 *          IHXPlayerNavigator::GetParentPlayer
 *      Purpose:
 *          Get the parent player
 */
STDMETHODIMP
HXPlayer::GetParentPlayer(REF(IHXPlayer*) pPlayer)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    pPlayer = NULL;

    if (m_pParentPlayer)
    {
        pPlayer = m_pParentPlayer;
        pPlayer->AddRef();

        return HXR_OK;
    }
    else
    {
        return HXR_FAILED;
    }
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
// UpdateStatsCallback
UpdateStatsCallback::UpdateStatsCallback() :
     m_lRefCount (0)
    ,m_pPlayer (0)
    ,m_PendingHandle (0)
    ,m_bIsCallbackPending(FALSE)
{
}

UpdateStatsCallback::~UpdateStatsCallback()
{
}

/*
 * IUnknown methods
 */

/////////////////////////////////////////////////////////////////////////
//      Method:
//              IUnknown::QueryInterface
//      Purpose:
//              Implement this to export the interfaces supported by your
//              object.
//
STDMETHODIMP UpdateStatsCallback::QueryInterface(REFIID riid, void** ppvObj)
{
    QInterfaceList qiList[] =
        {
            { GET_IIDHANDLE(IID_IHXCallback), (IHXCallback*)this },
            { GET_IIDHANDLE(IID_IUnknown), (IUnknown*)(IHXCallback*)this },
        };
    
    return ::QIFind(qiList, QILISTSIZE(qiList), riid, ppvObj);
}

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

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

    delete this;
    return 0;
}


/*
 *      IHXCallback methods
 */
STDMETHODIMP UpdateStatsCallback::Func(void)
{
    m_PendingHandle     = 0;
    m_bIsCallbackPending        = FALSE;

    if (m_pPlayer)
    {
        m_pPlayer->UpdateStatistics();
    }

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

// HXCallback

#if defined (_WIN32) || defined (_MACINTOSH) || defined(THREADS_SUPPORTED)

HXPlayerCallback::HXPlayerCallback(void* pParam, fGenericCBFunc pFunc)
 :  CHXGenericCallback(pParam, pFunc)
 ,  m_bInterrupSafe(FALSE) 
{
}
    
STDMETHODIMP HXPlayerCallback::QueryInterface(REFIID riid, void** ppvObj)
{
    if (IsEqualIID(riid, IID_IHXInterruptSafe))
    {
        AddRef();
        *ppvObj = (IUnknown*)(IHXInterruptSafe*)this;
        return HXR_OK;
    }
    else
    {
        return CHXGenericCallback::QueryInterface(riid, ppvObj);
    }
}

STDMETHODIMP_(BOOL) HXPlayerCallback::IsInterruptSafe()
{
    HXPlayer* pPlayer = (HXPlayer*)m_pParam;

    return  m_bInterrupSafe && 
            pPlayer->m_bInitialized &&
            !pPlayer->m_bIsDone;
}
#endif //(_WIN32) || defined (_MACINTOSH) || defined(THREADS_SUPPORTED)

void HXPlayer::PlayerCallback(void* pParam)
{
    HXPlayer* pObj = (HXPlayer*)pParam;

    if (pObj)
    {
        pObj->ProcessIdle();
    }
}

void HXPlayer::SetupCallback(void* pParam)
{
    HXPlayer* pObj = (HXPlayer*)pParam;

    if (pObj)
    {
        pObj->SetupAudioPlayer();
    }
}

#if defined(HELIX_FEATURE_AUTHENTICATION)
void HXPlayer::AuthenticationCallback(void* pParam)
{
    HXPlayer* pObj = (HXPlayer*)pParam;

    if (pObj)
    {
        pObj->ProcessPendingAuthentication();
    }
}
#endif //HELIX_FEATURE_AUTHENTICATION

/************************************************************************
 *  Method:
 *      HXPlayer::SetupRendererSite
 *
 *  NOTE: Notice that the props passed in are associated with the stream
 *  that the renderer is rendering, but we don't make renderers implement
 *  their own support IHXValues. That would be mean.
 */
void
HXPlayer::SetupRendererSite(IUnknown* pRenderer, IHXValues* pProps, BOOL bIsPersistent)
{
#if defined(HELIX_FEATURE_VIDEO)
    HX_ASSERT(pProps);
    HX_ASSERT(pRenderer);

    IHXSiteUserSupplier*   pSUS = NULL;
    IHXSiteUser*           pSU  = NULL;
    UINT32                  uReqestID;
    /*
     * If the renderer doesn't support IHXSiteUserSupplier then
     * it is not a display oriented renderer and we skip it to
     * go to the next one!
     */
    if (HXR_OK == pRenderer->QueryInterface(IID_IHXSiteUserSupplier,
                                            (void**)&pSUS))
    {
        /*
         * Ask the site manager if any sites are available
         * for the renderer by this playto/from info.
         */
        if (!m_pSiteManager->
                        IsSiteAvailableByPlayToFrom(pProps, /*bIsPersistent*/ FALSE))
        {
            if (m_pSiteSupplier)
            {
                /*
                 * Let the site supplier know that we are changing the layout.
                 */
                if (m_bBeginChangeLayoutTobeCalled)
                {
                    m_bBeginChangeLayoutTobeCalled      = FALSE;
                    m_pSiteSupplier->BeginChangeLayout();
                }


                // XXXRA Change to revert back to old focus behavior for
                // datatypes that rely on this behavior
                CheckIfRendererNeedFocus(pRenderer);

                /*
                 * Inform the TLC/SS of the new sites we need.
                 */
                uReqestID = (ULONG32)pSUS;
                m_pSiteSupplier->SitesNeeded(uReqestID,pProps);
                DisableScreenSaver();
                m_SiteRequestIDList.AddTail((void*)uReqestID);
            }
        }

        /*  JEB: if the hookup failed, do not release the site user
         *  Hookup will add it to a list and hook it up later
         *  when the site has really been added
         */

        if (m_pSiteManager->HookupByPlayToFrom(pSUS,pProps,/*bIsPersistent*/ FALSE))
        {
            pSUS->Release();
        }
    }
    // If the renderer doesn't support SiteUserSupplier, than see if
    // it supports single instance as a SiteUser...
    else if (HXR_OK == pRenderer->QueryInterface(IID_IHXSiteUser,
                            (void**)&pSU))
    {
        /*
         * Ask the site manager if any sites are available
         * for the renderer by this playto/from info.
         */
        if (!m_pSiteManager->
                        IsSiteAvailableByPlayToFrom(pProps, /*bIsPersistent*/ FALSE))
        {
            if (m_pSiteSupplier)
            {
                /*
                 * Let the site supplier know that we are changing the layout.
                 */
                if (m_bBeginChangeLayoutTobeCalled)
                {
                    m_bBeginChangeLayoutTobeCalled      = FALSE;
                    m_pSiteSupplier->BeginChangeLayout();
                }

                // XXXRA Change to revert back to old focus behavior for
                // datatypes that rely on this behavior
                CheckIfRendererNeedFocus(pRenderer);

                /*
                 * Inform the TLC/SS of the new sites we need.
                 */
                uReqestID = (ULONG32)pSU;
                m_pSiteSupplier->SitesNeeded(uReqestID,pProps);
                DisableScreenSaver();
                m_SiteRequestIDList.AddTail((void*)uReqestID);
            }
        }

        /*  JEB: if the hookup failed, do not release the site user
         *  Hookup will add it to a list and hook it up later
         *  when the site has really been added
         */

        if (m_pSiteManager->HookupSingleSiteByPlayToFrom(pSU,pProps, /*bIsPersistent*/ FALSE))
        {
            pSU->Release();
        }
    }
#endif /* HELIX_FEATURE_VIDEO */
}

/************************************************************************
 *  Method:
 *      HXPlayer::SetupLayoutSiteGroup
 */
void
HXPlayer::SetupLayoutSiteGroup(IUnknown* pLSG, BOOL bIsPersistent)
{
#if defined(HELIX_FEATURE_VIDEO)
    HX_ASSERT(pLSG);

    IHXSiteUserSupplier*   pSUS = NULL;
    IHXSiteUser*           pSU = NULL;

    if (HXR_OK == pLSG->QueryInterface(IID_IHXSiteUserSupplier,
                            (void**)&pSUS))
    {
        IHXValues* pSUSProps = NULL;

        BOOL releaseSUS = TRUE;

        if (HXR_OK == pSUS->QueryInterface(IID_IHXValues,
                                (void**)&pSUSProps))
        {
            /*
             * Ask the site manager if any sites are available
             * for the LSG by this LSGName.
             */
            if (!m_pSiteManager->IsSiteAvailableByLSGName(pSUSProps,
                /*bIsPersistent*/ FALSE))
            {
                if (m_pSiteSupplier)
                {
                    /*
                     * Let the site supplier know that we are changing the layout.
                     */
                    if (m_bBeginChangeLayoutTobeCalled)
                    {
                        m_bBeginChangeLayoutTobeCalled  = FALSE;
                        m_pSiteSupplier->BeginChangeLayout();
                    }

                    /*
                     * Inform the TLC/SS of the new sites we need.
                     */
                    ULONG32 uReqestID = (ULONG32)pSUS;
                    m_pSiteSupplier->SitesNeeded(uReqestID,pSUSProps);
                    DisableScreenSaver();
                    m_SiteRequestIDList.AddTail((void*)uReqestID);
                }
            }

            /*
             * We can now assume that the site supplier has added
             * any sites for this set of properties to the site
             * manager that it is willing to provide.
             *
             * Tell the site manager to hook up the site user to
             * any sites with the same LSGName as the layoutSiteGroup.
             *
             * Hookup will also create child sites for the tuners,
             * But these are added to the site manager with a flag
             * which states how they can be used (for renderers only).
             * Because we don't want to accidentally connect one of these
             * tuner sites as a LSG.
             */

            /*  JEB: if the hookup failed, do not release the site user
             *  Hookup will add it to a list and hook it up later
             *  when the site has really been added
             */

            if (!m_pSiteManager->HookupByLSGName(pSUS,pSUSProps,/*bIsPersistent*/ FALSE))
            {
                releaseSUS = FALSE;
            }

            pSUSProps->Release();
        }

        if (releaseSUS)
        {
            pSUS->Release();
        }
    }
    // If the LSG doesn't support SiteUserSupplier, than see if it supports
    // single instance as a SiteUser...
    else if (HXR_OK == pLSG->QueryInterface(IID_IHXSiteUser,
                            (void**)&pSU))
    {
        IHXValues* pSUProps = NULL;

        BOOL releaseSU = TRUE;

        if (HXR_OK == pSU->QueryInterface(IID_IHXValues,
                                (void**)&pSUProps))
        {
            /*
             * Ask the site manager if any sites are available
             * for the LSG by this LSGName.
             */
            if (!m_pSiteManager->IsSiteAvailableByLSGName(pSUProps,
                /*bIsPersistent*/ FALSE))
            {
                if (m_pSiteSupplier)
                {
                    /*
                     * Let the site supplier know that we are changing the layout.
                     */
                    if (m_bBeginChangeLayoutTobeCalled)
                    {
                        m_bBeginChangeLayoutTobeCalled  = FALSE;
                        m_pSiteSupplier->BeginChangeLayout();
                    }

                    /*
                     * Inform the TLC/SS of the new sites we need.
                     */
                    ULONG32 uReqestID = (ULONG32)pSU;
                    m_pSiteSupplier->SitesNeeded(uReqestID,pSUProps);
                    DisableScreenSaver();
                    m_SiteRequestIDList.AddTail((void*)uReqestID);
                }
            }

            /*
             * We can now assume that the site supplier has added
             * any sites for this set of properties to the site
             * manager that it is willing to provide.
             *
             * Tell the site manager to hook up the site user to
             * any sites with the same LSGName as the layoutSiteGroup.
             *
             * Hookup will also create child sites for the tuners,
             * But these are added to the site manager with a flag
             * which states how they can be used (for renderers only).
             * Because we don't want to accidentally connect one of these
             * tuner sites as a LSG.
             */

            /*  JEB: if the hookup failed, do not release the site user
             *  Hookup will add it to a list and hook it up later
             *  when the site has really been added
             */

            if (!m_pSiteManager->HookupSingleSiteByLSGName(pSU,pSUProps,/*bIsPersistent*/ FALSE))
            {
                releaseSU = FALSE;
            }

            pSUProps->Release();
        }

        if (releaseSU)
        {
            pSU->Release();
        }
    }
#endif /* HELIX_FEATURE_VIDEO */
}

/************************************************************************
 *  Method:
 *      HXPlayer::SetupLayout
 *  Purpose:
 *      shuts down old layout and sets up new layout. If bShowNewLayout
 *      is FALSE then new layout is not set up.
 */
STDMETHODIMP
HXPlayer::SetupLayout(BOOL bIsPersistent)
{
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();

    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSource);
        pSourceInfo->SetupRendererSites(bIsPersistent);
    }

    return HXR_OK;
}

/************************************************************************
 *  Method:
 *      HXPlayer::CleanupLayout
 *  Purpose:
 *      shuts down old layout
 */
STDMETHODIMP
HXPlayer::CleanupLayout()
{
    /*
     * For each Site/SiteUser combination unhook them because
     * the layout is changing. You might think that this is
     * only appropriate for associations by LSGName, but we do it
     * for all because we want this implementation to work for
     * empty-layouts as well.
     *
     * Note this also means to unhook any and all site/user
     * combinations for child sites for each of these sites.
     * This means that all layouts are released.
     */
#if defined(HELIX_FEATURE_VIDEO)
    if (m_pSiteManager) m_pSiteManager->UnhookAll();

    /*
     * Run through all previous requested sites... Note:
     * this is not the same as the list of layoutGroupSites
     * since we don't request ones that were available when
     * we set the layout.
     */
    CHXSimpleList::Iterator ndxRequest = m_SiteRequestIDList.Begin();

    for (; ndxRequest != m_SiteRequestIDList.End(); ++ndxRequest)
    {
        ULONG32 requestID = (ULONG32)(*ndxRequest);

        if (m_pSiteSupplier)
        {
            /*
             * Let the site supplier know that we are changing the layout.
             */
            if (m_bBeginChangeLayoutTobeCalled)
            {
                m_bBeginChangeLayoutTobeCalled  = FALSE;
                m_pSiteSupplier->BeginChangeLayout();
            }

            /*
             * Inform the TLC/SS that we don't need old sites.
             */
            m_pSiteSupplier->SitesNotNeeded(requestID);
        }
    }
    m_SiteRequestIDList.RemoveAll();
#endif /* HELIX_FEATURE_VIDEO */

    return HXR_OK;
}

void
HXPlayer::InternalPause()
{
    if (!m_bIsFirstBegin && !m_bBeginPending && !m_bTimelineToBeResumed)
    {
        m_bIsPlaying = FALSE;
        m_bTimelineToBeResumed = TRUE;
        m_pAudioPlayer->Pause();
//      DEBUG_OUT(this, (s,
//          "Pause Timeline %p", this));
    }
}

/*
 *  IHXGroupSink methods
 */
/************************************************************************
*  Method:
*      IHXGroupSink::GroupAdded
*  Purpose:
*               Notification of a new group being added to the presentation.
*/
STDMETHODIMP
HXPlayer::GroupAdded(UINT16         /*IN*/ uGroupIndex,
                      IHXGroup*    /*IN*/ pGroup)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    m_nGroupCount++;
    if (m_nCurrentGroup == m_pGroupManager->GetGroupCount() - 1)
    {
        m_bLastGroup = TRUE;
    }
    else
    {
        m_bLastGroup = FALSE;
    }
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    return HXR_OK;
}

/************************************************************************
*  Method:
*      IHXGroupSink::GroupRemoved
*  Purpose:
*               Notification of a group being removed from the presentation.
*/
STDMETHODIMP
HXPlayer::GroupRemoved(UINT16       /*IN*/ uGroupIndex,
                        IHXGroup*  /*IN*/ pGroup)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (m_nGroupCount > 0)
        m_nGroupCount--;

    UINT16 uNumGroups = m_pGroupManager->GetGroupCount();
    if (uNumGroups == 0 ||
        m_nCurrentGroup == uNumGroups - 1)
    {
        m_bLastGroup = TRUE;
    }
    else
    {
        m_bLastGroup = FALSE;
    }

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

/************************************************************************
*  Method:
*      IHXGroupSink::AllGroupsRemoved
*  Purpose:
*               Notification that all groups have been removed from the
*               current presentation.
*/
STDMETHODIMP
HXPlayer::AllGroupsRemoved(void)
{
    HX_RELEASE(m_pCurrentGroup);
    return HXR_OK;
}

/************************************************************************
*  Method:
*      IHXGroupSink::TrackAdded
*  Purpose:
*               Notification of a new track being added to a group.
*/
STDMETHODIMP
HXPlayer::TrackAdded(UINT16         /*IN*/ uGroupIndex,
                      UINT16        /*IN*/ uTrackIndex,
                      IHXValues*   /*IN*/ pTrack)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    HX_RESULT       theErr = HXR_OK;
    UINT16          uPrefetchSourceIndex = 0;
    char            szDelay[] = "Delay";
    UINT32          ulDelay = 0;
    SourceInfo*     pSourceInfo = NULL;

    IHXGroup*       pThisGroup = NULL;
    IHXPrefetch*   pPrefetch = NULL;

    m_pGroupManager->GetGroup(uGroupIndex, pThisGroup);

    /* Check if a track is added to the group currently played */
    if (uGroupIndex == m_nCurrentGroup &&
        m_pCurrentGroup == pThisGroup)
    {
#if defined(HELIX_FEATURE_PREFETCH)
        // determine whether the track has been prefetched
        if (m_pPrefetchManager &&
            m_pPrefetchManager->Lookup(pTrack, pSourceInfo))
        {
            pSourceInfo->m_pSource->PartOfPrefetchGroup(FALSE);
            if (HXR_OK == m_pCurrentGroup->QueryInterface(IID_IHXPrefetch,
                                                          (void**)&pPrefetch))
            {
                theErr = pPrefetch->RemovePrefetchTrack(pSourceInfo->m_uTrackID);
            }
            HX_RELEASE(pPrefetch);

            pSourceInfo->m_uGroupID = uGroupIndex;
            pSourceInfo->m_uTrackID = uTrackIndex;
            PrepareSourceInfo(pTrack, pSourceInfo);

            pSourceInfo->m_pSource->UpdatePlayTimes(pTrack);

            m_pSourceMap->SetAt((void*)pSourceInfo->m_pSource,
                              (void*)pSourceInfo);

            m_bPlayerWithoutSources = FALSE;
            m_bSourceMapUpdated = TRUE;
            m_bForceStatsUpdate = TRUE;

            m_uNumSourcesActive++;
            m_uNumCurrentSourceNotDone++;

            AdjustPresentationTime();

            InternalPause();
        }
        /* If we are not yet initialized, add tracks to the current source
         * map only if the track is within the fudge factor.
         *
         * This is to fix a bug in SMIL file with multiple sources in seq
         * with outer par.
         * The expected behavior is to start the first source
         * in seq and then initialize the remaining sources. Since we were
         * adding additional tracks to the source map, the player was not
         * getting initialized until ALL the sources in the seq have been
         * initialized. This resulted in massive startup delays.
         */
    else if (!m_bInitialized)
#else
        if (!m_bInitialized)
#endif
        {
            if ((HXR_OK != pTrack->GetPropertyULONG32(szDelay,ulDelay)) ||
                (ulDelay <= m_ulCurrentPlayTime + MIN_DELAYBEFORE_START))
            {
                theErr = OpenTrack(pTrack, uGroupIndex, uTrackIndex);
            }
            else
            {
                if (!m_pPendingTrackList)
                {
                    m_pPendingTrackList = new CHXSimpleList;
                }

                PendingTrackInfo* pPendingTrackInfo =
                    new PendingTrackInfo(uGroupIndex, uTrackIndex, pTrack);

                m_pPendingTrackList->AddTail(pPendingTrackInfo);
            }
        }
        else
        {
            theErr = OpenTrack(pTrack, uGroupIndex, uTrackIndex);
        }

        if (theErr)
        {
            ReportError(NULL, theErr, NULL);
        }
    }
    /* Check if a track is added to the group that is being prefetch */
    else
    {
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
        IHXGroup* pGroup        = NULL;
        UINT16 uCurrentGroup    = 0;
        if (m_bNextGroupStarted &&
            (m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pGroup)
                                                == HXR_OK) &&
            uCurrentGroup == uGroupIndex &&
            pGroup == pThisGroup)
        {
            m_bPartOfNextGroup = TRUE;
            theErr = OpenTrack(pTrack, uGroupIndex, uTrackIndex);
            if (theErr)
            {
                ReportError(NULL, theErr, NULL);
            }
            m_bPartOfNextGroup = FALSE;
        }

        HX_RELEASE(pGroup);
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
    }

    HX_RELEASE(pThisGroup);

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

HX_RESULT
HXPlayer::RepeatTrackAdded(UINT16       /*IN*/ uGroupIndex,
                            UINT16      /*IN*/ uTrackIndex,
                            IHXValues*  /*IN*/ pTrack)
{
#if defined(HELIX_FEATURE_ADVANCEDGROUPMGR) && defined(HELIX_FEATURE_SMIL_REPEAT)
    HX_RESULT           theErr = HXR_OK;
    UINT16              uCurrentGroup   = 0;
    SourceInfo*         pSourceInfo = NULL;
    IHXGroup*           pGroup  = NULL;
    IHXGroup*           pThisGroup = NULL;

    m_pGroupManager->GetGroup(uGroupIndex, pThisGroup);

    if (HXR_OK == GetSourceInfo(uGroupIndex, uTrackIndex, pSourceInfo))
    {
        theErr = pSourceInfo->AppendRepeatRequest(uTrackIndex, pTrack);
        AdjustPresentationTime();
    }
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    else if (m_bNextGroupStarted &&
             (m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pGroup) == HXR_OK) &&
             uCurrentGroup == uGroupIndex &&
             pGroup == pThisGroup)
    {
        m_pNextGroupManager->AddRepeatTrack(uTrackIndex, pTrack);
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
    else
    {
        // XXX HP something is wrong!!
        HX_ASSERT(FALSE);
    }

    HX_RELEASE(pGroup);
    HX_RELEASE(pThisGroup);

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


/************************************************************************
*  Method:
*      IHXGroupSink::TrackRemoved
*  Purpose:
*               Notification of a track being removed from a group.
*/
STDMETHODIMP
HXPlayer::TrackRemoved(UINT16           /*IN*/ uGroupIndex,
                        UINT16          /*IN*/ uTrackIndex,
                        IHXValues*      /*IN*/ pTrack)
{
    return HXR_OK;
}

/************************************************************************
*  Method:
*      IHXGroupSink::TrackStarted
*  Purpose:
*               Notification of a track being started in a group.
*/
STDMETHODIMP
HXPlayer::TrackStarted(UINT16           /*IN*/ uGroupIndex,
                        UINT16          /*IN*/ uTrackIndex,
                        IHXValues*      /*IN*/ pTrack)
{
    return HXR_OK;
}

/************************************************************************
*  Method:
*      IHXGroupSink::TrackStopped
*  Purpose:
*               Notification of a track being stopped in a group.
*/
STDMETHODIMP
HXPlayer::TrackStopped(UINT16           /*IN*/ uGroupIndex,
                        UINT16          /*IN*/ uTrackIndex,
                        IHXValues*      /*IN*/ pTrack)
{
    return HXR_OK;
}

/************************************************************************
*  Method:
*      IHXGroupSink::CurrentGroupSet
*  Purpose:
*               This group is being currently played in the presentation.
*/
STDMETHODIMP
HXPlayer::CurrentGroupSet(UINT16        /*IN*/ uGroupIndex,
                           IHXGroup*   /*IN*/ pGroup)
{
#if defined(HELIX_FEATURE_BASICGROUPMGR)
    HX_RESULT theErr = HXR_OK;

    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();
    /* If we called SetCurrentGroup, ignore this callback */
    m_bIsPresentationClosedToBeSent = FALSE;
    StopAllStreams(END_STOP);
    m_bIsPresentationClosedToBeSent = TRUE;

    ResetGroup();
    m_bInitialized      = FALSE;
    m_bIsDone           = FALSE;
    m_ulActiveSureStreamSource = 0;
    m_bFastStartCheckDone = FALSE;
    m_turboPlayOffReason = TP_OFF_BY_UNKNOWN;

    // uGroupIndex is needed to determine whether destroy the root layout
    // during group switching under nested meta support
    // uGroupIndex is used by IHXPersistentComponentManager::CloseAllRenderers()
    // which is called in CloseAllRenderers()
    CloseAllRenderers(uGroupIndex);

    /* Open this group here */

    /* Ask the next group manager for this group */
    UINT16 uCurrentGroup = 0;
    IHXGroup* pCurGroup = NULL;
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (m_pNextGroupManager->GetCurrentGroup(uCurrentGroup, pCurGroup) == HXR_OK &&
        uCurrentGroup == uGroupIndex && pCurGroup == pGroup)
    {
        SourceInfo*     pSourceInfo = NULL;

        UINT16 uNumSources = m_pNextGroupManager->GetNumSources();
        for (UINT16 i = 0; i < uNumSources; i++)
        {
            m_pNextGroupManager->GetSource(i, pSourceInfo);

            if (pSourceInfo->m_pSource)
            {
                m_pSourceMap->SetAt((void*) pSourceInfo->m_pSource,
                                  (void*) pSourceInfo);

                m_bPlayerWithoutSources = FALSE;
                m_bSourceMapUpdated = TRUE;

                pSourceInfo->m_pSource->PartOfNextGroup(FALSE);

                if (pSourceInfo->m_bTobeInitializedBeforeBegin)
                {
                    m_uNumSourceToBeInitializedBeforeBegin++;
                }

                // update the registries (from NextGroup.* to Player.*)
                UpdateSourceInfo(pSourceInfo,
#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
                                 m_pStats->m_ulRegistryID,
#else
                                 NULL,
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */
                                 pSourceInfo->m_uTrackID);
            }
        }

        m_pNextGroupManager->RemoveAllSources();

        const char* pErrorString = NULL;
        HXSource* pSource        = NULL;
        theErr = m_pNextGroupManager->GetLastError(pSource, pErrorString);

        if (theErr)
        {
            SetLastError(theErr);
        }

        if (m_LastError != HXR_OK)
        {
            m_bIsDone = TRUE;
            ReportError(pSource, m_LastError, pErrorString);
        }
        else
        {
            m_nCurrentGroup = uGroupIndex;
        }

        m_pNextGroupManager->Cleanup();

        /* Get the duration from group properties */
        UINT32 ulGroupDuration = 0;
        IHXValues* pGroupProps = pGroup->GetGroupProperties();
        if (pGroupProps &&
            pGroupProps->GetPropertyULONG32("Duration", ulGroupDuration)
                                                                == HXR_OK)
        {
            m_ulPresentationDuration = ulGroupDuration;
        }

        HX_RELEASE(pGroupProps);

        m_bIsPresentationClosedToBeSent = FALSE;
    }
    else
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
    {
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
        /* Cleanup any next group that we may have started downloading */
        m_pNextGroupManager->Cleanup();
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

        m_nCurrentGroup = uGroupIndex;
        theErr = DoOpenGroup(uGroupIndex);
    }

    if (uGroupIndex == (m_pGroupManager->GetGroupCount() - 1))
    {
        m_bLastGroup = TRUE;
    }
    else
    {
        m_bLastGroup = FALSE;
    }

    m_pCurrentGroup = pGroup;
    m_pCurrentGroup->AddRef();

    m_bNextGroupStarted = FALSE;
    HX_RELEASE(pCurGroup);

    if (!theErr && !m_LastError && m_bUserHasCalledBegin)
    {
        Begin();
    }

    SchedulePlayer();

    if (theErr)
    {
        ReportError(NULL, theErr, NULL);
    }
    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;
    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

/************************************************************************
*  Method:
*      IHXGroupSink::CurrentGroupSet
*  Purpose:
*               This group is set to be played next in the presentation.
*/
HX_RESULT
HXPlayer::NextGroupSet(UINT16   /*IN*/ uGroupIndex)
{
#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    /* Ask the next group manager for this group */
    UINT16 uCurrentGroup = 0;
    IHXGroup* pCurGroup = NULL;
    if (m_pNextGroupManager && m_pNextGroupManager->GetCurrentGroup(uCurrentGroup,
        pCurGroup) == HXR_OK)
    {
        // the next group being set is already the next group, so don't do anything
        if (uCurrentGroup == uGroupIndex)
        {
            return HXR_OK;
        }

        /* Cleanup any next group that we may have started downloading */
        m_pNextGroupManager->Cleanup();
        m_bNextGroupStarted     = FALSE;
    }

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
}

/************************************************************************
*   Method:
*       IHXRendererUpgrade::IsRendererAvailable
*   Purpose:
*       See if a renderer with this mime type has been loaded
*/
STDMETHODIMP_(BOOL)
HXPlayer::IsRendererAvailable(const char* pMimeType)
{
    BOOL bAvailable = FALSE;
#if defined(HELIX_FEATURE_AUTOUPGRADE)
    // create an upgrade collection
    HXUpgradeCollection* pCheckComponent = new HXUpgradeCollection;
    if (pCheckComponent)
    {
        pCheckComponent->AddRef();
        CHXBuffer* pBuffer = new CHXBuffer;
        pBuffer->AddRef();
        pBuffer->Set((BYTE*)pMimeType, strlen(pMimeType)+1);
        // add the component to the list
        pCheckComponent->Add(eUT_Required, pBuffer, 0, 0);
        HX_RELEASE(pBuffer);

        // Request the upgrade handler
        IHXUpgradeHandler* pUpgradeHandler = NULL;
        if(m_pClient &&
            m_pClient->QueryInterface(IID_IHXUpgradeHandler, (void**)&pUpgradeHandler) == HXR_OK)
        {
            // now see if the upgrade handler already has this component
            if(pUpgradeHandler->HasComponents(pCheckComponent) == HXR_OK)
            {
                bAvailable = TRUE;
            }
            HX_RELEASE(pUpgradeHandler);
        }
    }

    HX_RELEASE(pCheckComponent);
#endif /* HELIX_FEATURE_AUTOUPGRADE */

    // return component availability
    return(bAvailable);
}

/************************************************************************
*   Method:
*       IHXRendererUpgrade::ForceUpgrade
*   Purpose:
*       Use the force to upgrade all renderers
*/
STDMETHODIMP
HXPlayer::ForceUpgrade()
{
    return HXR_UNEXPECTED;
}

/************************************************************************
*  Method:
*      IHXLayoutSiteGroupManager::AddLayoutSiteGroup
*  Purpose:
*               Add LSG to the presentation.
*/
STDMETHODIMP
HXPlayer::AddLayoutSiteGroup(IUnknown*  /*IN*/ pLSG)
{
#if defined(HELIX_FEATURE_VIDEO)
    m_bAddLayoutSiteGroupCalled = TRUE;
    SetupLayoutSiteGroup(pLSG, TRUE);
    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_VIDEO */
}

/************************************************************************
*  Method:
*      IHXLayoutSiteGroupManager::RemoveLayoutSiteGroup
*  Purpose:
*               Remove LSG from the presentation.
*/
STDMETHODIMP
HXPlayer::RemoveLayoutSiteGroup(IUnknown* pLSG)
{
#if defined(HELIX_FEATURE_PLAYERNAVIGATOR)
    HX_ASSERT(pLSG);

    IHXSiteUserSupplier*   pSUS = NULL;
    IHXSiteUser*           pSU = NULL;
    BOOL                    bIsPersistent = TRUE;   // assume called by a persistent renderer

    if (HXR_OK == pLSG->QueryInterface(IID_IHXSiteUserSupplier,
                            (void**)&pSUS))
    {
        IHXValues* pSUSProps = NULL;

        BOOL releaseSUS = TRUE;

        if (HXR_OK == pSUS->QueryInterface(IID_IHXValues,
                                (void**)&pSUSProps))
        {
#if defined(HELIX_FEATURE_VIDEO)
            m_pSiteManager->RemoveSitesByLSGName(pSUSProps, /*bIsPersistent*/ FALSE);
            //m_pSiteManager->UnhookByLSGName(pSUS, pSUSProps, bIsPersistent);
#endif //HELIX_FEATURE_VIDEO

            pSUSProps->Release();
        }
        pSUS->Release();
    }
    // If the LSG doesn't support SiteUserSupplier, than see if it supports
    // single instance as a SiteUser...
    else if (HXR_OK == pLSG->QueryInterface(IID_IHXSiteUser,
                            (void**)&pSU))
    {
        IHXValues* pSUProps = NULL;

        if (HXR_OK == pSU->QueryInterface(IID_IHXValues,
                                (void**)&pSUProps))
        {
#if defined(HELIX_FEATURE_VIDEO)
            m_pSiteManager->RemoveSitesByLSGName(pSUProps, /*bIsPersistent*/ FALSE);
            // m_pSiteManager->UnhookByLSGName(pSU, pSUProps, bIsPersistent);
#endif //HELIX_FEATURE_VIDEO

            pSUProps->Release();
        }
        pSU->Release();
    }

    m_bAddLayoutSiteGroupCalled = FALSE;
    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_VIDEO */
}

/*
 * IHXInternalReset method
 */
STDMETHODIMP
HXPlayer::InternalReset(void)
{
    m_bCoreLocked = TRUE;
    m_pCoreMutex->Lock();

    m_bInternalReset = TRUE;
    PausePlayer();
    BeginPlayer();
    m_bInternalReset = FALSE;

    m_pCoreMutex->Unlock();
    m_bCoreLocked = FALSE;

    return HXR_OK;
}

void
HXPlayer::CheckToStartNextGroup(void)
{
    if (m_bLastGroup)
    {
        return;
    }

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    if (m_pGroupManager->GetGroupCount() <= 1)
    {
        m_bLastGroup = TRUE;
        return;
    }

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    /* If all sources have ended, start downloading the next group */
    if (m_uNumCurrentSourceNotDone == 0)
    {
        /* Resume prefetching if the next group already has sources */
        if (m_pNextGroupManager->GetNumSources() > 0)
        {
            UnRegisterCurrentSources();
            m_pNextGroupManager->ContinuePreFetch();
            m_bNextGroupStarted = TRUE;
            return;
        }

        if (m_nCurrentGroup < (m_pGroupManager->GetGroupCount() - 1))
        {
            IHXGroup* pGroup = NULL;
            UINT16 uNextGroup = 0;
            m_pGroupManager->GetNextGroup(uNextGroup);
            HX_RESULT theErr = m_pGroupManager->GetGroup(uNextGroup, pGroup);
            if (!theErr)
            {
                m_pNextGroupManager->SetCurrentGroup(uNextGroup, pGroup);
                HX_RELEASE(pGroup);

                UnRegisterCurrentSources();

                m_bPartOfNextGroup = TRUE;
                theErr = DoOpenGroup(uNextGroup);
                m_bPartOfNextGroup = FALSE;
                m_bNextGroupStarted     = TRUE;

                DEBUG_OUT(this, DOL_TRANSPORT, (s,"Next Group is prefetched: %lu", uNextGroup));

                if (theErr)
                {
                    m_pNextGroupManager->SetLastError(theErr);
                }
            }
        }
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */
#endif /* HELIX_FEATURE_BASICGROUPMGR */
}

void
HXPlayer::AdjustPresentationTime(void)
{
    UINT32 ulSourceDuration = 0;

    // reset presentation duration
    m_ulPresentationDuration = 0;

    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSource);

        // get duration after the source has been initialized
        // to ensure HXSource::AdjustClipTime() was called
        if (pSourceInfo->m_pSource->IsInitialized())
        {
            ulSourceDuration = pSourceInfo->GetActiveDuration();
            m_ulPresentationDuration = max(m_ulPresentationDuration,
                                           ulSourceDuration);
        }
    }

#if defined(HELIX_FEATURE_BASICGROUPMGR)
    // presentation duration is also restrained by its group duration
    // if it exists
    IHXGroup*   pGroup = NULL;
    if (HXR_OK == m_pGroupManager->GetGroup((UINT16)m_nCurrentGroup, pGroup))
    {
        /* Get the duration from group properties */
        UINT32 ulGroupDuration = 0;
        IHXValues* pGroupProps = pGroup->GetGroupProperties();
        if (pGroupProps &&
            HXR_OK == pGroupProps->GetPropertyULONG32("Duration", ulGroupDuration))
        {
            m_ulPresentationDuration = ulGroupDuration;
        }
        HX_RELEASE(pGroupProps);
    }
    HX_RELEASE(pGroup);
#endif /* HELIX_FEATURE_BASICGROUPMGR */

    if (m_pAdviseSink)
    {
        m_pAdviseSink->OnPosLength(m_ulCurrentPlayTime, m_ulPresentationDuration);
    }

    return;
}

void
HXPlayer::SetPresentationTime(UINT32 ulPresentationTime)
{
    m_ulPresentationDuration = ulPresentationTime;
    if (m_pAdviseSink)
    {
        m_pAdviseSink->OnPosLength(m_ulCurrentPlayTime, m_ulPresentationDuration);
    }
}

void
HXPlayer::UpdateSourceActive(void)
{
    m_uNumSourcesActive = 0;

    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    for (; ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        if (pSourceInfo->m_bActive)
        {
            m_uNumSourcesActive++;
        }
    }

    m_uNumCurrentSourceNotDone = m_uNumSourcesActive;
}

HX_RESULT
HXPlayer::UpdateSourceInfo(SourceInfo* pSourceInfo,
                            UINT32 ulParentRegId,
                            UINT16 ulTrackIndex)
{
    HX_RESULT   rc = HXR_OK;
    UINT32      ulRegId = 0;
    IHXBuffer*  pParentName = NULL;

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    // update sourc/stream stats' registry
    if (m_pRegistry && m_pStats &&
        HXR_OK == m_pRegistry->GetPropName(ulParentRegId, pParentName))
    {
        char        szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
        SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Source%ld", pParentName->GetBuffer(), ulTrackIndex);
        // delete this registry if it exists
        ulRegId = m_pRegistry->GetId(szRegName);
        if (ulRegId)
        {
            m_pRegistry->DeleteById(ulRegId);
        }
        // create/update registry
        ulRegId = m_pRegistry->AddComp(szRegName);
        pSourceInfo->m_pSource->UpdateRegistry(ulRegId);

#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

        pSourceInfo->m_uTrackID = ulTrackIndex;

#if defined(HELIX_FEATURE_STATS) && defined(HELIX_FEATURE_REGISTRY)
    }
    HX_RELEASE(pParentName);

    // update renderer stats registry
    pSourceInfo->ReInitializeStats();
#endif /* HELIX_FEATURE_STATS && HELIX_FEATURE_REGISTRY */

    return rc;
}

HX_RESULT
HXPlayer::UpdatePersistentSrcInfo(SourceInfo* pSourceInfo,
                                  UINT32 ulParentRegId,
                                  UINT16 ulTrackIndex)
{
    HX_RESULT   rc = HXR_OK;
    UINT32      ulRegId = 0;
    IHXBuffer*  pParentName = NULL;

#if defined(HELIX_FEATURE_REGISTRY)
    char        szRegName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
    // update sourc/stream stats' registry
    if (m_pRegistry && m_pStats &&
        HXR_OK == m_pRegistry->GetPropName(ulParentRegId, pParentName))
    {
        SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Source%u",
                pParentName->GetBuffer(), ulTrackIndex);

        // delete this registry if it exists
        ulRegId = m_pRegistry->GetId(szRegName);
        if (ulRegId)
        {
            m_pRegistry->DeleteById(ulRegId);
        }

        //Create a new one.
        SafeSprintf(szRegName, MAX_DISPLAY_NAME, "%s.Persistent%u", pParentName->GetBuffer(),
                pSourceInfo->m_ulPersistentComponentSelfID);

        // create/update registry
        ulRegId = m_pRegistry->GetId(szRegName);
        if( !ulRegId )
        {
            ulRegId = m_pRegistry->AddComp(szRegName);
        }
        pSourceInfo->m_pSource->UpdateRegistry(ulRegId);
        pSourceInfo->m_uTrackID = ulTrackIndex;
    }
#endif
    HX_RELEASE(pParentName);

    // update renderer stats registry
    pSourceInfo->ReInitializeStats();

    return rc;
}

HX_RESULT
HXPlayer::SetupAllStreams(void)
{
    HX_RESULT theErr = HXR_OK;
    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    /* Check if we are done. This may be TRUE for empty files */
    for (; !theErr && ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        theErr = pSourceInfo->SetupStreams();
    }

    return theErr;
}

void
HXPlayer::EnterToBeginList(RendererInfo* pRendInfo)
{
    if (m_ToBeginRendererList.IsEmpty())
    {
        m_ToBeginRendererList.AddHead(pRendInfo);
        return;
    }

    RendererInfo*   pTmpRendInfo        = NULL;
    BOOL            earlierPacketFound  = FALSE;

    UINT32 startPos = pRendInfo->m_pStreamInfo->m_ulDelay;

    LISTPOSITION    position = m_ToBeginRendererList.GetTailPosition();
    while (position != NULL && !earlierPacketFound)
    {
        pTmpRendInfo =
            (RendererInfo*) m_ToBeginRendererList.GetPrev(position);

        // If this event is less than or equal to the timestamp
        // then this things are looking ok...
        if (pTmpRendInfo->m_pStreamInfo->m_ulDelay <= startPos)
        {
            // Remember that we found an earlier packet...
            earlierPacketFound = TRUE;

            // If the position is null, then event was the first
            // item in the list, and we need to do some fancy footwork...
            if (!position)
            {
                POSITION theHead = m_ToBeginRendererList.GetHeadPosition();
                m_ToBeginRendererList.InsertAfter(theHead,pRendInfo);
            }
            // otherwise, roll ahead one...
            else
            {
                m_ToBeginRendererList.GetNext(position);
                // Now if the position is null, then event was the last
                // item in the list, and we need to do some more fancy footwork...
                if (!position)
                {
                    m_ToBeginRendererList.AddTail(pRendInfo);
                }
                else
                // otherwise, we have a normal case and we want to insert
                // right after the position of event
                {
                    m_ToBeginRendererList.InsertAfter(position,pRendInfo);
                }
            }

            // We don't need to search any more...
            break; // while
        }
    } // end while...

    // If we didn't find an earlier packet, then we should insert at
    // the head of the event list...
    if (!earlierPacketFound)
    {
        m_ToBeginRendererList.AddHead(pRendInfo);
    }
}

HX_RESULT
HXPlayer::CheckBeginList(void)
{
    RendererInfo* pRendInfo = (RendererInfo*) m_ToBeginRendererList.GetHead();
    if ((m_ulCurrentPlayTime < pRendInfo->m_pStreamInfo->m_ulDelay &&
        pRendInfo->m_pStreamInfo->m_ulDelay - m_ulCurrentPlayTime <=
        BEGIN_SYNC_FUDGE_FACTOR) ||
        pRendInfo->m_pStreamInfo->m_ulDelay <= m_ulCurrentPlayTime)
    {
        /* Send Begins to all the scheduled renderers */
        LISTPOSITION lPos = m_ToBeginRendererList.GetHeadPosition();

        while (lPos)
        {
            pRendInfo = (RendererInfo*) m_ToBeginRendererList.GetAt(lPos);
            if ((pRendInfo->m_bInterruptSafe || !m_pEngine->AtInterruptTime()) &&
                ((m_ulCurrentPlayTime < pRendInfo->m_pStreamInfo->m_ulDelay &&
                pRendInfo->m_pStreamInfo->m_ulDelay - m_ulCurrentPlayTime <=
                BEGIN_SYNC_FUDGE_FACTOR) ||
                pRendInfo->m_pStreamInfo->m_ulDelay <= m_ulCurrentPlayTime))
            {
                pRendInfo->m_bInitialBeginToBeSent  = FALSE;
                pRendInfo->m_pRenderer->OnBegin(m_ulCurrentPlayTime);
                lPos = m_ToBeginRendererList.RemoveAt(lPos);
            }
            else
            {
                break;
            }
        }
    }

    return HXR_OK;
}

void
HXPlayer::RemoveFromPendingList(RendererInfo* pRendInfo)
{
    LISTPOSITION lPos = NULL;

    lPos = m_ToBeginRendererList.Find((void*) pRendInfo);
    if (lPos)
    {
        m_ToBeginRendererList.RemoveAt(lPos);
    }
}

void
HXPlayer::UnregisterNonActiveSources()
{
    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    /* Check if we are done. This may be TRUE for empty files */
    for (; !m_bIsDone && ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        if (pSourceInfo->m_pSource &&
            (pSourceInfo->m_pSource->IsSourceDone() ||
            pSourceInfo->m_pSource->IsDelayed()))
        {
            pSourceInfo->UnRegister();
            pSourceInfo->m_pSource->AdjustClipBandwidthStats(FALSE);
        }
    }
}


/*
 *  Purpose: Shutdown all the renderers/fileformats
 */
void
HXPlayer::ShutDown(void)
{
    /* If we are not in a STOP state, do an internal stop */
    if (!m_bIsDone)
    {
        m_bIsPresentationClosedToBeSent = FALSE;
        StopPlayer(END_STOP);
    }

    CloseAllRenderers(m_nCurrentGroup);
}


BOOL
HXPlayer::AreAllSourcesSeekable(void)
{
    CHXMapPtrToPtr::Iterator ndxSource = m_pSourceMap->Begin();
    for (; ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        SourceInfo* pSourceInfo = (SourceInfo*)(*ndxSource);
        HXSource * pSource = pSourceInfo->m_pSource;

        if(!pSource)
        {
            continue;
        }

        /* If any one source is non-seekable, entire presentation
         * is non-seekable
         */
        if (!pSource->IsSeekable())
        {
            return FALSE;
        }
    }

    return TRUE;
}

void
HXPlayer::RegisterSourcesDone()
{
#if defined(HELIX_FEATURE_ASM)
    /* We are done Registering Sources with ASM Bandwidth Manager */
    HX_ASSERT(m_pBandwidthMgr);

    m_pBandwidthMgr->RegisterSourcesDone();

    if (m_pBandwidthMgr->NotEnoughBandwidth() == TRUE)
    {
        SetLastError(HXR_NOTENOUGH_BANDWIDTH);
    }
#endif /* HELIX_FEATURE_ASM */
}

BOOL
HXPlayer::CanBeStarted(HXSource* pSource, SourceInfo* pThisSourceInfo, BOOL m_bPartOfNextGroup)
{
    UINT32      ulDelay             = pSource->GetDelay();

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
    if (m_bPartOfNextGroup && m_pNextGroupManager)
    {
        return m_pNextGroupManager->CanBeStarted(pSource, pThisSourceInfo);
    }
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

    if ((ulDelay < m_ulCurrentPlayTime)                             ||
        (ulDelay - m_ulCurrentPlayTime <= MIN_DELAYBEFORE_START)    ||
        !pThisSourceInfo)
    {
        return TRUE;
    }

    // XXX HP only start when we are in playing mode
    // this fixed b#55865 - extreme long startup time on sequence of image
    // files
    if (!m_bIsPlaying)
    {
        return FALSE;
    }

    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    /* Check if we are done. This may be TRUE for empty files */
    for (; ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        if (!pSourceInfo->m_pSource ||
            pSourceInfo->m_pSource->IsSourceDone() ||
            !pSourceInfo->m_pSource->IsInitialized())
        {
            continue;
        }

#ifdef SEQ_DEPENDENCY
        int iRetVal = 0;
        if (!pSourceInfo->m_pSource->IsLive() &&
            IsDependent(pThisSourceInfo, pSourceInfo) &&
            !pSourceInfo->m_pSource->IsSourceDone())
        {
            return FALSE;
        }
#else
        if (!pSourceInfo->m_pSource->IsLive() &&
             pSourceInfo->m_pSource->GetDuration() <= ulDelay &&
            !pSourceInfo->m_pSource->IsSourceDone())
        {
            return FALSE;
        }
#endif /*SEQ_DEPENDENCY*/

    }

    return TRUE;
}

#ifdef SEQ_DEPENDENCY
BOOL
HXPlayer::IsDependent(SourceInfo* pThisSourceInfo, SourceInfo* pSourceInfo)
{
    if (!pThisSourceInfo                            ||
        !pSourceInfo                                ||
        pThisSourceInfo->m_uNumDependencies == 0    ||
        pSourceInfo->m_uNumDependencies     == 0)
    {
        return FALSE;
    }

    UINT16 uDepdencyNum = 0;

    while (uDepdencyNum < pThisSourceInfo->m_uNumDependencies &&
           uDepdencyNum < pSourceInfo->m_uNumDependencies)
    {
        if (pThisSourceInfo->m_pDependNode[uDepdencyNum] ==
            pSourceInfo->m_pDependNode[uDepdencyNum])
        {
            uDepdencyNum++;
        }
        else
        {

        }
    }

    if (uDepdencyNum < pThisSourceInfo->m_uNumDependencies &&
        uDepdencyNum >= pSourceInfo->m_uNumDependencies
    {
        return FALSE;
    }

    return TRUE;
}
#endif /*SEQ_DEPENDENCY*/

void
HXPlayer::EndOfSource(HXSource* pSource)
{
    BOOL bAtLeastOneSourceToBeResumed = FALSE;

    CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
    /* Check if we are done. This may be TRUE for empty files */
    for (; ndxSources != m_pSourceMap->End(); ++ndxSources)
    {
        SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
        if (!pSourceInfo->m_pSource)
        {
            continue;
        }

        if (pSourceInfo->m_pSource->TryResume())
        {
            bAtLeastOneSourceToBeResumed = TRUE;
        }
    }

    if (bAtLeastOneSourceToBeResumed)
    {
        RegisterSourcesDone();

        ndxSources = m_pSourceMap->Begin();
        /* Check if we are done. This may be TRUE for empty files */
        for (; ndxSources != m_pSourceMap->End(); ++ndxSources)
        {
            SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
            if (!pSourceInfo->m_pSource)
            {
                continue;
            }

            if (pSourceInfo->m_pSource->IsResumePending())
            {
                pSourceInfo->m_pSource->DoResume();
            }
        }
    }
}

void
HXPlayer::SureStreamSourceRegistered(SourceInfo* pSourceInfo)
{
    if (m_nCurrentGroup == pSourceInfo->m_uGroupID)
    {
        m_ulActiveSureStreamSource++;

        if (m_ulActiveSureStreamSource > 1 && m_bFastStart)
        {
            DEBUG_OUT(this, DOL_TRANSPORT, (s,"SureStreams > 1 - TurboPlay Off"));
            m_bFastStart = FALSE;

            CHXMapPtrToPtr::Iterator ndxSources = m_pSourceMap->Begin();
            for (;ndxSources != m_pSourceMap->End(); ++ndxSources)
            {
                SourceInfo* pSourceInfo = (SourceInfo*) (*ndxSources);
                if (pSourceInfo->m_bIsRegisterSourceDone &&
                    pSourceInfo->m_pSource)
                {
                    pSourceInfo->m_pSource->LeaveFastStart(TP_OFF_BY_MULTISURESTREAMS);
                }
            }
        }
    }

    return;
}

void
HXPlayer::SureStreamSourceUnRegistered(SourceInfo* pSourceInfo)
{
    if (m_nCurrentGroup == pSourceInfo->m_uGroupID)
    {
        m_ulActiveSureStreamSource--;
    }

    return;
}

BOOL
HXPlayer::CanBeFastStarted(SourceInfo* pSourceInfo)
{
    BOOL                bFastStart = TRUE;
    BOOL                bTurboPlay = FALSE;
    IHXBuffer*          pBuffer    = NULL;
    IHXUpgradeHandler*  pHandler   = NULL;
    UINT16              uNextGroup = 0;
    IHXGroup*           pNextGroup = NULL;

#if defined(__TCS__)
    m_turboPlayOffReason = TP_OFF_BY_PREFERENCE;
    m_bFastStart = FALSE;
    goto cleanup;
#endif /* __TCS__ */

    // check if the source is within the current group
    if (m_nCurrentGroup != pSourceInfo->m_uGroupID)
    {
        bFastStart = FALSE;

#if defined(HELIX_FEATURE_NEXTGROUPMGR)
        // we want faststart the next group if we are done with the current one
        if (m_bNextGroupStarted &&
            m_pNextGroupManager &&
            HXR_OK == m_pNextGroupManager->GetCurrentGroup(uNextGroup, pNextGroup))
        {
            if (uNextGroup == pSourceInfo->m_uGroupID)
            {
                bFastStart = TRUE;
            }
        }
        HX_RELEASE(pNextGroup);
#endif /* HELIX_FEATURE_NEXTGROUPMGR */

        goto cleanup;
    }
    else if (!m_bFastStartCheckDone)
    {
        m_bFastStartCheckDone = TRUE;
        m_bFastStart = TRUE;

        // check the preference
        ReadPrefBOOL(m_pPreferences, "TurboPlay", bTurboPlay);
        if (!bTurboPlay)
        {
            DEBUG_OUT(this, DOL_TRANSPORT, (s,"Preference check - TurboPlay Off"));
            m_turboPlayOffReason = TP_OFF_BY_PREFERENCE;
            m_bFastStart = FALSE;
            goto cleanup;
        }

    }
    else if (m_ulActiveSureStreamSource > 1)
    {
        m_turboPlayOffReason = TP_OFF_BY_MULTISURESTREAMS;
        bFastStart = FALSE;
        goto cleanup;
    }

  cleanup:

    HX_RELEASE(pHandler);
    HX_RELEASE(pBuffer);

    return (m_bFastStart & bFastStart);
}

void
HXPlayer::UpdateCurrentPlayTime( ULONG32 ulCurrentPlayTime )
{
    m_ulCurrentPlayTime = ulCurrentPlayTime;
#if defined(_MACINTOSH) || defined(_MAC_UNIX)
    if ( IsMacInCooperativeThread() )
    {
        m_ulCurrentSystemPlayTime = ulCurrentPlayTime;
    }
#endif
}

void
HXPlayer::SendPostSeekIfNecessary(RendererInfo* pRendererInfo)
{
    if (pRendererInfo->m_BufferingReason == BUFFERING_SEEK ||
        pRendererInfo->m_BufferingReason == BUFFERING_LIVE_PAUSE)
    {
        pRendererInfo->m_BufferingReason = BUFFERING_CONGESTION;
        pRendererInfo->m_pRenderer->OnPostSeek(
                pRendererInfo->m_pStreamInfo->m_ulTimeBeforeSeek,
                pRendererInfo->m_pStreamInfo->m_ulTimeAfterSeek);

        pRendererInfo->m_pStreamInfo->m_pStream->m_bPostSeekToBeSent = FALSE;
    }
}

BOOL
HXPlayer::ScheduleOnTimeSync()
{
    BOOL            bResult = FALSE;
    BOOL            bDurationTimeSyncAllSent = FALSE;
    ULONG32         ulAudioTime = 0;
    SourceInfo*     pSourceInfo = NULL;
    CHXMapPtrToPtr::Iterator    ndxSource;

    if (m_pAudioPlayer)
    {
        ulAudioTime = m_pAudioPlayer->GetCurrentPlayBackTime();
    }

#if defined(HELIX_FEATURE_NESTEDMETA)
    m_pPersistentComponentManager->OnTimeSync(ulAudioTime);
#endif /* HELIX_FEATURE_NESTEDMETA */

    ndxSource = m_pSourceMap->Begin();
    for (;ndxSource != m_pSourceMap->End(); ++ndxSource)
    {
        pSourceInfo = (SourceInfo*)(*ndxSource);

        if (!DurationTimeSyncAllSent(pSourceInfo))
        {
            pSourceInfo->OnTimeSync( ulAudioTime );

            bDurationTimeSyncAllSent = DurationTimeSyncAllSent(pSourceInfo);

            if (!pSourceInfo->m_bDurationTimeSyncScheduled &&
                !bDurationTimeSyncAllSent)
            {
                pSourceInfo->m_bDurationTimeSyncScheduled = TRUE;
                bResult = TRUE;
                goto cleanup;
            }
        }
    }

cleanup:

    return bResult;
}

BOOL
HXPlayer::DurationTimeSyncAllSent(SourceInfo* pSourceInfo)
{
    BOOL    bResult = TRUE;

    RendererInfo* pRendInfo = NULL;
    CHXMapLongToObj::Iterator   ndxRend;

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

        if (!pRendInfo->m_bDurationTimeSyncSent)
        {
            bResult = FALSE;
            break;
        }
    }

    return bResult;
}

void
HXPlayer::DisableScreenSaver()
{
    return;
}

void HXPlayer::RemovePendingCallback(CHXGenericCallback* pCB)
{
    if (pCB && 
        pCB->GetPendingCallback() &&
        m_pScheduler)
    {
        m_pScheduler->Remove(pCB->GetPendingCallback());
        pCB->CallbackCanceled();
    }
}

#ifndef _WIN16
#if defined(HELIX_FEATURE_AUTHENTICATION)

_CListOfWrapped_IUnknown_Node::_CListOfWrapped_IUnknown_Node()
  : m_plocPrev(NULL)
  , m_plocNext(NULL)
{
}

_CListOfWrapped_IUnknown_Node::~_CListOfWrapped_IUnknown_Node()
{
    Remove();
}

void
_CListOfWrapped_IUnknown_Node::Remove()
{
    if(m_plocPrev)
    {
        m_plocPrev->next(m_plocNext);
    }

    if(m_plocNext)
    {
        m_plocNext->prev(m_plocPrev);
    }
}

void
_CListOfWrapped_IUnknown_Node::Insert(_CListOfWrapped_IUnknown_Node& rlocnNew)
{
    rlocnNew.next(this);
    rlocnNew.prev(m_plocPrev);

    if(m_plocPrev)
    {
        m_plocPrev->next(&rlocnNew);
    }

    m_plocPrev = &rlocnNew;
}

Wrapped_IUnknown&
_CListOfWrapped_IUnknown_Node::value()
{
    return m_clsValue;
}

const Wrapped_IUnknown&
_CListOfWrapped_IUnknown_Node::value() const
{
    return m_clsValue;
}

void
_CListOfWrapped_IUnknown_Node::value(const Wrapped_IUnknown& rclsNewValue)
{
    m_clsValue = rclsNewValue;
}

_CListOfWrapped_IUnknown_Node&
_CListOfWrapped_IUnknown_Node::operator=(const Wrapped_IUnknown& rclsNewValue)
{
    m_clsValue = rclsNewValue;
    return *this;
}

_CListOfWrapped_IUnknown_Node*
_CListOfWrapped_IUnknown_Node::next() const
{
    return m_plocNext;
}

void
_CListOfWrapped_IUnknown_Node::next(_CListOfWrapped_IUnknown_Node* plocnNew)
{
    m_plocNext = plocnNew;
}

_CListOfWrapped_IUnknown_Node*
_CListOfWrapped_IUnknown_Node::prev() const
{
    return m_plocPrev;
}

void
_CListOfWrapped_IUnknown_Node::prev(_CListOfWrapped_IUnknown_Node* plocnNew)
{
    m_plocPrev = plocnNew;
}

_CListOfWrapped_IUnknown_::_CListOfWrapped_IUnknown_()
{
    m_locnREnd.next(&m_locnEnd);
    m_locnEnd.prev(&m_locnREnd);
}

_CListOfWrapped_IUnknown_::_CListOfWrapped_IUnknown_(const _CListOfWrapped_IUnknown_& rlocOther)
{
    m_locnREnd.next(&m_locnEnd);
    m_locnEnd.prev(&m_locnREnd);

    _copy(rlocOther);
}

_CListOfWrapped_IUnknown_::~_CListOfWrapped_IUnknown_()
{
    empty();
}

_CListOfWrapped_IUnknown_&
_CListOfWrapped_IUnknown_::operator=(const _CListOfWrapped_IUnknown_& rlocOther)
{
    empty();
    _copy(rlocOther);

    return *this;
}

void
_CListOfWrapped_IUnknown_::_copy(const _CListOfWrapped_IUnknown_& rlocOther)
{
    iterator itOther;

    for
    (
        itOther = rlocOther.begin();
        itOther != rlocOther.end();
        ++itOther
    )
    {
        insert(end(), *itOther);
    }
}

_CListOfWrapped_IUnknown_::iterator
_CListOfWrapped_IUnknown_::begin()
{
    return iterator(*(m_locnREnd.next()));
}

const _CListOfWrapped_IUnknown_::iterator
_CListOfWrapped_IUnknown_::begin() const
{
    return iterator(*(m_locnREnd.next()));
}

_CListOfWrapped_IUnknown_::iterator
_CListOfWrapped_IUnknown_::end()
{
    return iterator(m_locnEnd);
}

const _CListOfWrapped_IUnknown_::iterator
_CListOfWrapped_IUnknown_::end() const
{
    return iterator(m_locnEnd);
}

_CListOfWrapped_IUnknown_::reverse_iterator
_CListOfWrapped_IUnknown_::rbegin()
{
    return reverse_iterator(*(m_locnEnd.prev()));
}

const _CListOfWrapped_IUnknown_::reverse_iterator
_CListOfWrapped_IUnknown_::rbegin() const
{
    return const_reverse_iterator(*(m_locnEnd.prev()));
}

_CListOfWrapped_IUnknown_::reverse_iterator
_CListOfWrapped_IUnknown_::rend()
{
    return reverse_iterator(m_locnREnd);
}

const _CListOfWrapped_IUnknown_::reverse_iterator
_CListOfWrapped_IUnknown_::rend() const
{
    return const_reverse_iterator(*((const _CListOfWrapped_IUnknown_Node *)&m_locnREnd));
}

_CListOfWrapped_IUnknown_::iterator
_CListOfWrapped_IUnknown_::insert(iterator itBefore, const Wrapped_IUnknown& rclsNew)
{
    _CListOfWrapped_IUnknown_Node* plocnNew = new _CListOfWrapped_IUnknown_Node;

    HX_ASSERT(plocnNew);

    *plocnNew = rclsNew;

    itBefore.m_plocCurrent->Insert(*plocnNew);

    return iterator(*plocnNew);
}

void
_CListOfWrapped_IUnknown_::insert
(
    iterator itBefore,
    const iterator itFirst,
    const iterator itLast
)
{
    iterator itOther;
    _CListOfWrapped_IUnknown_Node* plocnNew;

    for (itOther = itFirst; itOther != itLast; ++itOther)
    {
        plocnNew = new _CListOfWrapped_IUnknown_Node;

        HX_ASSERT(plocnNew);

        *plocnNew = *itOther;

        itBefore.m_plocCurrent->Insert(*plocnNew);
    }
}

void
_CListOfWrapped_IUnknown_::remove(iterator itThis)
{
    if
    (
        itThis.m_plocCurrent == &m_locnEnd ||
        itThis.m_plocCurrent == &m_locnREnd
    )
    {
        return;
    }

    _CListOfWrapped_IUnknown_Node* plocnOld;

    plocnOld = itThis.m_plocCurrent;

    ++itThis;

    plocnOld->Remove();

    delete plocnOld;
}

void
_CListOfWrapped_IUnknown_::remove(iterator itFirst, iterator itLast)
{
    if
    (
        itFirst.m_plocCurrent == &m_locnEnd ||
        itFirst.m_plocCurrent == &m_locnREnd
    )
    {
        return;
    }

    iterator itOther;
    _CListOfWrapped_IUnknown_Node* plocnOld;

    for (itOther = itFirst; itOther != itLast;)
    {
        plocnOld = itOther.m_plocCurrent;

        ++itOther;

        plocnOld->Remove();

        delete plocnOld;
    }
}

void
_CListOfWrapped_IUnknown_::empty()
{
    remove(begin(), end());
}

_CListIteratorWrapped_IUnknown_::_CListIteratorWrapped_IUnknown_()
  : m_plocCurrent(NULL)
{
}

_CListIteratorWrapped_IUnknown_::_CListIteratorWrapped_IUnknown_
(
    const _CListOfWrapped_IUnknown_Node& rlocnNewLocation
)
  : m_plocCurrent((_CListOfWrapped_IUnknown_Node*)&rlocnNewLocation)
{
}

_CListIteratorWrapped_IUnknown_::_CListIteratorWrapped_IUnknown_
(
    const _CListIteratorWrapped_IUnknown_& rliocOther
)
  : m_plocCurrent(rliocOther.m_plocCurrent)
{
}

_CListIteratorWrapped_IUnknown_::~_CListIteratorWrapped_IUnknown_()
{
}

_CListIteratorWrapped_IUnknown_&
_CListIteratorWrapped_IUnknown_::operator=
(
    const _CListIteratorWrapped_IUnknown_& rliocOther
)
{
    m_plocCurrent = rliocOther.m_plocCurrent;

    return *this;
}

Wrapped_IUnknown&
_CListIteratorWrapped_IUnknown_::operator*()
{
    HX_ASSERT(m_plocCurrent);
    return m_plocCurrent->value();
}

_CListIteratorWrapped_IUnknown_&
_CListIteratorWrapped_IUnknown_::operator=(const Wrapped_IUnknown& rclsNewValue)
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent->value(rclsNewValue);

    return *this;
}

_CListIteratorWrapped_IUnknown_&
_CListIteratorWrapped_IUnknown_::operator++()
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent = m_plocCurrent->next();

    return *this;
}

const _CListIteratorWrapped_IUnknown_
_CListIteratorWrapped_IUnknown_::operator++(int)
{
    _CListIteratorWrapped_IUnknown_ liocRet(*this);

    ++(*this);

    return liocRet;
}

_CListIteratorWrapped_IUnknown_&
_CListIteratorWrapped_IUnknown_::operator--()
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent = m_plocCurrent->prev();

    return *this;
}

const _CListIteratorWrapped_IUnknown_
_CListIteratorWrapped_IUnknown_::operator--(int)
{
    _CListIteratorWrapped_IUnknown_ liocRet(*this);

    --(*this);

    return liocRet;
}

BOOL operator==
(
    const _CListIteratorWrapped_IUnknown_& rliocLeft,
    const _CListIteratorWrapped_IUnknown_& rliocRight
)
{
    return (rliocLeft.m_plocCurrent == rliocRight.m_plocCurrent);
}

BOOL operator!=
(
    const _CListIteratorWrapped_IUnknown_& rliocLeft,
    const _CListIteratorWrapped_IUnknown_& rliocRight
)
{
    return (rliocLeft.m_plocCurrent != rliocRight.m_plocCurrent);
}

_CListReverseIteratorWrapped_IUnknown_::_CListReverseIteratorWrapped_IUnknown_()
  : m_plocCurrent(NULL)
{
}

_CListReverseIteratorWrapped_IUnknown_::_CListReverseIteratorWrapped_IUnknown_
(
    const _CListOfWrapped_IUnknown_Node& rlocnNewLocation
)
  : m_plocCurrent((_CListOfWrapped_IUnknown_Node*)&rlocnNewLocation)
{
}

_CListReverseIteratorWrapped_IUnknown_::_CListReverseIteratorWrapped_IUnknown_
(
    const _CListReverseIteratorWrapped_IUnknown_& rlriocOther
)
  : m_plocCurrent(rlriocOther.m_plocCurrent)
{
}

_CListReverseIteratorWrapped_IUnknown_::~_CListReverseIteratorWrapped_IUnknown_()
{
}

_CListReverseIteratorWrapped_IUnknown_&
_CListReverseIteratorWrapped_IUnknown_::operator=
(
    const _CListReverseIteratorWrapped_IUnknown_& rlriocOther
)
{
    m_plocCurrent = rlriocOther.m_plocCurrent;
    return *this;
}

Wrapped_IUnknown&
_CListReverseIteratorWrapped_IUnknown_::operator*()
{
    HX_ASSERT(m_plocCurrent);
    return m_plocCurrent->value();
}

_CListReverseIteratorWrapped_IUnknown_&
_CListReverseIteratorWrapped_IUnknown_::operator=(const Wrapped_IUnknown& rclsNewValue)
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent->value(rclsNewValue);

    return *this;
}

_CListReverseIteratorWrapped_IUnknown_&
_CListReverseIteratorWrapped_IUnknown_::operator++()
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent = m_plocCurrent->prev();

    return *this;
}

const _CListReverseIteratorWrapped_IUnknown_
_CListReverseIteratorWrapped_IUnknown_::operator++(int)
{
    _CListReverseIteratorWrapped_IUnknown_ lriocRet(*this);

    ++(*this);

    return lriocRet;
}

_CListReverseIteratorWrapped_IUnknown_&
_CListReverseIteratorWrapped_IUnknown_::operator--()
{
    if(!m_plocCurrent)
        return *this;

    m_plocCurrent = m_plocCurrent->next();

    return *this;
}

const _CListReverseIteratorWrapped_IUnknown_
_CListReverseIteratorWrapped_IUnknown_::operator--(int)
{
    _CListReverseIteratorWrapped_IUnknown_ lriocRet(*this);

    --(*this);

    return lriocRet;
}

BOOL operator==
(
    const _CListReverseIteratorWrapped_IUnknown_& rlriocLeft,
    const _CListReverseIteratorWrapped_IUnknown_& rlriocRight
)
{
    return (rlriocLeft.m_plocCurrent == rlriocRight.m_plocCurrent);
}

BOOL operator!=
(
    const _CListReverseIteratorWrapped_IUnknown_& rlriocLeft,
    const _CListReverseIteratorWrapped_IUnknown_& rlriocRight
)
{
    return (rlriocLeft.m_plocCurrent != rlriocRight.m_plocCurrent);
}
#endif /* HELIX_FEATURE_AUTHENTICATION */

_CHXAuthenticationRequests::_CHXAuthenticationRequests()
    : m_pMutexProtectList(NULL)
    , m_bUIShowing(FALSE)
{
#ifdef HELIX_FEATURE_AUTHENTICATION
#ifdef THREADS_SUPPORTED
    HXMutex::MakeMutex(m_pMutexProtectList);
#else
    HXMutex::MakeStubMutex(m_pMutexProtectList);
#endif
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

_CHXAuthenticationRequests::~_CHXAuthenticationRequests()
{
#ifdef HELIX_FEATURE_AUTHENTICATION
    HX_DELETE(m_pMutexProtectList);
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

HX_RESULT
_CHXAuthenticationRequests::Add(HXPlayer* pPlayerRequester,
        IHXAuthenticationManagerResponse* pAuthenticationManagerResponseRequester,
        IHXValues* pAuthenticationHeaderValues)
{
#ifdef HELIX_FEATURE_AUTHENTICATION
    BOOL bShowUI = FALSE;
    IHXAuthenticationManager* pAuthenticationManagerClient = NULL;
    IHXAuthenticationManager2* pAuthenticationManagerClient2 = NULL;

    pPlayerRequester->m_pClient->QueryInterface(IID_IHXAuthenticationManager2, (void**)&pAuthenticationManagerClient2);

    if (pAuthenticationManagerClient2)
    {
        HX_ASSERT(pPlayerRequester);
        if (pAuthenticationManagerClient2 == (IHXAuthenticationManager2*)pPlayerRequester)
        {
            HX_RELEASE(pAuthenticationManagerClient2);
            pAuthenticationManagerClient2 = NULL;
        }
    }

    if (!pAuthenticationManagerClient2)
    {

        pPlayerRequester->m_pClient->QueryInterface
        (
            IID_IHXAuthenticationManager,
            (void**)&pAuthenticationManagerClient
        );

    }

    if (!pAuthenticationManagerClient && !pAuthenticationManagerClient2)
    {
        return pAuthenticationManagerResponseRequester->AuthenticationRequestDone
        (
            HXR_UNEXPECTED,
            NULL,
            NULL
        );
    }

    HX_ASSERT(pAuthenticationManagerClient || pAuthenticationManagerClient2); // we want one...
    HX_ASSERT(!(pAuthenticationManagerClient && pAuthenticationManagerClient2)); // .. but not both

    // Don't allow iterating while we are adding.
    m_pMutexProtectList->Lock();

    m_ListOfIUnknownRequesters.insert(m_ListOfIUnknownRequesters.end(), (IUnknown*)pAuthenticationManagerResponseRequester);

    if (!m_bUIShowing)
    {
        bShowUI = m_bUIShowing = TRUE;
    }

    m_pMutexProtectList->Unlock();

    if (bShowUI)
    {
        IHXInterruptSafe* pInterruptSafe = NULL;
        if (pAuthenticationManagerClient) pAuthenticationManagerClient->QueryInterface(IID_IHXInterruptSafe,
                                                     (void**) &pInterruptSafe);
        if (pAuthenticationManagerClient2) pAuthenticationManagerClient2->QueryInterface(IID_IHXInterruptSafe,
                                                        (void**) &pInterruptSafe);

        if (!pPlayerRequester->m_pEngine->AtInterruptTime() ||
                      (pInterruptSafe && pInterruptSafe->IsInterruptSafe()))
        {
            /* Remove any pending callback */
            pPlayerRequester->RemovePendingCallback(pPlayerRequester->m_pAuthenticationCallback);

            if (pAuthenticationManagerClient)
            {
                pAuthenticationManagerClient->HandleAuthenticationRequest
                            (
                                pPlayerRequester
                            );
            }

            if (pAuthenticationManagerClient2)
            {
                pAuthenticationManagerClient2->HandleAuthenticationRequest2
                            (
                                pPlayerRequester,
                                pAuthenticationHeaderValues
                            );
            }
        }
        else
        {
            m_bUIShowing = FALSE;

            /*
             * Schedule a callback to request authentication at
             * non-interrupt time
             */
            if (pPlayerRequester->m_pAuthenticationCallback &&
                !pPlayerRequester->m_pAuthenticationCallback->GetPendingCallback())
            {
                pPlayerRequester->m_pAuthenticationCallback->CallbackScheduled(
                    pPlayerRequester->m_pScheduler->RelativeEnter(pPlayerRequester->m_pAuthenticationCallback, 0));
            }
        }

        HX_RELEASE(pInterruptSafe);
    }

    HX_RELEASE(pAuthenticationManagerClient);
    HX_RELEASE(pAuthenticationManagerClient2);

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

HX_RESULT
_CHXAuthenticationRequests::SatisfyPending
(
    HX_RESULT ResultStatus,
    const char* pCharUser,
    const char* pCharPassword
)
{
#ifdef HELIX_FEATURE_AUTHENTICATION
    _CListOfWrapped_IUnknown_::iterator ListOfIUnknownIteratorCurrentRequester;
    IUnknown* pUnknownRequester = NULL;
    IHXAuthenticationManagerResponse* pAuthenticationManagerResponseRequester = NULL;

    // Don't allow add's while we are iterating.
    m_pMutexProtectList->Lock();

    m_bUIShowing = FALSE;

    for
    (
        ListOfIUnknownIteratorCurrentRequester = m_ListOfIUnknownRequesters.begin();
        ListOfIUnknownIteratorCurrentRequester != m_ListOfIUnknownRequesters.end();
        ++ListOfIUnknownIteratorCurrentRequester
    )
    {
        pUnknownRequester = (*ListOfIUnknownIteratorCurrentRequester).wrapped_ptr();

        if (pUnknownRequester)
        {
            pUnknownRequester->QueryInterface
            (
                IID_IHXAuthenticationManagerResponse,
                (void**)&pAuthenticationManagerResponseRequester
            );

            if (pAuthenticationManagerResponseRequester)
            {
                pAuthenticationManagerResponseRequester->AuthenticationRequestDone
                (
                    ResultStatus,
                    pCharUser,
                    pCharPassword
                );
            }
        }

        HX_RELEASE(pAuthenticationManagerResponseRequester);
        pUnknownRequester = NULL;
    }
    m_ListOfIUnknownRequesters.empty();

    m_pMutexProtectList->Unlock();

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_AUTHENTICATION */
}

void
_CHXAuthenticationRequests::ClearPendingList()
{
#ifdef HELIX_FEATURE_AUTHENTICATION
    m_ListOfIUnknownRequesters.empty();
#endif /* HELIX_FEATURE_AUTHENTICATION */
}
#endif /* _WIN16 */

HX_RESULT
HXPlayer::AdjustSeekOnRepeatedSource(SourceInfo*   pSourceInfo,
                                      UINT32        ulSeekTime)
{
#if defined(HELIX_FEATURE_SMIL_REPEAT)
    HX_RESULT   theErr = HXR_OK;
    SourceInfo* pAdjustedSourceInfo = NULL;

    pAdjustedSourceInfo = pSourceInfo->DoAdjustSeek(ulSeekTime);

    if (pAdjustedSourceInfo == pSourceInfo)
    {
        theErr = pSourceInfo->m_pSource->DoSeek(ulSeekTime);
    }
    else
    {
        m_pSourceMap->RemoveKey(pSourceInfo->m_pSource);
        m_pSourceMap->SetAt((void*)pAdjustedSourceInfo->m_pSource,
                          (void*)pAdjustedSourceInfo);

        m_bSourceMapUpdated = TRUE;
        m_bForceStatsUpdate = TRUE;

        if (pAdjustedSourceInfo->m_bTobeInitializedBeforeBegin)
        {
            m_uNumSourceToBeInitializedBeforeBegin++;
        }
    }

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

BOOL
HXPlayer::IsSitePresent
(
    IHXSite*                pSite
)
{
#if defined(HELIX_FEATURE_VIDEO)
    return m_pSiteManager->IsSitePresent(pSite);
#else
    return FALSE;
#endif /* HELIX_FEATURE_VIDEO */
}

void
HXPlayer::CheckIfRendererNeedFocus(IUnknown* pRenderer)
{
#if defined(HELIX_FEATURE_VIDEO)
    BOOL bNeedFocus = FALSE;
    ReadPrefBOOL(m_pPreferences, "GrabFocus", bNeedFocus);

    IHXRenderer* pRend = NULL;
    pRenderer->QueryInterface(IID_IHXRenderer, (void**) &pRend);
    if (pRend)
    {
        UINT32 ulGran = 0;
        const char**    ppszMimeTypes = NULL;
        pRend->GetRendererInfo(ppszMimeTypes, ulGran);
        while (ppszMimeTypes && *ppszMimeTypes)
        {
            // XXRA Hernry, please remove the GrabFocus preference code from above
            // when you add the right mimetypes
            if ((::strcasecmp(*ppszMimeTypes, "MIMETYPE1") == 0) ||
                (::strcasecmp(*ppszMimeTypes, "MIMETYPE2") == 0))
            {
                bNeedFocus = TRUE;
                goto rendexit;
            }

            ppszMimeTypes++;
        }
    }

rendexit:
    HX_RELEASE(pRend);

    if (m_pSiteManager && bNeedFocus)
    {
        m_pSiteManager->NeedFocus(TRUE);
    }
#endif /* HELIX_FEATURE_VIDEO */
}

#if defined(HELIX_FEATURE_RECORDCONTROL)
BOOL HXPlayer::IsRecordServiceEnabled()
{
    BOOL bRes = FALSE;

    ReadPrefBOOL(m_pPreferences, "LiveSuperBuffer", bRes);

    return bRes;
}
#endif

STDMETHODIMP
HXPlayer::LoadRecordService(IHXRecordService* pRecordService)
{
#if defined(HELIX_FEATURE_RECORDCONTROL)
    HX_RELEASE(m_pRecordService);
    m_pRecordService = pRecordService;
    if(m_pRecordService)
        m_pRecordService->AddRef();

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_RECORDCONTROL */
}

STDMETHODIMP
HXPlayer::GetRecordService(REF(IHXRecordService*) pRecordService)
{
#if defined(HELIX_FEATURE_RECORDCONTROL)
    pRecordService = m_pRecordService;
    if(pRecordService)
    {
        pRecordService->AddRef();
        return HXR_OK;
    }

    return HXR_FAILED;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_RECORDCONTROL */
}

STDMETHODIMP
HXPlayer::UnloadRecordService()
{
#if defined(HELIX_FEATURE_RECORDCONTROL)
    HX_RELEASE(m_pRecordService);

    return HXR_OK;
#else
    return HXR_NOTIMPL;
#endif /* HELIX_FEATURE_RECORDCONTROL */
}


// working set monitoring tools on Windows
#if 0
#ifdef WIN32

typedef struct _PSAPI_WS_WATCH_INFORMATION
{
    LPVOID FaultingPc;
    LPVOID FaultingVa;
} PSAPI_WS_WATCH_INFORMATION;

#define WORKING_SET_BUFFER_ENTRYS 4096
PSAPI_WS_WATCH_INFORMATION WorkingSetBuffer[WORKING_SET_BUFFER_ENTRYS];

typedef BOOL (WINAPI * InitializeProcessForWsWatchType) (
    HANDLE hProcess
    );

typedef BOOL (WINAPI * GetWsChangesType) (
    HANDLE hProcess,
    PSAPI_WS_WATCH_INFORMATION* lpWatchInfo,
    DWORD cb
    );

InitializeProcessForWsWatchType g_fpInitializeProcessForWsWatch = NULL;
GetWsChangesType                g_fpGetWsChanges = NULL;
HINSTANCE                       g_PSAPIHandle = NULL;
HANDLE                          g_hCurrentProcess = NULL;
BOOL                            g_bPrintChanges = FALSE;
BOOL                            g_bSetWsChangeHook = FALSE;
BOOL                            g_bLockLikeACrazyMan = TRUE;
CHXMapPtrToPtr                  g_mWorkingSetMap;
int                             g_LockedPages = 0;
int                             g_totalFaults = 0;
int                             g_AttemptedLockedPages = 0;
int                             g_FailedLockedPages = 0;


void GetChangesToWorkingSet()
{
    int   count = 0;

    if (!g_hCurrentProcess)
    {
        g_hCurrentProcess = GetCurrentProcess();

        // check to see if we want to print data
        HKEY    hKey;
        char    szKeyName[256]; /* Flawfinder: ignore */
        long    szValueSize = 1024;
        char    szValue[1024]; /* Flawfinder: ignore */

        g_bLockLikeACrazyMan = FALSE;

        SafeSprintf(szKeyName, 256, "Software\\%s\\Debug\\LockLikeCrazy", HXVER_COMMUNITY);
        if( RegOpenKey(HKEY_CLASSES_ROOT, szKeyName, &hKey) == ERROR_SUCCESS )
        {
            RegQueryValue(hKey, "", szValue, (long *)&szValueSize);
            g_bLockLikeACrazyMan = !strcmp(szValue,"1");
            RegCloseKey(hKey);
        }
        else
        {
            RegCreateKey(HKEY_CLASSES_ROOT, szKeyName, &hKey);
            RegCloseKey(hKey);
        }

        g_bSetWsChangeHook = FALSE;

        SafeSprintf(szKeyName, 256, "Software\\%s\\Debug\\SetWsHook", HXVER_COMMUNITY);
        if( RegOpenKey(HKEY_CLASSES_ROOT, szKeyName, &hKey) == ERROR_SUCCESS )
        {
            RegQueryValue(hKey, "", szValue, (long *)&szValueSize);
            g_bSetWsChangeHook = !strcmp(szValue,"1");
            RegCloseKey(hKey);
        }
        else
        {
            RegCreateKey(HKEY_CLASSES_ROOT, szKeyName, &hKey);
            RegCloseKey(hKey);
        }

        if (g_bSetWsChangeHook)
        {
            if (g_bLockLikeACrazyMan)
            {
                BOOL setProcessWorkingSize = SetProcessWorkingSetSize(g_hCurrentProcess, (1<<23), (1<<24) );
            }

            g_PSAPIHandle = LoadLibrary("psapi.dll");

            if (g_PSAPIHandle)
            {
                g_fpInitializeProcessForWsWatch = (InitializeProcessForWsWatchType) GetProcAddress(g_PSAPIHandle, "InitializeProcessForWsWatch");
                g_fpGetWsChanges = (GetWsChangesType) GetProcAddress(g_PSAPIHandle, "GetWsChanges");
            }

            BOOL initRetVal = g_fpInitializeProcessForWsWatch(g_hCurrentProcess);
        }

        // check to see if we want to print data
        SafeSprintf(szKeyName, 256, "Software\\%s\\Debug\\PrintFaults", HXVER_COMMUNITY);
        if( RegOpenKey(HKEY_CLASSES_ROOT, szKeyName, &hKey) == ERROR_SUCCESS )
        {
            RegQueryValue(hKey, "", szValue, (long *)&szValueSize);
            g_bPrintChanges = !strcmp(szValue,"1");
            RegCloseKey(hKey);
        }
        else
        {
            RegCreateKey(HKEY_CLASSES_ROOT, szKeyName, &hKey);
            RegCloseKey(hKey);
        }
    }

    BOOL b = FALSE;

    if (g_fpGetWsChanges)
    {
        b = g_fpGetWsChanges(g_hCurrentProcess,&WorkingSetBuffer[0],sizeof(WorkingSetBuffer));
    }

    if ( b )
    {
        int i = 0;
        while (WorkingSetBuffer[i].FaultingPc)
        {
            void* Pc = WorkingSetBuffer[i].FaultingPc;
            void* Va = WorkingSetBuffer[i].FaultingVa;
            void* VaPage = (void*) ((ULONG)Va & 0xfffff000);

            g_totalFaults++;

            Va = (LPVOID)( (ULONG)Va & 0xfffffffe);
            count = 0;

            g_mWorkingSetMap.Lookup(VaPage, (void*&)count);
            count++;
            g_mWorkingSetMap.SetAt(VaPage, (void*)count);
            if (count==50 && g_bLockLikeACrazyMan)
            {
                g_AttemptedLockedPages++;
#if 0 /* do not attempt to lock - RA */
                BOOL bRetVal = VirtualLock(VaPage, 4096);
                if (!bRetVal)
                {
                    DWORD lastError = GetLastError();
                    void* lpMsgBuf;
                    FormatMessage(  FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                                    NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );
                    LocalFree( lpMsgBuf );
                    g_FailedLockedPages++;
                }
                else
                {
                    g_LockedPages++;
                }
#endif
            }
            i++;
        }
    }
}
#endif
#endif
