chxavplayer.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 1,374 行 · 第 1/3 页

CPP
1,374
字号
/************************************************************************
 * chxavplayer.cpp
 * ---------------
 *
 * Synopsis:
 * Contains the implementation of the CHXAvPlayer class.  This class
 * coordinates the client core to play back a file or url.
 *
 * Target:
 * Symbian OS
 *
 *
 * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
 *
 *****************************************************************************/
  

#include "hxtypes.h"
#include "ihxaccesspoint.h"

#include "hxsym_debug.h"
#include "hxsym_leaveutil.h"
#include "hxdebug_hxapi.h"
#include "hxapihelp_player.h"
#include "hxapihelp.h"
#include "hxgroup.h" //IHXGroupSink
#include "chxavcleanstring.h"
#include "chxavramparser.h"
#include "chxavconfignames.h"
#include "chxavcleanupstack.h"
#include "chxavnetconnectui.h"
#include "comptr.h"
#include "comptr_traits.h"
#include "chxavutil.h"
#include "chxavplayer.h"

namespace
{
   
CHXAvFile::FileType GetFileTypeFromUrlL(const char* pURL)
{
    // get path-only part of url in a descriptor
    HBufC* pPath = CHXAvUtil::AllocStdPathFromPlayerUrlL(pURL);
    AUTO_PUSH_POP_DEL(pPath);

    // handle case where local file is a ram/playlist
    return CHXAvFile::GetFileType(*pPath);
}

bool HasRemoteURL(IHXValues* pVal)
{
    CHXString strURL;
    if(val::GetString(pVal, "url", strURL))
    {
        if(!CHXAvUtil::IsLocal(strURL) || 0 == strURL.Find("helix-sdp"))
        {
            return true;
        }
    }
    return false;

}

} // locals

// IUnknown implementation body...
BEGIN_INTERFACE_LIST(CHXAvPlayer)
    INTERFACE_LIST_ENTRY(IID_IHXClientAdviseSink, IHXClientAdviseSink)
    INTERFACE_LIST_ENTRY(IID_IHXAccessPointSelector, IHXAccessPointSelector)
    INTERFACE_LIST_ENTRY(IID_IHXErrorSink, IHXErrorSink)
    INTERFACE_LIST_ENTRY(IID_IHXGroupSink, IHXGroupSink)
    INTERFACE_LIST_ENTRY_DELEGATE_BLIND
    (
        QueryInterfaceDelegates
    )
END_INTERFACE_LIST

HX_RESULT CHXAvPlayer::QueryInterfaceDelegates(REFIID riid, void** ppvObj)
{
    if( IsEqualIID(riid, IID_IHXPreferences) )
    {
        return m_spEngine->GetPrefs()->QueryInterface(riid, ppvObj);
    }
    else if( IsEqualIID(riid, IID_IHXSiteSupplier) )
    {
        return m_siteSupplier->QueryInterface(riid, ppvObj);
    }

    return HXR_NOINTERFACE;
}

 
/*
 * CHXAvPlayer
 * -----------
 *
 */
CHXAvPlayer::CHXAvPlayer() 
: m_clipDuration(0)
, m_clipPos(0)
, m_volumeStep(kVolumeMax / 10) // must match nokia vol control XXXLCM hardcoded
, m_bEnableAutoPlayNext(true)
, m_bIsTruePlaylistLoaded(false)
, m_bResumeOnEndSeek(false)
, m_hxPlayer(0)
, m_startupStage(ssStopped)
, m_bIsRemotePlayback(false)
, m_bAccessPointSetupFailed(false)
{
}




/*
 * ~CHXAvPlayer
 * -------------
 * Destructor.
 *
 */
CHXAvPlayer::~CHXAvPlayer()
{
}



/*
 * ConstructL
 * ----------
 *
 * Client must call InitPlayerL() before attempting playback
 *
 */
void
CHXAvPlayer::ConstructL(const CHXClientEngineManagerPtr& spEngine, 
                        const CHXAvNetConnectUIPtr& pAccessPointSelector)
{
    DPRINTF(SYMP_INFO, ("CHXAvPlayer::ConstructL()\n"));

    HX_ASSERT(spEngine);
    m_spEngine = spEngine;

    m_playerState.ConstructL();

    // timer for playing current clip
    const CHXAvCommand& cmdPlay = 
	MakeCommand(this, &CHXAvPlayer::PlayCurrent);
    m_cbPlay.ConstructL(cmdPlay);

    // for convenience
    m_prefs = m_spEngine->GetPrefs();
    m_factory = m_spEngine->GetFactory();

    // ap selector handles some ui logic for selecting and setting access points
    m_apSelector = pAccessPointSelector;

}


void CHXAvPlayer::Play(const TDesC& url)
{
    HX_ASSERT(CHXAvUtil::IsValidUrl(url));
    CHXString str = CHXAvStringUtils::DescToString(url);
    Play(str);
}

////////////////////////////////////////
// helper
//
// create a playlist and iterator for ram/playlist
//
void CHXAvPlayer::DoPlaylistInit(const char* pURL)
{
    CHXAvURLRep urlRep(pURL);

    // these should be reset with each (main url) play attempt
    HX_ASSERT(!m_pPlaylist);
    HX_ASSERT(!m_pPlaylist);
    HX_ASSERT(!m_bIsTruePlaylistLoaded);
      
    m_pPlaylist = CHXAvRAMParser::Parse(urlRep.Path());
    if( m_pPlaylist )
    {
#ifdef PLAYLIST_END_IN_LST_ONLY
        static const char * const k_pPlaylistExt = ".lst"; // XXXLCM

        // if ram file has playlist extension, treat it as 'true playlist' (one that can be shuffled, etc.)
        
        INT32 idxDot = urlRep.Path().ReverseFind('.');
        if( idxDot != -1 )
        {
            CHXString ext = urlRep.Path().Mid(idxDot);
            m_bIsTruePlaylistLoaded = (0 == ext.CompareNoCase(k_pPlaylistExt));
        }
#else
	m_bIsTruePlaylistLoaded = true;
#endif

        // apply shuffle mode if this is a true playlist
        bool bShuffleModeOn = prefs::GetBool(m_prefs, CHXAV_ShuffleMode);
        if(m_bIsTruePlaylistLoaded && bShuffleModeOn)
        {
            m_pPlaylist->Shuffle();
        }

        m_pPlayItr = new (ELeave) CHXAvPlaylistItr(*m_pPlaylist);

        // set iterator loop mode off (even if player 'loop mode' on; that's handled elsewhere)
        m_pPlayItr->Loop(false);

        // ensure we are at beginning
        m_pPlayItr->ResetBegin(); 
    }
}




/*
 * Play
 * ----
 * Handle user command to play the given url.  
 *
 */

void 
CHXAvPlayer::Play(const char *url) // XXXLCM can leave
{
   
    DPRINTF(SYMP_INFO, ("CHXAvPlayer::Play(): url = '%s'\n", url));
    HX_ASSERT(m_hxPlayer);

    // main url is requested url (ram or single clip)
    m_mainUrl = url;
    m_playUrl = "";

    // reset playlist-related stuff on new main url play attempt
    m_pPlaylist = 0;
    m_pPlayItr = 0;
    m_bIsTruePlaylistLoaded = false;

    // see if we can squeeze blood from a turnip
    User::CompressAllHeaps();

    if(CHXAvUtil::IsFileUrl(url))
    {
        // handle case where local file is a ram/playlist
        CHXAvFile::FileType type = GetFileTypeFromUrlL(url); //XXXLCM can leave
        if( CHXAvFile::ftRam == type )
        {
            DoPlaylistInit(url);
            if(m_pPlayItr)
            {
                DoPlayImp(m_pPlayItr->Current().String());
            } 	
            else
            {
                // invalid ram file
                HX_ASSERT(false);
                m_playerState.OnError(HXR_INVALID_FILE);
            }
        }
        else
        {
            // local non-ram file
            DoPlayImp(url);
        }
    }
    else
    {
        // remote url
        DoPlayImp(url);
    }
}


/*
 * PlayCurrent
 * ----
 * Play the current url  
 *
 */

void 
CHXAvPlayer::PlayCurrent()
{
    HX_ASSERT(!m_playUrl.IsEmpty());
    DoPlayImp(m_playUrl);
}


/*
 * Reset state variables for current clip that won't make sense
 * once the clip is unloaded. After a stop the last played
 * clip remains "loaded", i.e., ready for re-play. The UI should
 * continue to reflect attributes (and provide access to clip info)
 * that pertain to the stopped (still-loaded) clip.
 *
 * A clips is "unloaded" after an advance to next clip in playlist
 * or when replaced by a new clip upon a new play request. Also, no
 * clip is loaded when this player object is first created.
 *
 */
void 
CHXAvPlayer::ResetUnloadedClipState()
{
    // since play url had changed, current headers and bitrate values no longer apply
    m_clipInfo.Reset();

    // unknown for next clip
    m_clipDuration = 0;
    m_bIsRemotePlayback = false;
}



/* 
 * DoPlayImp
 * ------
 *
 */
void
CHXAvPlayer::DoPlayImp(const char* url)
{
    if( m_playUrl != url)
    {
        m_playUrl = url;
    
        // reset stuff we won't know until we load 
        ResetUnloadedClipState();
    }

    // reset stuff for each play
    m_bEnableAutoPlayNext = true;
    m_clipPos = 0;
    m_startupStage = ssPastInitiate;
    m_bAccessPointSetupFailed = false;

    m_playerState.OnPlayInitiate(url);


    // fixup url in case we need to add duration option to it
    CHXString fixedUrl(url); // XXXLCM cleanup stack; function can leave
    
    UINT32 secIntro = prefs::GetUINT32(m_prefs, CHXAV_ClipIntroSecs);
    if( m_bIsTruePlaylistLoaded && secIntro != 0 )
    {
	// Force end of each clip at N seconds into clip. If actual clip
	// duration is shorter than N seconds, then the clip will end at
	// its proper end time.
	static const char * const k_Format = "?end=%lu";
	CHXString strOption;
	strOption.Format(k_Format, secIntro);
	fixedUrl += strOption;
    }
    
    HX_ASSERT(m_hxPlayer);
    HX_RESULT hxr = m_hxPlayer->OpenURL(fixedUrl);
    if( HXR_OK == hxr)
    {
	hxr = m_hxPlayer->Begin();
	if (HXR_OK == hxr)
	{
	    // the file header can be gotten at this point
	    m_clipInfo.CacheHeadersL(m_hxPlayer);
            
            // we detect need for net connect later on for smil and sdp
            if(!m_bAccessPointSetupFailed && !CHXAvUtil::IsLocal(url))
            {
                OnNetConnect();
            }
	}
    }
    
    if( hxr != HXR_OK )
    {
	m_playerState.OnError(hxr);
    }
}

// heleper
void CHXAvPlayer::OnNetConnect()
{
    m_bIsRemotePlayback = true;
    if(m_startupStage < ssPastFirstBuffer)
    {
        m_playerState.OnNetConnect();
    }
}



/*
 * CanSeek
 * ---------
 * Returns true if it is safe to seek.
 *
 */
bool 
CHXAvPlayer::CanSeek() const
{
    bool bCanSeek = false;
    switch (m_playerState.GetState())
    {
    case CHXAvPlayerState::Playing:
    case CHXAvPlayerState::Seeking:
    case CHXAvPlayerState::Paused:
        bCanSeek = !m_clipInfo.IsLive(); // && (m_startupStage > ssPastFirstBuffer);
	break;
    default:
	break;
    }
    return bCanSeek;

}



/*
 * CanPause
 * ----------
 * Return true if we are in a state where it is safe to pause.
 *
 */
bool CHXAvPlayer::CanPause() const
{
    bool bCanPause = false;
    switch (m_playerState.GetState())
    {
    case CHXAvPlayerState::Playing:
    case CHXAvPlayerState::Connecting:
	bCanPause = true;
	break;
    default:
	break;
    }
    return bCanPause;

}
 




/*
 * CanResume
 * -----------
 * Return true if we can resume from current state.
 */
bool 
CHXAvPlayer::CanResume() const
{
    return (!m_mainUrl.IsEmpty() && (IsPaused() || IsStopped()));
}


/*
 * Stop

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?