Bug 1075400 - [RTSP] Ensure PausedDone completes before sending a PLAY request to RTSP server. r=sworkman
authorEthan Tseng <ettseng@mozilla.com>
Fri, 03 Oct 2014 16:21:31 +0800
changeset 232160 878c12dad5a1a20411595f48a7962d076503ab29
parent 232107 e0d714f43edc0363136d7f563aecc6bdc83482bd
child 232161 7079f5535e67de76b4dfdc59b19c729aa148f537
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssworkman
bugs1075400
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1075400 - [RTSP] Ensure PausedDone completes before sending a PLAY request to RTSP server. r=sworkman
netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
netwerk/protocol/rtsp/rtsp/RTSPSource.h
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
@@ -44,16 +44,17 @@ RTSPSource::RTSPSource(
     : mURL(url),
       mUserAgent(userAgent),
       mUIDValid(uidValid),
       mUID(uid),
       mState(DISCONNECTED),
       mFinalResult(OK),
       mDisconnectReplyID(0),
       mLatestPausedUnit(0),
+      mPlayPending(false),
       mSeekGeneration(0)
 
 {
     CHECK(aListener != NULL);
 
     // Use main thread pointer, but allow access off main thread.
     mListener =
       new nsMainThreadPtrHolder<nsIStreamingProtocolListener>(aListener, false);
@@ -208,84 +209,94 @@ status_t RTSPSource::seekTo(int64_t seek
 }
 
 void RTSPSource::performPlay(int64_t playTimeUs) {
     if (mState == DISCONNECTED) {
         LOGI("We are in a idle state, restart play");
         start();
         return;
     }
-    if (mState != CONNECTED && mState != PAUSING) {
+    // If state is PAUSING, which means a previous PAUSE request is still being
+    // processed, put off the PLAY request until PausedDone.
+    if (mState == PAUSING) {
+        mPlayPending = true;
         return;
     }
-    if (mState == PAUSING) {
-      playTimeUs = mLatestPausedUnit;
+    // Reject invalid state transition.
+    if (mState != CONNECTED && mState != PAUSED) {
+        return;
+    }
+    // Use the latest received frame time if we were paused.
+    if (mState == PAUSED) {
+        playTimeUs = mLatestPausedUnit;
     }
 
     int64_t duration = 0;
     getDuration(&duration);
     MOZ_ASSERT(playTimeUs < duration,
                "Should never receive an out of bounds play time!");
     if (playTimeUs >= duration) {
-      return;
+        return;
     }
 
     LOGI("performPlay : duration=%lld playTimeUs=%lld", duration, playTimeUs);
     mState = PLAYING;
     mHandler->play(playTimeUs);
 }
 
 void RTSPSource::performPause() {
+    // Reject invalid state transition.
     if (mState != PLAYING) {
         return;
     }
     LOGI("performPause :");
     for (size_t i = 0; i < mTracks.size(); ++i) {
-      TrackInfo *info = &mTracks.editItemAt(i);
-      info->mLatestPausedUnit = 0;
+        TrackInfo *info = &mTracks.editItemAt(i);
+        info->mLatestPausedUnit = 0;
     }
     mLatestPausedUnit = 0;
 
     mState = PAUSING;
     mHandler->pause();
 }
 
 void RTSPSource::performResume() {
 // TODO, Bug 895753.
 }
 
 void RTSPSource::performSuspend() {
 // TODO, Bug 895753.
 }
 
 void RTSPSource::performPlaybackEnded() {
-    // Transition from PLAYING to CONNECTED state so that we are ready to
-    // perform an another play operation.
+    // Reject invalid state transition.
     if (mState != PLAYING) {
         return;
     }
+    // Transition from PLAYING to CONNECTED state so that we are ready to
+    // perform an another play operation.
     mState = CONNECTED;
 }
 
 void RTSPSource::performSeek(int64_t seekTimeUs) {
-    if (mState != CONNECTED && mState != PLAYING && mState != PAUSING) {
+    if (mState != CONNECTED && mState != PLAYING && mState != PAUSED) {
         return;
     }
 
     int64_t duration = 0;
     getDuration(&duration);
     MOZ_ASSERT(seekTimeUs < duration,
                "Should never receive an out of bounds seek time!");
     if (seekTimeUs >= duration) {
-      return;
+        return;
     }
 
     for (size_t i = 0; i < mTracks.size(); ++i) {
-      TrackInfo *info = &mTracks.editItemAt(i);
-      info->mLatestPausedUnit = 0;
+        TrackInfo *info = &mTracks.editItemAt(i);
+        info->mLatestPausedUnit = 0;
     }
     mLatestPausedUnit = 0;
 
     LOGI("performSeek: %llu", seekTimeUs);
     mState = SEEKING;
     mHandler->seek(seekTimeUs);
 }
 
@@ -361,31 +372,42 @@ void RTSPSource::onMessageReceived(const
                 info->mLatestPausedUnit = 0;
             }
             mLatestPausedUnit = 0;
             break;
         }
 
         case RtspConnectionHandler::kWhatPausedDone:
         {
+            // Reject invalid state transition.
+            if (mState != PAUSING) {
+                return;
+            }
+            mState = PAUSED;
+
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 TrackInfo *info = &mTracks.editItemAt(i);
                 info->mLatestPausedUnit = info->mLatestReceivedUnit;
             }
 
             // The timestamp after a 'Pause' is done is the earliest
             // timestamp among all of the latest received units.
             TrackInfo *info = &mTracks.editItemAt(0);
             mLatestPausedUnit = info->mLatestReceivedUnit;
             for (size_t i = 1; i < mTracks.size(); ++i) {
                 TrackInfo *info = &mTracks.editItemAt(i);
                 if (mLatestPausedUnit > info->mLatestReceivedUnit) {
                     mLatestPausedUnit = info->mLatestReceivedUnit;
                 }
             }
+
+            if (mPlayPending) {
+                mPlayPending = false;
+                performPlay(mLatestPausedUnit);
+            }
             break;
         }
 
         case RtspConnectionHandler::kWhatAccessUnitComplete:
         {
             size_t trackIndex;
             CHECK(msg->findSize("trackIndex", &trackIndex));
             CHECK_LT(trackIndex, mTracks.size());
@@ -426,17 +448,17 @@ void RTSPSource::onMessageReceived(const
                         / info->mTimeScale
                         * 1000000ll
                         + info->mNormalPlaytimeUs;
 
                 accessUnit->meta()->setInt64("timeUs", nptUs);
                 info->mLatestReceivedUnit = nptUs;
                 // Drop the frames that are older than the frames in the queue.
                 if (info->mLatestPausedUnit && (int64_t)info->mLatestPausedUnit > nptUs) {
-                  break;
+                    break;
                 }
                 source->queueAccessUnit(accessUnit);
             }
 
             onTrackDataAvailable(trackIndex);
             break;
         }
 
@@ -571,44 +593,44 @@ void RTSPSource::onConnected(bool isSeek
         meta = new mozilla::net::RtspMetaData();
         meta->SetTotalTracks(numTracks);
         meta->SetMimeType(mimeType);
 
         CHECK(format->findInt64(kKeyDuration, &int64Value));
         meta->SetDuration(int64Value);
 
         if (isAudio) {
-          CHECK(format->findInt32(kKeyChannelCount, &int32Value));
-          meta->SetChannelCount(int32Value);
+            CHECK(format->findInt32(kKeyChannelCount, &int32Value));
+            meta->SetChannelCount(int32Value);
 
-          CHECK(format->findInt32(kKeySampleRate, &int32Value));
-          meta->SetSampleRate(int32Value);
+            CHECK(format->findInt32(kKeySampleRate, &int32Value));
+            meta->SetSampleRate(int32Value);
         } else {
-          CHECK(format->findInt32(kKeyWidth, &int32Value));
-          meta->SetWidth(int32Value);
+            CHECK(format->findInt32(kKeyWidth, &int32Value));
+            meta->SetWidth(int32Value);
 
-          CHECK(format->findInt32(kKeyHeight, &int32Value));
-          meta->SetHeight(int32Value);
+            CHECK(format->findInt32(kKeyHeight, &int32Value));
+            meta->SetHeight(int32Value);
         }
 
         // Optional meta data.
         const void *data;
         uint32_t type;
         size_t length = 0;
 
         if (format->findData(kKeyESDS, &type, &data, &length)) {
-          nsCString esds;
-          esds.Assign((const char *)data, length);
-          meta->SetEsdsData(esds);
+            nsCString esds;
+            esds.Assign((const char *)data, length);
+            meta->SetEsdsData(esds);
         }
 
         if (format->findData(kKeyAVCC, &type, &data, &length)) {
-          nsCString avcc;
-          avcc.Assign((const char *)data, length);
-          meta->SetAvccData(avcc);
+            nsCString avcc;
+            avcc.Assign((const char *)data, length);
+            meta->SetAvccData(avcc);
         }
 
         mListener->OnConnected(i, meta.get());
         mTracks.push(info);
     }
 
     mState = CONNECTED;
 }
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.h
@@ -84,16 +84,17 @@ private:
     };
 
     enum State {
         DISCONNECTED,
         CONNECTING,
         CONNECTED,
         SEEKING,
         PAUSING,
+        PAUSED,
         PLAYING,
     };
 
     enum Flags {
         // Don't log any URLs.
         kFlagIncognito = 1,
     };
 
@@ -112,16 +113,17 @@ private:
     AString mURL;
     AString mUserAgent;
     bool mUIDValid;
     uid_t mUID;
     State mState;
     status_t mFinalResult;
     uint32_t mDisconnectReplyID;
     uint64_t mLatestPausedUnit;
+    bool mPlayPending;
 
     sp<ALooper> mLooper;
     sp<AHandlerReflector<RTSPSource> > mReflector;
     sp<RtspConnectionHandler> mHandler;
 
     Vector<TrackInfo> mTracks;
     sp<AnotherPacketSource> mAudioTrack;
     sp<AnotherPacketSource> mVideoTrack;