chxavplayer.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:32k
源码类别:

Symbian

开发平台:

Visual C++

  1. /************************************************************************
  2.  * chxavplayer.cpp
  3.  * ---------------
  4.  *
  5.  * Synopsis:
  6.  * Contains the implementation of the CHXAvPlayer class.  This class
  7.  * coordinates the client core to play back a file or url.
  8.  *
  9.  * Target:
  10.  * Symbian OS
  11.  *
  12.  *
  13.  * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
  14.  *
  15.  *****************************************************************************/
  16.   
  17. #include "hxtypes.h"
  18. #include "ihxaccesspoint.h"
  19. #include "hxsym_debug.h"
  20. #include "hxsym_leaveutil.h"
  21. #include "hxdebug_hxapi.h"
  22. #include "hxapihelp_player.h"
  23. #include "hxapihelp.h"
  24. #include "hxgroup.h" //IHXGroupSink
  25. #include "chxavcleanstring.h"
  26. #include "chxavramparser.h"
  27. #include "chxavconfignames.h"
  28. #include "chxavcleanupstack.h"
  29. #include "chxavnetconnectui.h"
  30. #include "comptr.h"
  31. #include "comptr_traits.h"
  32. #include "chxavutil.h"
  33. #include "chxavplayer.h"
  34. namespace
  35. {
  36.    
  37. CHXAvFile::FileType GetFileTypeFromUrlL(const char* pURL)
  38. {
  39.     // get path-only part of url in a descriptor
  40.     HBufC* pPath = CHXAvUtil::AllocStdPathFromPlayerUrlL(pURL);
  41.     AUTO_PUSH_POP_DEL(pPath);
  42.     // handle case where local file is a ram/playlist
  43.     return CHXAvFile::GetFileType(*pPath);
  44. }
  45. bool HasRemoteURL(IHXValues* pVal)
  46. {
  47.     CHXString strURL;
  48.     if(val::GetString(pVal, "url", strURL))
  49.     {
  50.         if(!CHXAvUtil::IsLocal(strURL) || 0 == strURL.Find("helix-sdp"))
  51.         {
  52.             return true;
  53.         }
  54.     }
  55.     return false;
  56. }
  57. } // locals
  58. // IUnknown implementation body...
  59. BEGIN_INTERFACE_LIST(CHXAvPlayer)
  60.     INTERFACE_LIST_ENTRY(IID_IHXClientAdviseSink, IHXClientAdviseSink)
  61.     INTERFACE_LIST_ENTRY(IID_IHXAccessPointSelector, IHXAccessPointSelector)
  62.     INTERFACE_LIST_ENTRY(IID_IHXErrorSink, IHXErrorSink)
  63.     INTERFACE_LIST_ENTRY(IID_IHXGroupSink, IHXGroupSink)
  64.     INTERFACE_LIST_ENTRY_DELEGATE_BLIND
  65.     (
  66.         QueryInterfaceDelegates
  67.     )
  68. END_INTERFACE_LIST
  69. HX_RESULT CHXAvPlayer::QueryInterfaceDelegates(REFIID riid, void** ppvObj)
  70. {
  71.     if( IsEqualIID(riid, IID_IHXPreferences) )
  72.     {
  73.         return m_spEngine->GetPrefs()->QueryInterface(riid, ppvObj);
  74.     }
  75.     else if( IsEqualIID(riid, IID_IHXSiteSupplier) )
  76.     {
  77.         return m_siteSupplier->QueryInterface(riid, ppvObj);
  78.     }
  79.     return HXR_NOINTERFACE;
  80. }
  81.  
  82. /*
  83.  * CHXAvPlayer
  84.  * -----------
  85.  *
  86.  */
  87. CHXAvPlayer::CHXAvPlayer() 
  88. : m_clipDuration(0)
  89. , m_clipPos(0)
  90. , m_volumeStep(kVolumeMax / 10) // must match nokia vol control XXXLCM hardcoded
  91. , m_bEnableAutoPlayNext(true)
  92. , m_bIsTruePlaylistLoaded(false)
  93. , m_bResumeOnEndSeek(false)
  94. , m_hxPlayer(0)
  95. , m_startupStage(ssStopped)
  96. , m_bIsRemotePlayback(false)
  97. , m_bAccessPointSetupFailed(false)
  98. {
  99. }
  100. /*
  101.  * ~CHXAvPlayer
  102.  * -------------
  103.  * Destructor.
  104.  *
  105.  */
  106. CHXAvPlayer::~CHXAvPlayer()
  107. {
  108. }
  109. /*
  110.  * ConstructL
  111.  * ----------
  112.  *
  113.  * Client must call InitPlayerL() before attempting playback
  114.  *
  115.  */
  116. void
  117. CHXAvPlayer::ConstructL(const CHXClientEngineManagerPtr& spEngine, 
  118.                         const CHXAvNetConnectUIPtr& pAccessPointSelector)
  119. {
  120.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::ConstructL()n"));
  121.     HX_ASSERT(spEngine);
  122.     m_spEngine = spEngine;
  123.     m_playerState.ConstructL();
  124.     // timer for playing current clip
  125.     const CHXAvCommand& cmdPlay = 
  126. MakeCommand(this, &CHXAvPlayer::PlayCurrent);
  127.     m_cbPlay.ConstructL(cmdPlay);
  128.     // for convenience
  129.     m_prefs = m_spEngine->GetPrefs();
  130.     m_factory = m_spEngine->GetFactory();
  131.     // ap selector handles some ui logic for selecting and setting access points
  132.     m_apSelector = pAccessPointSelector;
  133. }
  134. void CHXAvPlayer::Play(const TDesC& url)
  135. {
  136.     HX_ASSERT(CHXAvUtil::IsValidUrl(url));
  137.     CHXString str = CHXAvStringUtils::DescToString(url);
  138.     Play(str);
  139. }
  140. ////////////////////////////////////////
  141. // helper
  142. //
  143. // create a playlist and iterator for ram/playlist
  144. //
  145. void CHXAvPlayer::DoPlaylistInit(const char* pURL)
  146. {
  147.     CHXAvURLRep urlRep(pURL);
  148.     // these should be reset with each (main url) play attempt
  149.     HX_ASSERT(!m_pPlaylist);
  150.     HX_ASSERT(!m_pPlaylist);
  151.     HX_ASSERT(!m_bIsTruePlaylistLoaded);
  152.       
  153.     m_pPlaylist = CHXAvRAMParser::Parse(urlRep.Path());
  154.     if( m_pPlaylist )
  155.     {
  156. #ifdef PLAYLIST_END_IN_LST_ONLY
  157.         static const char * const k_pPlaylistExt = ".lst"; // XXXLCM
  158.         // if ram file has playlist extension, treat it as 'true playlist' (one that can be shuffled, etc.)
  159.         
  160.         INT32 idxDot = urlRep.Path().ReverseFind('.');
  161.         if( idxDot != -1 )
  162.         {
  163.             CHXString ext = urlRep.Path().Mid(idxDot);
  164.             m_bIsTruePlaylistLoaded = (0 == ext.CompareNoCase(k_pPlaylistExt));
  165.         }
  166. #else
  167. m_bIsTruePlaylistLoaded = true;
  168. #endif
  169.         // apply shuffle mode if this is a true playlist
  170.         bool bShuffleModeOn = prefs::GetBool(m_prefs, CHXAV_ShuffleMode);
  171.         if(m_bIsTruePlaylistLoaded && bShuffleModeOn)
  172.         {
  173.             m_pPlaylist->Shuffle();
  174.         }
  175.         m_pPlayItr = new (ELeave) CHXAvPlaylistItr(*m_pPlaylist);
  176.         // set iterator loop mode off (even if player 'loop mode' on; that's handled elsewhere)
  177.         m_pPlayItr->Loop(false);
  178.         // ensure we are at beginning
  179.         m_pPlayItr->ResetBegin(); 
  180.     }
  181. }
  182. /*
  183.  * Play
  184.  * ----
  185.  * Handle user command to play the given url.  
  186.  *
  187.  */
  188. void 
  189. CHXAvPlayer::Play(const char *url) // XXXLCM can leave
  190. {
  191.    
  192.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::Play(): url = '%s'n", url));
  193.     HX_ASSERT(m_hxPlayer);
  194.     // main url is requested url (ram or single clip)
  195.     m_mainUrl = url;
  196.     m_playUrl = "";
  197.     // reset playlist-related stuff on new main url play attempt
  198.     m_pPlaylist = 0;
  199.     m_pPlayItr = 0;
  200.     m_bIsTruePlaylistLoaded = false;
  201.     // see if we can squeeze blood from a turnip
  202.     User::CompressAllHeaps();
  203.     if(CHXAvUtil::IsFileUrl(url))
  204.     {
  205.         // handle case where local file is a ram/playlist
  206.         CHXAvFile::FileType type = GetFileTypeFromUrlL(url); //XXXLCM can leave
  207.         if( CHXAvFile::ftRam == type )
  208.         {
  209.             DoPlaylistInit(url);
  210.             if(m_pPlayItr)
  211.             {
  212.                 DoPlayImp(m_pPlayItr->Current().String());
  213.             } 
  214.             else
  215.             {
  216.                 // invalid ram file
  217.                 HX_ASSERT(false);
  218.                 m_playerState.OnError(HXR_INVALID_FILE);
  219.             }
  220.         }
  221.         else
  222.         {
  223.             // local non-ram file
  224.             DoPlayImp(url);
  225.         }
  226.     }
  227.     else
  228.     {
  229.         // remote url
  230.         DoPlayImp(url);
  231.     }
  232. }
  233. /*
  234.  * PlayCurrent
  235.  * ----
  236.  * Play the current url  
  237.  *
  238.  */
  239. void 
  240. CHXAvPlayer::PlayCurrent()
  241. {
  242.     HX_ASSERT(!m_playUrl.IsEmpty());
  243.     DoPlayImp(m_playUrl);
  244. }
  245. /*
  246.  * Reset state variables for current clip that won't make sense
  247.  * once the clip is unloaded. After a stop the last played
  248.  * clip remains "loaded", i.e., ready for re-play. The UI should
  249.  * continue to reflect attributes (and provide access to clip info)
  250.  * that pertain to the stopped (still-loaded) clip.
  251.  *
  252.  * A clips is "unloaded" after an advance to next clip in playlist
  253.  * or when replaced by a new clip upon a new play request. Also, no
  254.  * clip is loaded when this player object is first created.
  255.  *
  256.  */
  257. void 
  258. CHXAvPlayer::ResetUnloadedClipState()
  259. {
  260.     // since play url had changed, current headers and bitrate values no longer apply
  261.     m_clipInfo.Reset();
  262.     // unknown for next clip
  263.     m_clipDuration = 0;
  264.     m_bIsRemotePlayback = false;
  265. }
  266. /* 
  267.  * DoPlayImp
  268.  * ------
  269.  *
  270.  */
  271. void
  272. CHXAvPlayer::DoPlayImp(const char* url)
  273. {
  274.     if( m_playUrl != url)
  275.     {
  276.         m_playUrl = url;
  277.     
  278.         // reset stuff we won't know until we load 
  279.         ResetUnloadedClipState();
  280.     }
  281.     // reset stuff for each play
  282.     m_bEnableAutoPlayNext = true;
  283.     m_clipPos = 0;
  284.     m_startupStage = ssPastInitiate;
  285.     m_bAccessPointSetupFailed = false;
  286.     m_playerState.OnPlayInitiate(url);
  287.     // fixup url in case we need to add duration option to it
  288.     CHXString fixedUrl(url); // XXXLCM cleanup stack; function can leave
  289.     
  290.     UINT32 secIntro = prefs::GetUINT32(m_prefs, CHXAV_ClipIntroSecs);
  291.     if( m_bIsTruePlaylistLoaded && secIntro != 0 )
  292.     {
  293. // Force end of each clip at N seconds into clip. If actual clip
  294. // duration is shorter than N seconds, then the clip will end at
  295. // its proper end time.
  296. static const char * const k_Format = "?end=%lu";
  297. CHXString strOption;
  298. strOption.Format(k_Format, secIntro);
  299. fixedUrl += strOption;
  300.     }
  301.     
  302.     HX_ASSERT(m_hxPlayer);
  303.     HX_RESULT hxr = m_hxPlayer->OpenURL(fixedUrl);
  304.     if( HXR_OK == hxr)
  305.     {
  306. hxr = m_hxPlayer->Begin();
  307. if (HXR_OK == hxr)
  308. {
  309.     // the file header can be gotten at this point
  310.     m_clipInfo.CacheHeadersL(m_hxPlayer);
  311.             
  312.             // we detect need for net connect later on for smil and sdp
  313.             if(!m_bAccessPointSetupFailed && !CHXAvUtil::IsLocal(url))
  314.             {
  315.                 OnNetConnect();
  316.             }
  317. }
  318.     }
  319.     
  320.     if( hxr != HXR_OK )
  321.     {
  322. m_playerState.OnError(hxr);
  323.     }
  324. }
  325. // heleper
  326. void CHXAvPlayer::OnNetConnect()
  327. {
  328.     m_bIsRemotePlayback = true;
  329.     if(m_startupStage < ssPastFirstBuffer)
  330.     {
  331.         m_playerState.OnNetConnect();
  332.     }
  333. }
  334. /*
  335.  * CanSeek
  336.  * ---------
  337.  * Returns true if it is safe to seek.
  338.  *
  339.  */
  340. bool 
  341. CHXAvPlayer::CanSeek() const
  342. {
  343.     bool bCanSeek = false;
  344.     switch (m_playerState.GetState())
  345.     {
  346.     case CHXAvPlayerState::Playing:
  347.     case CHXAvPlayerState::Seeking:
  348.     case CHXAvPlayerState::Paused:
  349.         bCanSeek = !m_clipInfo.IsLive(); // && (m_startupStage > ssPastFirstBuffer);
  350. break;
  351.     default:
  352. break;
  353.     }
  354.     return bCanSeek;
  355. }
  356. /*
  357.  * CanPause
  358.  * ----------
  359.  * Return true if we are in a state where it is safe to pause.
  360.  *
  361.  */
  362. bool CHXAvPlayer::CanPause() const
  363. {
  364.     bool bCanPause = false;
  365.     switch (m_playerState.GetState())
  366.     {
  367.     case CHXAvPlayerState::Playing:
  368.     case CHXAvPlayerState::Connecting:
  369. bCanPause = true;
  370. break;
  371.     default:
  372. break;
  373.     }
  374.     return bCanPause;
  375. }
  376.  
  377. /*
  378.  * CanResume
  379.  * -----------
  380.  * Return true if we can resume from current state.
  381.  */
  382. bool 
  383. CHXAvPlayer::CanResume() const
  384. {
  385.     return (!m_mainUrl.IsEmpty() && (IsPaused() || IsStopped()));
  386. }
  387. /*
  388.  * Stop
  389.  * ----
  390.  * Stop the playback. From user command.
  391.  *
  392.  */
  393. void 
  394. CHXAvPlayer::Stop()
  395. {
  396.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::Stop()n"));
  397.     
  398.     // prevent automatic playlist/loop advance after user request to stop
  399.     m_bEnableAutoPlayNext = false;
  400.     
  401.     DoStopImp();
  402. }
  403. /*
  404.  * DoStopImp
  405.  * ------
  406.  * Stop
  407.  *
  408.  */
  409. void
  410. CHXAvPlayer::DoStopImp()
  411. {
  412.     m_clipPos = 0;
  413.     m_startupStage = ssStopped;
  414.     m_playerState.OnStop();
  415.     HX_ASSERT(m_hxPlayer);
  416.     m_hxPlayer->Stop();
  417. }
  418.     
  419. /*
  420.  * Pause
  421.  * -----
  422.  *
  423.  */
  424. void 
  425. CHXAvPlayer::Pause()
  426. {
  427.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::Pause()n"));
  428.     if ((m_hxPlayer != NULL) && (!m_hxPlayer->IsDone()))
  429.     {
  430. m_hxPlayer->Pause();
  431. m_playerState.OnPause();
  432.     }
  433. }
  434.     
  435. /*
  436.  * Resume
  437.  * ------
  438.  *
  439.  */
  440. void 
  441. CHXAvPlayer::Resume()
  442. {
  443.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::Resume()n"));
  444.     if ((m_hxPlayer != NULL) && (!m_hxPlayer->IsDone()))
  445.     {
  446. m_hxPlayer->Begin();
  447.     }
  448. }
  449. /*
  450.  * SetVolume
  451.  * ---------
  452.  *
  453.  */
  454. void 
  455. CHXAvPlayer::SetVolume(TUint level)
  456. {
  457.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::SetVolume(): level = %dn", level));
  458.     HX_ASSERT(level <= 100);
  459.     HX_ASSERT(m_audioPlayer);
  460.     if( level <= 100 )
  461.     {
  462.         if(m_audioPlayer)
  463.         {
  464.             IHXVolume* pVolume = m_audioPlayer->GetDeviceVolume();
  465.             if( pVolume )
  466.             {
  467.                 pVolume->SetVolume(level);
  468.                 HX_RELEASE(pVolume);  
  469.             }
  470.         }
  471.         m_playerState.OnVolume(level);
  472.     }
  473. }
  474.     
  475. void
  476. CHXAvPlayer::StepVolume(TInt factor)
  477. {
  478.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::StepVolume(): fact = %dn", factor));
  479.     // adjust volume by factor
  480.     TInt level = GetVolume();
  481.     level += m_volumeStep * factor;
  482.     // constrain to valid level
  483.     level = min(kVolumeMax, max(0, level));
  484.     SetVolume(level);
  485.     
  486. }
  487. /*
  488.  * GetVolume
  489.  * ---------
  490.  *
  491.  */
  492. TUint 
  493. CHXAvPlayer::GetVolume() const
  494. {
  495.     TUint level = 0;
  496.     HX_ASSERT(m_audioPlayer);
  497.     if (m_audioPlayer)
  498.     {
  499.         IHXVolume* pVolume = m_audioPlayer->GetDeviceVolume();
  500.         if( pVolume )
  501.         {
  502.             level = pVolume->GetVolume();
  503.             HX_RELEASE(pVolume);
  504.         }
  505.     }
  506.     return level;
  507. }
  508.     
  509. /*
  510.  * Mute
  511.  * ----
  512.  *
  513.  */
  514. void 
  515. CHXAvPlayer::Mute(bool bToMute)
  516. {
  517.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::Mute('%s')n", dbg::Bool(bToMute)));
  518.     HX_ASSERT(m_audioPlayer);
  519.     if (m_audioPlayer)
  520.     {
  521.         IHXVolume* pVolume = m_audioPlayer->GetDeviceVolume();
  522.         if( pVolume )
  523.         {
  524.             pVolume->SetMute( bToMute );
  525.             HX_RELEASE(pVolume);     
  526.         }
  527.     }
  528.     m_playerState.OnMute(bToMute);
  529. }
  530. /*
  531.  * IsMuted
  532.  * -------
  533.  *
  534.  */
  535. bool 
  536. CHXAvPlayer::IsMuted() const
  537. {
  538.     bool bMute = false;
  539.     HX_ASSERT(m_audioPlayer);
  540.     if (m_audioPlayer)
  541.     {
  542.         IHXVolume* pVolume = m_audioPlayer->GetDeviceVolume();
  543.         if( pVolume )
  544.         {
  545.             bMute = pVolume->GetMute();
  546.             HX_RELEASE(pVolume);
  547.         }
  548.     }
  549.     return bMute;
  550. }
  551. /*
  552.  * InitPlayerL
  553.  * -----------
  554.  *
  555.  * Create a new player object and set it up for playback. Call 
  556.  * only when player is currently shutdown.
  557.  *
  558.  */
  559. void CHXAvPlayer::InitPlayerL(CCoeControl* pRenderWindow)
  560. {
  561.     // player
  562.     HX_ASSERT(!m_hxPlayer);
  563.     m_spEngine->GetEngine()->CreatePlayer(m_hxPlayer.AsRef());
  564.     
  565.     // site supplier (must be done before we setup client context)
  566.     m_siteSupplier = new (ELeave) CHXAvSiteSupplier();
  567.     m_siteSupplier->ConstructL(m_hxPlayer, pRenderWindow);
  568.     m_hxPlayer->SetClientContext(static_cast<IHXClientAdviseSink*>(this)); // arbitrary unknown
  569.     
  570.     // set us up to observe player events
  571.     m_hxPlayer->AddAdviseSink(this);    
  572.     
  573.     // set us up to observer error messages
  574.     comptr<IHXErrorSinkControl> control;
  575.     control.From(m_hxPlayer);
  576.     control->AddErrorSink(this, HXLOG_EMERG, HXLOG_INFO);
  577.     // set us up as ap selector
  578.     m_apManager.From(m_hxPlayer);
  579.     if(m_apManager)
  580.     {
  581.         m_apManager->RegisterSelector(this);
  582.     }
  583.       
  584.     // grab some interfaces
  585.     m_audioPlayer.From(m_hxPlayer);
  586.     // set up to receive group/track events
  587.     comptr<IHXGroupManager> groupMgr;
  588.     groupMgr.From(m_hxPlayer);
  589.     if(groupMgr)
  590.     {
  591.         groupMgr->AddSink(this);
  592.     }
  593. }
  594. // IHXAccessPointSelector
  595. STDMETHODIMP 
  596. CHXAvPlayer::SelectAccessPoint(IHXAccessPointSelectorResponse* pResponse)
  597. {
  598.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::SelectAccessPoint()n"));
  599.     HX_RESULT hr = HXR_OK;
  600.     if(m_apSelector)
  601.     {
  602.         HX_ASSERT(m_apManager);
  603.         TRAPD(err, hr = m_apSelector->DoSelectAccessPointL(m_apManager, pResponse));
  604.         if(err != KErrNone)
  605.         {
  606.             hr = HXR_FAIL;
  607.         }
  608.     }
  609.     if(SUCCEEDED(hr))
  610.     {
  611.         // just in case; we should detect this via other methods
  612.         OnNetConnect();
  613.     }
  614.     else
  615.     {
  616.         // some pending client core tasks (e.g., group sink notifications) get processed
  617.         // before this error is detected and reported; we want to ignore these, hence this
  618.         // pulchritudinous flag
  619.         m_bAccessPointSetupFailed = true;
  620.     }
  621.     return hr;
  622. }
  623. /*
  624.  * ShutDown
  625.  * --------
  626.  *
  627.  * Release and destroy the player object. The player does not unload
  628.  * renderers and sites until it closes or a new presentation is opened.
  629.  *
  630.  * UI owner must call this to free references held by client core (so that
  631.  * subsequent release of this object results in deletion)
  632.  *
  633.  * Undoes everything done in InitPlayerL
  634.  *
  635.  * Note: clip, playlist and header info remains valid
  636.  */
  637. void 
  638. CHXAvPlayer::ShutDown()
  639. {
  640.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::ShutDown()n"));
  641.     //HX_ASSERT(m_hxPlayer);
  642.     if( m_hxPlayer )
  643.     {
  644.         // stop and remove sinks (just in case; probably not really necessary)
  645.         if(!m_hxPlayer->IsDone())
  646.         {
  647.             m_hxPlayer->Stop();
  648.         }
  649.         m_hxPlayer->RemoveAdviseSink(this);
  650.         comptr<IHXErrorSinkControl> control;
  651.         control.From(m_hxPlayer);
  652.         control->RemoveErrorSink(this);
  653.         control.Reset();
  654.         comptr<IHXGroupManager> groupMgr;
  655.         groupMgr.From(m_hxPlayer);
  656.         if(groupMgr)
  657.         {
  658.             groupMgr->RemoveSink(this);
  659.         }
  660.         // unregister with access point manager
  661.         if(m_apManager)
  662.         {
  663.             m_apManager->UnregisterSelector(this);
  664.         }
  665.         m_spEngine->GetEngine()->ClosePlayer(m_hxPlayer);
  666.         m_audioPlayer = 0;
  667.         m_siteSupplier = 0;
  668.         m_hxPlayer = 0;
  669.         m_apManager = 0;
  670.     }
  671.     // reset stuff associated with previously active HX player
  672.     m_mainUrl = "";
  673.     m_playUrl = "";
  674.     m_pPlaylist = 0;
  675.     m_pPlayItr = 0;
  676.     m_bIsTruePlaylistLoaded = false;
  677.     ResetUnloadedClipState();
  678. }
  679. /*
  680.  * GetClipTime
  681.  * -----------
  682.  * Returns the point in the timeline where we are currently.
  683.  *
  684.  */
  685. ULONG32
  686. CHXAvPlayer::GetClipTime() const
  687. {
  688.     // note: we don't use IHXPlayer::GetCurrentPlayTime() so we have better control over this value
  689.     return m_clipPos;
  690. }
  691. /*
  692.  * EndSeek
  693.  * -------
  694.  * Called when user stops seeking
  695.  *
  696.  */
  697. void
  698. CHXAvPlayer::EndSeek()
  699. {
  700.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::EndSeek()n"));
  701.     HX_ASSERT(m_hxPlayer);
  702.     if(  m_clipPos >= GetClipDuration() )
  703.     {
  704.         // seek to end
  705.         DoStopImp();
  706.     }
  707.     else
  708.     {
  709.         HX_RESULT hr = m_hxPlayer->Seek(m_clipPos);
  710.         if( SUCCEEDED(hr) )
  711.         {
  712.             // auto-resume playback if we were playing when we began seeking
  713.     if (m_bResumeOnEndSeek)
  714.     {
  715.                 DPRINTF(SYMP_INFO, ("CHXAvPlayer::EndSeek(): resuming...n"));
  716.         hr = m_hxPlayer->Begin();
  717.     }
  718.     else
  719.     {
  720.         m_playerState.OnPause();
  721.     }
  722.         }
  723.         if(FAILED(hr))
  724.         {
  725.             DPRINTF(SYMP_INFO, ("CHXAvPlayer::EndSeek(): failed to resume player after seek ('%s')n", dbg::ErrorCode(hr)));
  726.             DoStopImp();
  727.         }
  728.     } 
  729.     m_bResumeOnEndSeek = false;
  730. }
  731. /*
  732.  * StartSeek
  733.  * ---------
  734.  * Called when user begins seeking (drags slider, presses seek button, etc.)
  735.  *
  736.  */
  737. void
  738. CHXAvPlayer::StartSeek()
  739. {
  740.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::StartSeek()n"));
  741.     bool bIsPaused = (m_playerState.GetState() == CHXAvPlayerState::Paused);
  742.     m_bResumeOnEndSeek = !bIsPaused;
  743.     m_playerState.OnBeginSeek();
  744.     // we must pause while user is seeking
  745.     if( !bIsPaused )
  746.     {
  747.         m_hxPlayer->Pause();
  748.     }
  749. }
  750. /*
  751.  * SetSeekPoint
  752.  * ------------
  753.  * update current seek point as user moves slider/position around
  754.  *
  755.  */
  756. void
  757. CHXAvPlayer::SetSeekPoint(ULONG32 time)
  758. {
  759.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::SetSeekPoint(): time = %lun", time));
  760.     HX_ASSERT(IsSeeking());
  761.     
  762.     ULONG32 duration = GetClipDuration();
  763.     if( time > duration )
  764.     {
  765. //
  766. // set time to duration so when we attempt to resume
  767. // we will automatically go on to the next clip
  768. //
  769. time = duration;
  770.     }
  771.     m_clipPos = time;
  772.     m_playerState.OnNewPos(time);
  773.     
  774. }
  775. //IHXClientAdviseSink
  776. STDMETHODIMP
  777. CHXAvPlayer::OnPosLength(UINT32 ulPosition, UINT32 ulLength)
  778. {
  779.     //DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPosLength(): pos = %lun", ulPosition));
  780.     if(ulPosition > 0)
  781.     {
  782.         // we assume we get a buffer message before OnPosLength() in every case
  783.         HX_ASSERT(m_startupStage >= ssPastFirstBuffer);
  784.         m_startupStage = ssPastTimerStarted;
  785.     }
  786.     m_clipPos = ulPosition;
  787.     m_clipDuration = ulLength;
  788.     if(ulLength >0)
  789.     {
  790.         m_playerState.OnNewPos(ulPosition);
  791.     }
  792.     return HXR_OK;
  793. }
  794. ////////////////////////////////
  795. //
  796. TInt CHXAvPlayer::GetPlaylistCurrentIndex() const
  797. {
  798.     HX_ASSERT(m_pPlayItr);
  799.     return m_pPlayItr->Offset();
  800. }
  801. TInt CHXAvPlayer::GetPlaylistItemCount() const
  802. {
  803.     HX_ASSERT(m_pPlaylist);
  804.     return m_pPlaylist->Length();
  805. }
  806. ////////////////////////////////////////////
  807. // user command to move to next or previous item in playlist
  808. //
  809. // from user request
  810. //
  811. void CHXAvPlayer::AdvancePlaylist(TUint flag)
  812. {
  813.     if(!m_pPlayItr)
  814.     {
  815.         return;
  816.     }
  817.     // move forward or backward in playlist
  818.     HandlePlaylistAdvance(flag);
  819.     if( CHXAvPlayerState::Stopped != m_playerState.GetState() )
  820.     {
  821.         // stop current clip as soon as user moves through playlist
  822.         m_bEnableAutoPlayNext = false;       
  823.         DoStopImp();
  824.     }
  825. }
  826. ////////////////////////////////////////////
  827. //
  828. // return true if playlist end was reached
  829. //
  830. bool CHXAvPlayer::HandlePlaylistAdvance(TUint flag)
  831. {
  832.     HX_ASSERT(m_pPlayItr);
  833.     
  834.     bool bReachedEnd = false;
  835.     // temporarily set playlist iter loop mode on so we loop around
  836.     m_pPlayItr->Loop( (flag & advanceLoop) != 0 );
  837.     if (flag & advanceNext)
  838.     {
  839.         m_pPlayItr->Next();
  840.     }
  841.     else
  842.     {
  843.         HX_ASSERT(flag & advancePrev);
  844.         m_pPlayItr->Prev();
  845.     }
  846.     if(!m_pPlayItr->More())
  847.     {
  848.         m_pPlayItr->ResetBegin();
  849.         bReachedEnd = true;
  850.     }
  851.     m_playUrl = m_pPlayItr->Current().String();
  852.     // restore playlist iter loop mode
  853.     m_pPlayItr->Loop(false);
  854.     // play url has changed - reset associated state variables
  855.     ResetUnloadedClipState();
  856.     m_playerState.OnAdvancePlaylist();
  857.     return bReachedEnd;
  858.     
  859. }
  860. /*
  861.  * IHXClientAdviseSink
  862.  * OnPresentationOpened
  863.  * --------------------
  864.  *
  865.  */
  866. STDMETHODIMP
  867. CHXAvPlayer::OnPresentationOpened()
  868. {
  869.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPresentationOpened()n"));
  870.     HX_ASSERT(m_hxPlayer != NULL);
  871.     m_startupStage = ssPastOpenPres;
  872.     // now we should be able to obtain all headers for main source (in case of smil
  873.     // sub-sources will not be there yet -- see OnBuffering)
  874.     m_clipInfo.CacheHeadersL(m_hxPlayer);
  875.     // see if we are video-only and/or live
  876.     m_clipInfo.CachePresentationInfoL(m_hxPlayer);
  877.     
  878.     // get request headers...
  879.     comptr<IHXPlayer2> play2;
  880.     play2.From(m_hxPlayer);
  881.     HX_ASSERT(play2);
  882.     
  883.     comptr<IHXRequest> req;
  884.     play2->GetRequest(req.AsRef());
  885.     HX_ASSERT(req);
  886.     
  887.     // possibly save some request info
  888.     m_clipInfo.CacheRequestInfo(req);
  889.     m_playerState.OnLoadSession(req);
  890.     return HXR_OK;
  891. }
  892.     
  893. // IHXClientAdviseSink
  894. STDMETHODIMP
  895. CHXAvPlayer::OnPresentationClosed()
  896. {
  897.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPresentationClosed()n"));
  898.     HX_ASSERT(CHXAvPlayerState::Stopped == m_playerState.GetState()); // we expect OnStop() first
  899.     
  900.     m_playerState.OnStop(); // just in case
  901.     if( m_bEnableAutoPlayNext )
  902.     {
  903.         // current clip ended by playing out; try to advance to next clip or loop
  904.         bool bLoopModeEnabled = prefs::GetBool(m_prefs, CHXAV_LoopMode);
  905.         bool bDoPlay = true;
  906.         if( m_pPlayItr )
  907.         {
  908.             TUint af = advanceNext;
  909.             if( bLoopModeEnabled )
  910.             {
  911.                 af |= advanceLoop;
  912.             }
  913.             //  advance through playlist
  914.             bool bReachedEnd = HandlePlaylistAdvance(af);
  915.             if( bReachedEnd && !bLoopModeEnabled )
  916.             {
  917.                 // stop at end of playlist when loop mode is off
  918.                 bDoPlay = false;
  919.             }
  920.         }
  921.         else
  922.         {
  923.             bDoPlay = bLoopModeEnabled;
  924.         }
  925.     
  926.         if( bDoPlay )
  927.         { 
  928.             // if we call PlayCurrent() here, we get an immediate OnStop() and OnPresentationClosed()
  929.             m_cbPlay.Set(10);
  930.         }
  931.     }
  932.    
  933.     return HXR_OK;
  934. }
  935.     
  936. // IHXClientAdviseSink
  937. STDMETHODIMP
  938. CHXAvPlayer::OnStatisticsChanged()
  939. {
  940. #if defined(HELIX_FEATURE_DPRINTF)
  941.     char  szBuff[100];
  942.     for(UINT16 idx = 0; /*NULL*/; ++idx)
  943.     {
  944.         sprintf(szBuff, "Statistics.Player%u", idx );
  945.         if(!dbg::DumpRegistry(m_spEngine->GetEngine(), szBuff))
  946.         {
  947.             break;
  948.         }
  949.     }
  950. #endif
  951.     return HXR_OK;
  952. }
  953.  
  954.  
  955. // IHXClientAdviseSink
  956. //
  957. // called when player object begins seek, just after
  958. // user finishes setting seek target; during this period
  959. // we expect to receive buffer notifications until OnPostSeek()
  960. // is called
  961. STDMETHODIMP
  962. CHXAvPlayer::OnPreSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  963. {
  964.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPreSeek()n"));
  965.     return HXR_OK;
  966. }
  967.     
  968. // IHXClientAdviseSink
  969. STDMETHODIMP
  970. CHXAvPlayer::OnPostSeek(ULONG32 ulOldTime, ULONG32 ulNewTime)
  971. {
  972.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPostSeek()n"));
  973.     return HXR_OK;
  974. }
  975.     
  976. // IHXClientAdviseSink
  977. STDMETHODIMP
  978. CHXAvPlayer::OnStop()
  979. {
  980.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnStop()n"));
  981.     m_clipPos = 0;
  982.     m_playerState.OnStop();
  983.     return HXR_OK;
  984. }
  985.     
  986. // IHXClientAdviseSink
  987. STDMETHODIMP
  988. CHXAvPlayer::OnPause(ULONG32 ulTime)
  989. {
  990.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnPause()n"));
  991.     if( m_playerState.GetState() != CHXAvPlayerState::Seeking)
  992.     {
  993.         m_playerState.OnPause();
  994.     }
  995.     return HXR_OK;
  996. }
  997.     
  998. // IHXClientAdviseSink
  999. //
  1000. // called a) after renderers are initialized (before open pres) b) after EndSeek 
  1001. STDMETHODIMP
  1002. CHXAvPlayer::OnBegin(ULONG32 ulTime)
  1003. {
  1004.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnBegin()n"));
  1005.     if(m_startupStage >= ssPastFirstBuffer)
  1006.     {
  1007.         m_playerState.OnResume();
  1008.     }
  1009.     return HXR_OK;
  1010. }
  1011.     
  1012. // IHXClientAdviseSink
  1013. STDMETHODIMP
  1014. CHXAvPlayer::OnBuffering(ULONG32 type, UINT16 unPercentComplete)
  1015. {
  1016.     //DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnBuffering(type = %lu('%s'), percent = %u)n", type, dbg::BufferReason(type), unPercentComplete));
  1017.     if(m_startupStage < ssPastFirstBuffer) 
  1018.     {
  1019.         m_startupStage = ssPastFirstBuffer;
  1020.         dbg::DumpHeaders(m_hxPlayer);
  1021.         //XXXLCM consider just updating header and presentation info, etc. in call to
  1022.         // GetClipInfo() (or method such as UpdateClipInfo() that can be called beforehand);
  1023.         // we'd still have to cache the info when we stop; this will clip info is up to date
  1024.         // if sources are added and removed as presentation goes along (for smil case)
  1025.         // for smil all sources should be created by now
  1026.         m_clipInfo.CacheHeadersL(m_hxPlayer);
  1027.         m_clipInfo.CacheURLsL(m_hxPlayer);
  1028.         m_clipInfo.CachePresentationInfoL(m_hxPlayer);
  1029.         // now is earliest time to get best stream bitrate  values (i.e., 
  1030.         // subscribed surestream bitrate will be known, if applicable)
  1031.         m_clipInfo.SaveStreamBitrateValuesL(m_hxPlayer);
  1032.     }
  1033.     //
  1034.     // Buffering state is independent of main player state
  1035.     //
  1036.     // - cannot assume we get a value of 0 for first buffer
  1037.     // - can assume we get 100 for buffer complete
  1038.     // - we often get repeated calls with no change in value from last time
  1039.     // - sometimes after 100 we get more buffering (re-buffering)
  1040.     // - we do not get other messages indicating play is resuming
  1041.     // - if seeking, we do get subsequent OnPostSeek
  1042.     //
  1043.     
  1044.     m_playerState.OnBuffering(type, unPercentComplete);
  1045.     return HXR_OK;
  1046. }
  1047.     
  1048. // IHXClientAdviseSink
  1049. //
  1050. // called when about to resolve host name via dns lookup
  1051. STDMETHODIMP
  1052. CHXAvPlayer::OnContacting(const char* pHostName)
  1053. {
  1054.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnContacting(): '%s'n", pHostName));
  1055.     return HXR_OK;
  1056. }
  1057. // IHXClientAdviseSink
  1058. STDMETHODIMP
  1059. CHXAvPlayer::ErrorOccurred(const UINT8 unSeverity,  
  1060. const ULONG32 ulHXCode,
  1061. const ULONG32 ulUserCode,
  1062. const char* pUserString,
  1063. const char* pMoreInfoURL)
  1064. {
  1065.     // do not continue through playlist or loop after an error
  1066.     m_bEnableAutoPlayNext = false; 
  1067.     
  1068.     if( m_clipInfo.GetSourceCount() > 0 && m_clipInfo.GetStreamCount(0) == 0 )
  1069.     {
  1070.         //
  1071.         // No stream headers are currently cached for the first source. 
  1072.         // It is possible that they are now available. (This can be the
  1073.         // case if the error occurs after the request is issued but before 
  1074.         // the presentation opens.) We now try to cache the stream
  1075.         // headers in order to enable the user to be able to see 
  1076.         // as much clip info as possible after this error.
  1077.         // 
  1078.         HX_ASSERT(m_hxPlayer);
  1079.         UINT32 streamCount = player::GetStreamCount(m_hxPlayer, 0);
  1080.         if(streamCount > 0)
  1081.         {
  1082.             m_clipInfo.CacheHeadersL(m_hxPlayer);
  1083.         }
  1084.     }
  1085.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::OnError(): code = 0x%08x(%s), user code = 0x%08x', sev = %u(%s)n", ulHXCode, dbg::ErrorCode(ulHXCode), ulUserCode, unSeverity, dbg::SevCode(unSeverity)));
  1086.     if(!m_bAccessPointSetupFailed)
  1087.     {
  1088.         m_playerState.OnError(ulHXCode);
  1089.     }
  1090.     return HXR_OK;
  1091. }
  1092. //IHXGroupSink
  1093. STDMETHODIMP
  1094. CHXAvPlayer::GroupAdded(UINT16 uGroupIndex,IHXGroup* pGroup)
  1095. {
  1096.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::GroupAdded()n"));
  1097.     return HXR_OK;
  1098. }
  1099. //IHXGroupSink
  1100. STDMETHODIMP
  1101. CHXAvPlayer::GroupRemoved(UINT16 uGroupIndex, IHXGroup* pGroup)
  1102. {
  1103.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::GroupRemoved()n"));
  1104.     return HXR_OK;
  1105. }
  1106. //IHXGroupSink
  1107. STDMETHODIMP
  1108. CHXAvPlayer::AllGroupsRemoved()
  1109. {
  1110.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::AllGroupsRemoved()n"));
  1111.     return HXR_OK;
  1112. }
  1113. //IHXGroupSink
  1114. STDMETHODIMP
  1115. CHXAvPlayer::TrackAdded(UINT16 uGroupIndex, UINT16 uTrackIndex,IHXValues* pTrack)
  1116. {
  1117.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::TrackAdded(): group idx = %u; track idx = %un", uGroupIndex, uTrackIndex));
  1118.     dbg::DumpObject(pTrack);
  1119.     if(!m_bAccessPointSetupFailed)
  1120.     {
  1121.         // for smil case
  1122.         if(HasRemoteURL(pTrack))
  1123.         {
  1124.             //XXXLCM to be 100% correct we should look at other track notifications
  1125.             //and deal convoluted cases where we have both network and local links. For
  1126.             //example, if we have a network source followed by a local source in a smil
  1127.             //file we will incorrectly advertise that the current source is remote once
  1128.             //the local source becomes current
  1129.             
  1130.             OnNetConnect(); 
  1131.         }
  1132.     }
  1133.     
  1134.     return HXR_OK;
  1135. }
  1136. //IHXGroupSink
  1137. STDMETHODIMP
  1138. CHXAvPlayer::TrackRemoved(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pTrack)
  1139. {
  1140.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::TrackRemoved()n"));
  1141.     return HXR_OK;
  1142. }
  1143. //IHXGroupSink
  1144. STDMETHODIMP
  1145. CHXAvPlayer::TrackStarted(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pTrack)
  1146. {
  1147.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::TrackStarted()n"));
  1148.     return HXR_OK;
  1149. }
  1150. //IHXGroupSink
  1151. STDMETHODIMP
  1152. CHXAvPlayer::TrackStopped(UINT16 uGroupIndex, UINT16 uTrackIndex, IHXValues* pTrack)
  1153. {
  1154.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::TrackStopped()n"));
  1155.     return HXR_OK;
  1156. }
  1157. //IHXGroupSink
  1158. STDMETHODIMP
  1159. CHXAvPlayer::CurrentGroupSet(UINT16 uGroupIndex, IHXGroup* pGroup)
  1160. {
  1161.     DPRINTF(SYMP_INFO, ("CHXAvPlayer::CurrentGroupSet()n"));
  1162.     if(!m_bAccessPointSetupFailed)
  1163.     {
  1164.         // look for a non-local url in this group
  1165.         UINT16 count = pGroup->GetTrackCount();
  1166.         for(UINT16 idx = 0; idx < count; ++idx)
  1167.         {
  1168.             DPRINTF(SYMP_INFO, ("CHXAvPlayer::CurrentGroupSet(): group %un", idx));
  1169.             comptr<IHXValues> val;
  1170.             pGroup->GetTrack(idx, val.AsRef());
  1171.             dbg::DumpObject(val); // 'url'
  1172.         
  1173.             if(HasRemoteURL(val))
  1174.             {
  1175.                 OnNetConnect();
  1176.             }
  1177.         }
  1178.     }
  1179.     return HXR_OK;
  1180. }