src/3rdparty/phonon/mmf/abstractmediaplayer.cpp
changeset 22 79de32ba3296
parent 18 2f34d5167611
child 37 758a864f9613
--- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp	Mon May 03 13:17:34 2010 +0300
+++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp	Fri May 14 16:40:13 2010 +0300
@@ -48,7 +48,7 @@
     (MediaObject *parent, const AbstractPlayer *player)
         :   AbstractPlayer(player)
         ,   m_parent(parent)
-        ,   m_playPending(false)
+        ,   m_pending(NothingPending)
         ,   m_positionTimer(new QTimer(this))
         ,   m_bufferStatusTimer(new QTimer(this))
         ,   m_mmfMaxVolume(NullMaxVolume)
@@ -74,14 +74,12 @@
         break;
 
     case LoadingState:
-        m_playPending = true;
+        setPending(PlayPending);
         break;
 
     case StoppedState:
     case PausedState:
-        doPlay();
-        startPositionTimer();
-        changeState(PlayingState);
+        startPlayback();
         break;
 
     case PlayingState:
@@ -103,14 +101,16 @@
     TRACE_CONTEXT(AbstractMediaPlayer::pause, EAudioApi);
     TRACE_ENTRY("state %d", privateState());
 
-    m_playPending = false;
     stopTimers();
 
     switch (privateState()) {
     case GroundState:
     case LoadingState:
+    case StoppedState:
+        setPending(PausePending);
+        break;
+
     case PausedState:
-    case StoppedState:
         // Do nothing
         break;
 
@@ -135,7 +135,7 @@
     TRACE_CONTEXT(AbstractMediaPlayer::stop, EAudioApi);
     TRACE_ENTRY("state %d", privateState());
 
-    m_playPending = false;
+    setPending(NothingPending);
     stopTimers();
 
     switch (privateState()) {
@@ -365,12 +365,31 @@
     doVolumeChanged();
 }
 
+void MMF::AbstractMediaPlayer::loadingComplete(int error)
+{
+    Q_ASSERT(Phonon::LoadingState == state());
+
+    if (KErrNone == error) {
+        updateMetaData();
+        changeState(StoppedState);
+    } else {
+        setError(tr("Loading clip failed"), error);
+    }
+}
+
 void MMF::AbstractMediaPlayer::playbackComplete(int error)
 {
     stopTimers();
 
+    if (KErrNone == error && !m_aboutToFinishSent) {
+        const qint64 total = totalTime();
+        emit MMF::AbstractPlayer::tick(total);
+        m_aboutToFinishSent = true;
+        emit aboutToFinish();
+    }
+
     if (KErrNone == error) {
-        changeState(StoppedState);
+        changeState(PausedState);
 
         // MediaObject::switchToNextSource deletes the current player, so we
         // call it via delayed slot invokation to ensure that this object does
@@ -379,6 +398,7 @@
     }
     else {
         setError(tr("Playback complete"), error);
+        emit finished();
     }
 }
 
@@ -393,15 +413,13 @@
 
 void MMF::AbstractMediaPlayer::positionTick()
 {
-    emitMarksIfReached();
-
     const qint64 current = currentTime();
+    emitMarksIfReached(current);
     emit MMF::AbstractPlayer::tick(current);
 }
 
-void MMF::AbstractMediaPlayer::emitMarksIfReached()
+void MMF::AbstractMediaPlayer::emitMarksIfReached(qint64 current)
 {
-    const qint64 current = currentTime();
     const qint64 total = totalTime();
     const qint64 remaining = total - current;
 
@@ -435,11 +453,39 @@
             m_aboutToFinishSent = false;
 }
 
+void MMF::AbstractMediaPlayer::setPending(Pending pending)
+{
+    const Phonon::State oldState = state();
+    m_pending = pending;
+    const Phonon::State newState = state();
+    if (newState != oldState)
+        emit stateChanged(newState, oldState);
+}
+
+void MMF::AbstractMediaPlayer::startPlayback()
+{
+    doPlay();
+    startPositionTimer();
+    changeState(PlayingState);
+}
+
 void MMF::AbstractMediaPlayer::bufferStatusTick()
 {
     emit MMF::AbstractPlayer::bufferStatus(bufferStatus());
 }
 
+Phonon::State MMF::AbstractMediaPlayer::phononState(PrivateState state) const
+{
+    Phonon::State result = AbstractPlayer::phononState(state);
+
+    if (PausePending == m_pending) {
+        Q_ASSERT(Phonon::StoppedState == result || Phonon::LoadingState == result);
+        result = Phonon::PausedState;
+    }
+
+    return result;
+}
+
 void MMF::AbstractMediaPlayer::changeState(PrivateState newState)
 {
     TRACE_CONTEXT(AbstractMediaPlayer::changeState, EAudioInternal);
@@ -447,20 +493,26 @@
     const Phonon::State oldPhononState = phononState(privateState());
     const Phonon::State newPhononState = phononState(newState);
 
-    // TODO: add some invariants to check that the transition is valid
-    AbstractPlayer::changeState(newState);
-
     if (LoadingState == oldPhononState && StoppedState == newPhononState) {
-        // Ensure initial volume is set on MMF API before starting playback
-        doVolumeChanged();
+        switch (m_pending) {
+        case NothingPending:
+            AbstractPlayer::changeState(newState);
+            break;
 
-        // Check whether play() was called while clip was being loaded.  If so,
-        // playback should be started now
-        if (m_playPending) {
-            TRACE_0("play was called while loading; starting playback now");
-            m_playPending = false;
-            play();
+        case PlayPending:
+            changeState(PlayingState); // necessary in order to apply initial volume
+            doVolumeChanged();
+            startPlayback();
+            break;
+
+        case PausePending:
+            AbstractPlayer::changeState(PausedState);
+            break;
         }
+
+        setPending(NothingPending);
+    } else {
+        AbstractPlayer::changeState(newState);
     }
 }