Bug 1021006 - [RTSP] Browser pops up a network warning message in the end of RTSP streaming. r=sworkman, a=2.0+
authorBenjamin Chen <bechen@mozilla.com>
Tue, 17 Jun 2014 17:47:13 +0800
changeset 207430 ae91134619c5219c786ceb2fbcac0a3aa9787da0
parent 207429 f62422f3864cc6743d4649f2f9b2da4e5a5ab76c
child 207431 2016c180a540a97dd44965168c80fa305857cbcb
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssworkman, 2
bugs1021006
milestone32.0a2
Bug 1021006 - [RTSP] Browser pops up a network warning message in the end of RTSP streaming. r=sworkman, a=2.0+
content/media/omx/RtspOmxDecoder.cpp
content/media/omx/RtspOmxDecoder.h
netwerk/base/public/nsIStreamingProtocolController.idl
netwerk/ipc/PRtspController.ipdl
netwerk/protocol/rtsp/controller/RtspController.cpp
netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
netwerk/protocol/rtsp/controller/RtspControllerParent.h
netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
netwerk/protocol/rtsp/rtsp/RTSPSource.h
--- a/content/media/omx/RtspOmxDecoder.cpp
+++ b/content/media/omx/RtspOmxDecoder.cpp
@@ -18,10 +18,30 @@ MediaDecoder* RtspOmxDecoder::Clone()
 
 MediaDecoderStateMachine* RtspOmxDecoder::CreateStateMachine()
 {
   return new MediaDecoderStateMachine(this,
                                       new RtspOmxReader(this),
                                       mResource->IsRealTime());
 }
 
+void RtspOmxDecoder::ApplyStateToStateMachine(PlayState aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MediaDecoder::ApplyStateToStateMachine(aState);
+
+  // Notify RTSP controller if the play state is ended.
+  // This is necessary for RTSP controller to transit its own state.
+  if (aState == PLAY_STATE_ENDED) {
+    nsRefPtr<RtspMediaResource> resource = mResource->GetRtspPointer();
+    if (resource) {
+      nsIStreamingProtocolController* controller =
+        resource->GetMediaStreamController();
+      if (controller) {
+        controller->PlaybackEnded();
+      }
+    }
+  }
+}
+
 } // namespace mozilla
 
--- a/content/media/omx/RtspOmxDecoder.h
+++ b/content/media/omx/RtspOmxDecoder.h
@@ -25,15 +25,17 @@ public:
   : MediaDecoder() {
     MOZ_COUNT_CTOR(RtspOmxDecoder);
   }
 
   ~RtspOmxDecoder() {
     MOZ_COUNT_DTOR(RtspOmxDecoder);
   }
 
-  virtual MediaDecoder* Clone() MOZ_OVERRIDE;
-  virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE;
+  virtual MediaDecoder* Clone() MOZ_OVERRIDE MOZ_FINAL;
+  virtual MediaDecoderStateMachine* CreateStateMachine() MOZ_OVERRIDE MOZ_FINAL;
+  virtual void ApplyStateToStateMachine(PlayState aState)
+                                        MOZ_OVERRIDE MOZ_FINAL;
 };
 
 } // namespace mozilla
 
 #endif
--- a/netwerk/base/public/nsIStreamingProtocolController.idl
+++ b/netwerk/base/public/nsIStreamingProtocolController.idl
@@ -110,17 +110,17 @@ interface nsIStreamingProtocolListener :
      * @param reason The reason of disconnection.
      */
     void onDisconnected(in uint8_t index, in nsresult reason);
 };
 
 /**
  * Media stream controller API: control and retrieve meta data from media stream.
  */
-[uuid(a9bdd4b0-8559-11e2-9e96-0800200c9a66)]
+[uuid(4ce040f0-c50d-461f-94e2-af5a77fe13a5)]
 interface nsIStreamingProtocolController : nsISupports
 {
     /**
      * Preprare the URI before we can start the connection.
      * @param aUri The URI of the media stream.
      */
     void init(in nsIURI aUri);
 
@@ -168,13 +168,19 @@ interface nsIStreamingProtocolController
     void seek(in unsigned long long seekTimeUs);
 
     /*
      * Tell the streaming server to stop the
      * media stream and close the connection.
      */
     void stop();
 
+    /*
+     * Notify the streaming controller that the playback has ended.
+     * The controller might have to perform certain internal state transition.
+     */
+    void playbackEnded();
+
     /**
      * Total number of audio/video tracks.
      */
     readonly attribute octet totalTracks;
 };
--- a/netwerk/ipc/PRtspController.ipdl
+++ b/netwerk/ipc/PRtspController.ipdl
@@ -39,16 +39,17 @@ async protocol PRtspController
 parent:
   AsyncOpen(URIParams aURI);
   Play();
   Pause();
   Resume();
   Suspend();
   Seek(uint64_t offset);
   Stop();
+  PlaybackEnded();
   __delete__();
 
 child:
   OnMediaDataAvailable(uint8_t index,
                        nsCString data,
                        uint32_t length,
                        uint32_t offset,
                        RtspMetadataParam[] meta);
--- a/netwerk/protocol/rtsp/controller/RtspController.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspController.cpp
@@ -364,10 +364,23 @@ RtspController::Init(nsIURI *aURI)
   rv = aURI->GetAsciiSpec(mSpec);
   if (NS_FAILED(rv)) return rv;
 
   mURI = aURI;
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+RtspController::PlaybackEnded()
+{
+  LOG(("RtspController::PlaybackEnded()"));
+  if (!mRtspSource.get()) {
+    MOZ_ASSERT(mRtspSource.get(), "mRtspSource should not be null!");
+    return NS_ERROR_NOT_INITIALIZED;
+  }
+
+  mRtspSource->playbackEnded();
+  return NS_OK;
+}
+
 } // namespace mozilla::net
 } // namespace mozilla
--- a/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspControllerChild.cpp
@@ -232,17 +232,18 @@ RtspControllerChild::GetTrackMetaData(
 enum IPCEvent
 {
   SendNoneEvent = 0,
   SendPlayEvent,
   SendPauseEvent,
   SendSeekEvent,
   SendResumeEvent,
   SendSuspendEvent,
-  SendStopEvent
+  SendStopEvent,
+  SendPlaybackEndedEvent
 };
 
 class SendIPCEvent : public nsRunnable
 {
 public:
   SendIPCEvent(RtspControllerChild *aController, IPCEvent aEvent)
     : mController(aController)
     , mEvent(aEvent)
@@ -276,16 +277,18 @@ public:
     } else if (mEvent == SendSeekEvent) {
       rv = mController->SendSeek(mSeekTime);
     } else if (mEvent == SendResumeEvent) {
       rv = mController->SendResume();
     } else if (mEvent == SendSuspendEvent) {
       rv = mController->SendSuspend();
     } else if (mEvent == SendStopEvent) {
       rv = mController->SendStop();
+    } else if (mEvent == SendPlaybackEndedEvent) {
+      rv = mController->SendPlaybackEnded();
     } else {
       LOG(("RtspControllerChild::SendIPCEvent"));
     }
     if (!rv) {
       return NS_ERROR_FAILURE;
     }
     return NS_OK;
   }
@@ -419,16 +422,34 @@ RtspControllerChild::GetTotalTracks(uint
   *aTracks = kRtspTotalTracks;
   if (mTotalTracks) {
     *aTracks = mTotalTracks;
   }
   LOG(("RtspControllerChild::GetTracks() %d", *aTracks));
   return NS_OK;
 }
 
+NS_IMETHODIMP
+RtspControllerChild::PlaybackEnded()
+{
+  LOG(("RtspControllerChild::PlaybackEnded"));
+
+  if (NS_IsMainThread()) {
+    if (!OKToSendIPC() || !SendPlaybackEnded()) {
+      return NS_ERROR_FAILURE;
+    }
+  } else {
+    nsresult rv = NS_DispatchToMainThread(
+                    new SendIPCEvent(this, SendPlaybackEndedEvent));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // RtspControllerChild::nsIStreamingProtocolListener
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 RtspControllerChild::OnMediaDataAvailable(uint8_t index,
                                           const nsACString & data,
                                           uint32_t length,
                                           uint32_t offset,
--- a/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
+++ b/netwerk/protocol/rtsp/controller/RtspControllerParent.cpp
@@ -162,16 +162,27 @@ RtspControllerParent::RecvStop()
   LOG(("RtspControllerParent::RecvStop()"));
   NS_ENSURE_TRUE(mController, true);
 
   nsresult rv = mController->Stop();
   NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
+bool
+RtspControllerParent::RecvPlaybackEnded()
+{
+  LOG(("RtspControllerParent::RecvPlaybackEnded()"));
+  NS_ENSURE_TRUE(mController, true);
+
+  nsresult rv = mController->PlaybackEnded();
+  SEND_DISCONNECT_IF_ERROR(rv)
+  return true;
+}
+
 NS_IMETHODIMP
 RtspControllerParent::OnMediaDataAvailable(uint8_t index,
                                            const nsACString & data,
                                            uint32_t length,
                                            uint32_t offset,
                                            nsIStreamingProtocolMetaData *meta)
 {
   NS_ENSURE_ARG_POINTER(meta);
--- a/netwerk/protocol/rtsp/controller/RtspControllerParent.h
+++ b/netwerk/protocol/rtsp/controller/RtspControllerParent.h
@@ -32,16 +32,17 @@ class RtspControllerParent : public PRts
 
   bool RecvAsyncOpen(const URIParams& aURI);
   bool RecvPlay();
   bool RecvPause();
   bool RecvResume();
   bool RecvSuspend();
   bool RecvSeek(const uint64_t& offset);
   bool RecvStop();
+  bool RecvPlaybackEnded();
 
  private:
   bool mIPCOpen;
   void ActorDestroy(ActorDestroyReason why);
   // RTSP URL refer to a stream or an aggregate of streams.
   nsCOMPtr<nsIURI> mURI;
   // The nsIStreamingProtocolController implementation.
   nsCOMPtr<nsIStreamingProtocolController> mController;
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
@@ -127,16 +127,23 @@ void RTSPSource::suspend()
 }
 
 void RTSPSource::seek(uint64_t timeUs)
 {
     LOGI("RTSPSource::seek() %llu", timeUs);
     seekTo(timeUs);
 }
 
+void RTSPSource::playbackEnded()
+{
+    LOGI("RTSPSource::playbackEnded()");
+    sp<AMessage> msg = new AMessage(kWhatPerformPlaybackEnded, mReflector->id());
+    msg->post();
+}
+
 status_t RTSPSource::feedMoreTSData() {
     return mFinalResult;
 }
 
 sp<MetaData> RTSPSource::getFormat(bool audio) {
     sp<AnotherPacketSource> source = getSource(audio);
 
     if (source == NULL) {
@@ -241,16 +248,25 @@ void RTSPSource::performPause() {
 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.
+    if (mState != PLAYING) {
+        return;
+    }
+    mState = CONNECTED;
+}
+
 void RTSPSource::performSeek(int64_t seekTimeUs) {
     if (mState != CONNECTED && mState != PLAYING && mState != PAUSING) {
         return;
     }
 
     int64_t duration = 0;
     getDuration(&duration);
     MOZ_ASSERT(seekTimeUs < duration,
@@ -305,16 +321,19 @@ void RTSPSource::onMessageReceived(const
         performPause();
         return;
     } else if (msg->what() == kWhatPerformResume) {
         performResume();
         return;
     } else if (msg->what() == kWhatPerformSuspend) {
         performSuspend();
         return;
+    } else if (msg->what() == kWhatPerformPlaybackEnded) {
+        performPlaybackEnded();
+        return;
     }
 
     CHECK_EQ(msg->what(), (uint32_t)kWhatNotify);
 
     int32_t what;
     int32_t isSeekable = 0;
     CHECK(msg->findInt32("what", &what));
 
@@ -670,17 +689,16 @@ void RTSPSource::onTrackDataAvailable(si
 
     if (mListener) {
         mListener->OnMediaDataAvailable(trackIndex, data, data.Length(), 0, meta.get());
     }
 }
 
 void RTSPSource::onTrackEndOfStream(size_t trackIndex)
 {
-    mState = CONNECTED;
     if (!mListener) {
         return;
     }
 
     nsRefPtr<nsIStreamingProtocolMetaData> meta;
     meta = new mozilla::net::RtspMetaData();
     meta->SetFrameType(MEDIASTREAM_FRAMETYPE_END_OF_STREAM);
 
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.h
@@ -49,16 +49,17 @@ public:
     void start();
     void stop();
 
     void play();
     void pause();
     void seek(uint64_t timeUs);
     void resume();
     void suspend();
+    void playbackEnded();
 
     status_t feedMoreTSData();
 
     sp<MetaData> getFormat(bool audio);
     status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
     status_t getDuration(int64_t *durationUs);
     status_t seekTo(int64_t seekTimeUs);
@@ -66,23 +67,24 @@ public:
 
     void onMessageReceived(const sp<AMessage> &msg);
 
 protected:
     ~RTSPSource();
 
 private:
     enum {
-        kWhatNotify          = 'noti',
-        kWhatDisconnect      = 'disc',
-        kWhatPerformSeek     = 'seek',
-        kWhatPerformPlay     = 'play',
-        kWhatPerformPause    = 'paus',
-        kWhatPerformResume   = 'resu',
-        kWhatPerformSuspend  = 'susp',
+        kWhatNotify               = 'noti',
+        kWhatDisconnect           = 'disc',
+        kWhatPerformSeek          = 'seek',
+        kWhatPerformPlay          = 'play',
+        kWhatPerformPause         = 'paus',
+        kWhatPerformResume        = 'resu',
+        kWhatPerformSuspend       = 'susp',
+        kWhatPerformPlaybackEnded = 'ende',
     };
 
     enum State {
         DISCONNECTED,
         CONNECTING,
         CONNECTED,
         SEEKING,
         PAUSING,
@@ -135,16 +137,18 @@ private:
     void performPlay(int64_t playTimeUs);
 
     void performPause();
 
     void performResume();
 
     void performSuspend();
 
+    void performPlaybackEnded();
+
     void onTrackDataAvailable(size_t trackIndex);
 
     void onTrackEndOfStream(size_t trackIndex);
 
     nsMainThreadPtrHandle<nsIStreamingProtocolListener> mListener;
     int mPrintCount;
 
     DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);