m_strPlayListFile = "";
m_nextPlaylistItem = -1;
m_bPlaybackStarting = false;
+ m_ePlayState = PLAY_STATE_NONE;
m_skinReloading = false;
#ifdef HAS_GLX
m_pKaraokeMgr->Stop();
#endif
- // tell system we are starting a file
- m_bPlaybackStarting = true;
+ {
+ CSingleLock lock(m_playStateMutex);
+ // tell system we are starting a file
+ m_bPlaybackStarting = true;
+
+ // for playing a new item, previous playing item's callback may already
+ // pushed some delay message into the threadmessage list, they are not
+ // expected be processed after or during the new item playback starting.
+ // so we clean up previous playing item's playback callback delay messages here.
+ int previousMsgsIgnoredByNewPlaying[] = {
+ GUI_MSG_PLAYBACK_STARTED,
+ GUI_MSG_PLAYBACK_ENDED,
+ GUI_MSG_PLAYBACK_STOPPED,
+ GUI_MSG_PLAYLIST_CHANGED,
+ GUI_MSG_PLAYLISTPLAYER_STOPPED,
+ GUI_MSG_PLAYLISTPLAYER_STARTED,
+ GUI_MSG_PLAYLISTPLAYER_CHANGED,
+ GUI_MSG_QUEUE_NEXT_ITEM,
+ 0
+ };
+ int dMsgCount = g_windowManager.RemoveThreadMessageByMessageIds(&previousMsgsIgnoredByNewPlaying[0]);
+ if (dMsgCount > 0)
+ CLog::Log(LOGDEBUG,"%s : Ignored %d playback thread messages", __FUNCTION__, dMsgCount);
+ }
// We should restart the player, unless the previous and next tracks are using
// one of the players that allows gapless playback (paplayer, dvdplayer)
delete m_pPlayer;
m_pPlayer = NULL;
}
+ else
+ {
+ // XXX: we had to stop the previous playing item, it was done in dvdplayer::OpenFile.
+ // but in paplayer::OpenFile, it sometimes just fade in without call CloseFile.
+ // but if we do not stop it, we can not distingush callbacks from previous
+ // item and current item, it will confused us then we can not make correct delay
+ // callback after the starting state.
+ m_pPlayer->CloseFile();
+ }
}
+ // now reset play state to starting, since we already stopped the previous playing item if there is.
+ // and from now there should be no playback callback from previous playing item be called.
+ m_ePlayState = PLAY_STATE_STARTING;
+
if (!m_pPlayer)
{
m_eCurrentPlayer = eNewCore;
if (item.HasPVRChannelInfoTag())
g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_NONE);
}
+
+ CSingleLock lock(m_playStateMutex);
m_bPlaybackStarting = false;
if (bResult)
{
- // we must have started, otherwise player might send this later
- if(IsPlaying())
- OnPlayBackStarted();
- else
- OnPlayBackEnded();
+ // play state: none, starting; playing; stopped; ended.
+ // last 3 states are set by playback callback, they are all ignored during starting,
+ // but we recorded the state, here we can make up the callback for the state.
+ CLog::Log(LOGDEBUG,"%s : OpenFile succeed, play state %d", __FUNCTION__, m_ePlayState);
+ switch (m_ePlayState)
+ {
+ case PLAY_STATE_PLAYING:
+ OnPlayBackStarted();
+ break;
+ // FIXME: it seems no meaning to callback started here if there was an started callback
+ // before this stopped/ended callback we recorded. if we callback started here
+ // first, it will delay send OnPlay announce, but then we callback stopped/ended
+ // which will send OnStop announce at once, so currently, just call stopped/ended.
+ case PLAY_STATE_ENDED:
+ OnPlayBackEnded();
+ break;
+ case PLAY_STATE_STOPPED:
+ OnPlayBackStopped();
+ break;
+ case PLAY_STATE_STARTING:
+ // neither started nor stopped/ended callback be called, that means the item still
+ // not started, we need not make up any callback, just leave this and
+ // let the player callback do its work.
+ break;
+ default:
+ break;
+ }
}
else
{
if(next < 0
|| next >= size)
OnPlayBackStopped();
+ m_ePlayState = PLAY_STATE_NONE;
}
return bResult;
void CApplication::OnPlayBackEnded()
{
+ CSingleLock lock(m_playStateMutex);
+ CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
+ m_ePlayState = PLAY_STATE_ENDED;
if(m_bPlaybackStarting)
return;
void CApplication::OnPlayBackStarted()
{
+ CSingleLock lock(m_playStateMutex);
+ CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
+ m_ePlayState = PLAY_STATE_PLAYING;
if(m_bPlaybackStarting)
return;
void CApplication::OnQueueNextItem()
{
+ CSingleLock lock(m_playStateMutex);
+ CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
+ if(m_bPlaybackStarting)
+ return;
// informs python script currently running that we are requesting the next track
// (does nothing if python is not loaded)
#ifdef HAS_PYTHON
void CApplication::OnPlayBackStopped()
{
+ CSingleLock lock(m_playStateMutex);
+ CLog::Log(LOGDEBUG,"%s : play state was %d, starting %d", __FUNCTION__, m_ePlayState, m_bPlaybackStarting);
+ m_ePlayState = PLAY_STATE_STOPPED;
if(m_bPlaybackStarting)
return;