Bug 1103188 - Keep track of stopped tracks in gUM stream listener. r=jib a=lizzard
💩💩 backed out by 4e86a0d1261a 💩 💩
authorAndreas Pehrson <pehrsons@gmail.com>
Wed, 30 Sep 2015 00:39:38 +0800
changeset 296673 1babaebeccc6
parent 296672 b199ea9f265c
child 296674 c458ad434a12
push id5281
push userkwierso@gmail.com
push date2015-11-09 17:50 +0000
treeherdermozilla-beta@3705005d2190 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, lizzard
bugs1103188
milestone43.0
Bug 1103188 - Keep track of stopped tracks in gUM stream listener. r=jib a=lizzard This is needed to avoid something like: * [old stream] stop track 1 -> deallocate MediaDevice for track 1 * [new stream] gUM() -> allocate MediaDevice for track 1 * [old stream] stop stream -> deallocate MediaDevice for track 1 * [new stream] gUM() -> start MediaDevice for track 1 (oops, MediaDevice was no more!)
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -3023,46 +3023,58 @@ void
 GetUserMediaCallbackMediaStreamListener::Invalidate()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
   if (mStopped) {
     return;
   }
   mStopped = true;
 
+  AudioDevice* audioDevice = nullptr;
+  VideoDevice* videoDevice = nullptr;
+  if (!mAudioStopped) {
+    audioDevice = mAudioDevice.get();
+  }
+  if (!mVideoStopped) {
+    videoDevice = mVideoDevice.get();
+  }
+
   // We can't take a chance on blocking here, so proxy this to another
   // thread.
   // Pass a ref to us (which is threadsafe) so it can query us for the
   // source stream info.
   MediaManager::PostTask(FROM_HERE,
     new MediaOperationTask(MEDIA_STOP,
                            this, nullptr, nullptr,
-                           mAudioDevice, mVideoDevice,
+                           audioDevice, videoDevice,
                            mFinished, mWindowID, nullptr));
+  mAudioStopped = !!audioDevice;
+  mVideoStopped = !!videoDevice;
 }
 
 // Doesn't kill audio
 // XXX refactor to combine with Invalidate()?
 void
 GetUserMediaCallbackMediaStreamListener::StopSharing()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
   if (mVideoDevice && !mStopped &&
       (mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Screen ||
        mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Application ||
        mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Window)) {
     // Stop the whole stream if there's no audio; just the video track if we have both
     if (!mAudioDevice) {
       Invalidate();
-    } else {
+    } else if (!mVideoStopped) {
       MediaManager::PostTask(FROM_HERE,
         new MediaOperationTask(MEDIA_STOP_TRACK,
                                this, nullptr, nullptr,
                                nullptr, mVideoDevice,
                                mFinished, mWindowID, nullptr));
+      mVideoStopped = true;
     }
   } else if (mAudioDevice &&
              mAudioDevice->GetMediaSource() == dom::MediaSourceEnum::AudioCapture) {
     nsCOMPtr<nsPIDOMWindow> window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
     MOZ_ASSERT(window);
     window->SetAudioCapture(false);
     MediaStreamGraph* graph =
       MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
@@ -3171,22 +3183,25 @@ GetUserMediaCallbackMediaStreamListener:
 void
 GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aTrackID, bool aIsAudio)
 {
   if (((aIsAudio && mAudioDevice) ||
        (!aIsAudio && mVideoDevice)) && !mStopped)
   {
     // XXX to support multiple tracks of a type in a stream, this should key off
     // the TrackID and not just the type
+    AudioDevice* audioDevice = aIsAudio  && !mAudioStopped ? mAudioDevice.get() : nullptr;
+    VideoDevice* videoDevice = !aIsAudio && !mVideoStopped ? mVideoDevice.get() : nullptr;
     MediaManager::PostTask(FROM_HERE,
       new MediaOperationTask(MEDIA_STOP_TRACK,
                              this, nullptr, nullptr,
-                             aIsAudio  ? mAudioDevice.get() : nullptr,
-                             !aIsAudio ? mVideoDevice.get() : nullptr,
+                             audioDevice, videoDevice,
                              mFinished, mWindowID, nullptr));
+    mAudioStopped = !!audioDevice;
+    mVideoStopped = !!videoDevice;
   } else {
     LOG(("gUM track %d ended, but we don't have type %s",
          aTrackID, aIsAudio ? "audio" : "video"));
   }
 }
 
 // Called from the MediaStreamGraph thread
 void
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -122,16 +122,18 @@ class GetUserMediaCallbackMediaStreamLis
 {
 public:
   // Create in an inactive state
   GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
     uint64_t aWindowID)
     : mMediaThread(aThread)
     , mWindowID(aWindowID)
     , mStopped(false)
+    , mAudioStopped(false)
+    , mVideoStopped(false)
     , mFinished(false)
     , mLock("mozilla::GUMCMSL")
     , mRemoved(false) {}
 
   ~GetUserMediaCallbackMediaStreamListener()
   {
     unused << mMediaThread;
     // It's OK to release mStream on any thread; they have thread-safe
@@ -296,16 +298,24 @@ public:
 
 private:
   // Set at construction
   base::Thread* mMediaThread;
   uint64_t mWindowID;
 
   bool mStopped; // MainThread only
 
+  // true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mAudioDevice.
+  // MainThread only.
+  bool mAudioStopped;
+
+  // true if we have sent MEDIA_STOP or MEDIA_STOP_TRACK for mAudioDevice.
+  // MainThread only.
+  bool mVideoStopped;
+
   // Set at Activate on MainThread
 
   // Accessed from MediaStreamGraph thread, MediaManager thread, and MainThread
   // No locking needed as they're only addrefed except on the MediaManager thread
   nsRefPtr<AudioDevice> mAudioDevice; // threadsafe refcnt
   nsRefPtr<VideoDevice> mVideoDevice; // threadsafe refcnt
   nsRefPtr<SourceMediaStream> mStream; // threadsafe refcnt
   bool mFinished;