Bug 1494675 - Merge SourceListener::Remove into SourceListener::Stop. r=padenot
authorAndreas Pehrson <apehrson@mozilla.com>
Fri, 29 Mar 2019 16:12:20 +0000
changeset 466792 be0fbe76851f6b09f56744a245cf633d40c85fa4
parent 466791 276622dfadd8c63574341b02fa5e594a36493c37
child 466793 8cde0ca01548efbce3d08620f0831acd6af26938
push id35780
push useropoprus@mozilla.com
push dateFri, 29 Mar 2019 21:53:01 +0000
treeherdermozilla-central@414f37afbe07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1494675
milestone68.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 1494675 - Merge SourceListener::Remove into SourceListener::Stop. r=padenot Depends on: D24903 Differential Revision: https://phabricator.services.mozilla.com/D25114
dom/media/MediaManager.cpp
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -330,30 +330,29 @@ class SourceListener : public SupportsWe
                 MediaDevice* aVideoDevice);
 
   /**
    * Posts a task to initialize and start all associated devices.
    */
   RefPtr<SourceListenerPromise> InitializeAsync();
 
   /**
-   * Stops all live tracks, finishes the associated MediaStream and cleans up.
+   * Stops all live tracks, finishes the associated MediaStream and cleans up
+   * the weak reference to the associated window listener.
+   * This will also tell the window listener to remove its hard reference to
+   * this SourceListener, so any caller will need to keep its own hard ref.
    */
   void Stop();
 
   /**
-   * Removes this SourceListener from its associated MediaStream and marks it
-   * removed. Also removes the weak reference to the associated window listener.
-   */
-  void Remove();
-
-  /**
    * Posts a task to stop the device associated with aTrackID and notifies the
    * associated window listener that a track was stopped.
-   * Should this track be the last live one to be stopped, we'll also clean up.
+   * Should this track be the last live one to be stopped, we'll also call Stop.
+   * This might tell the window listener to remove its hard reference to this
+   * SourceListener, so any caller will need to keep its own hard ref.
    */
   void StopTrack(TrackID aTrackID);
 
   /**
    * Gets the main thread MediaTrackSettings from the MediaEngineSource
    * associated with aTrackID.
    */
   void GetSettingsFor(TrackID aTrackID,
@@ -396,22 +395,16 @@ class SourceListener : public SupportsWe
   MediaDevice* GetAudioDevice() const {
     return mAudioDeviceState ? mAudioDeviceState->mDevice.get() : nullptr;
   }
 
   MediaDevice* GetVideoDevice() const {
     return mVideoDeviceState ? mVideoDeviceState->mDevice.get() : nullptr;
   }
 
-  /**
-   * Called on main thread after MediaStreamGraph notifies us that one of our
-   * track listeners was removed as listener from its track in the graph.
-   */
-  void NotifyRemoved(TrackID aTrackID);
-
   bool Activated() const { return mStream; }
 
   bool Stopped() const { return mStopped; }
 
   bool CapturingVideo() const;
 
   bool CapturingAudio() const;
 
@@ -436,20 +429,16 @@ class SourceListener : public SupportsWe
    * Since this is a raw pointer and the state lifetime depends on the
    * SourceListener's lifetime, it's internal use only.
    */
   DeviceState& GetDeviceStateFor(TrackID aTrackID) const;
 
   // true after this listener has had all devices stopped. MainThread only.
   bool mStopped;
 
-  // true after this listener has been removed from its MediaStream.
-  // MainThread only.
-  bool mRemoved;
-
   // never ever indirect off this; just for assertions
   PRThread* mMainThreadCheck;
 
   // Set in Register() on main thread, then read from any thread.
   PrincipalHandle mPrincipalHandle;
 
   // Weak pointer to the window listener that owns us. MainThread only.
   GetUserMediaWindowListener* mWindowListener;
@@ -509,36 +498,25 @@ class GetUserMediaWindowListener {
                "Must be registered to activate");
     MOZ_ASSERT(!mActiveListeners.Contains(aListener), "Already activated");
 
     mInactiveListeners.RemoveElement(aListener);
     aListener->Activate(aStream, aAudioDevice, aVideoDevice);
     mActiveListeners.AppendElement(do_AddRef(aListener));
   }
 
-  // Can be invoked from EITHER MainThread or MSG thread
-  void Stop() {
-    MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
-
-    for (auto& source : mActiveListeners) {
-      source->Stop();
-    }
-
-    // Once all tracks have stopped, that will trigger the chrome notification
-  }
-
   /**
    * Removes all SourceListeners from this window listener.
    * Removes this window listener from the list of active windows, so callers
    * need to make sure to hold a strong reference.
    */
   void RemoveAll() {
     MOZ_ASSERT(NS_IsMainThread());
 
-    // Shallow copy since SourceListener::Remove() will modify the arrays.
+    // Shallow copy since SourceListener::Stop() will modify the arrays.
     nsTArray<RefPtr<SourceListener>> listeners(mInactiveListeners.Length() +
                                                mActiveListeners.Length());
     listeners.AppendElements(mInactiveListeners);
     listeners.AppendElements(mActiveListeners);
     for (auto& l : listeners) {
       Remove(l);
     }
 
@@ -582,18 +560,18 @@ class GetUserMediaWindowListener {
 
     MOZ_ASSERT(!mInactiveListeners.Contains(aListener),
                "A SourceListener should only be once in one of "
                "mInactiveListeners and mActiveListeners");
     MOZ_ASSERT(!mActiveListeners.Contains(aListener),
                "A SourceListener should only be once in one of "
                "mInactiveListeners and mActiveListeners");
 
-    LOG("GUMWindowListener %p removing SourceListener %p.", this, aListener);
-    aListener->Remove();
+    LOG("GUMWindowListener %p stopping SourceListener %p.", this, aListener);
+    aListener->Stop();
 
     if (MediaDevice* removedDevice = aListener->GetVideoDevice()) {
       bool revokeVideoPermission = true;
       nsString removedRawId;
       nsString removedSourceType;
       removedDevice->GetRawId(removedRawId);
       removedDevice->GetMediaSource(removedSourceType);
       for (const auto& l : mActiveListeners) {
@@ -649,16 +627,17 @@ class GetUserMediaWindowListener {
       }
     }
 
     if (mInactiveListeners.Length() == 0 && mActiveListeners.Length() == 0) {
       LOG("GUMWindowListener %p Removed last SourceListener. Cleaning up.",
           this);
       RemoveAll();
     }
+
     return true;
   }
 
   void StopSharing();
 
   void StopRawID(const nsString& removedDeviceID);
 
   /**
@@ -1201,17 +1180,18 @@ class GetUserMediaStreamRunnable : publi
         void GetSettings(dom::MediaTrackSettings& aOutSettings) override {
           if (mListener) {
             mListener->GetSettingsFor(mTrackID, aOutSettings);
           }
         }
 
         void Stop() override {
           if (mListener) {
-            mListener->StopTrack(mTrackID);
+            RefPtr<SourceListener> deathGrip(mListener);
+            deathGrip->StopTrack(mTrackID);
             mListener = nullptr;
           }
         }
 
         void Disable() override {
           if (mListener) {
             mListener->SetEnabledFor(mTrackID, false);
           }
@@ -2159,16 +2139,17 @@ nsresult MediaManager::NotifyRecordingSt
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ConvertUTF8toUTF16 requestURL(pageURL);
 
   props->SetPropertyAsAString(NS_LITERAL_STRING("requestURL"), requestURL);
 
   obs->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
                        "recording-device-events", nullptr);
+  LOG("Sent recording-device-events for url '%s'", pageURL.get());
 
   return NS_OK;
 }
 
 int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback) {
   bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
   MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
     MediaManager* manager = MediaManager::GetIfExists();
@@ -2196,60 +2177,60 @@ void MediaManager::OnDeviceChange() {
         // after receiving devicechange event, sometimes we would get outdated
         // devices list.
         PR_Sleep(PR_MillisecondsToInterval(200));
         auto devices = MakeRefPtr<MediaDeviceSetRefCnt>();
         self->EnumerateRawDevices(
                 0, MediaSourceEnum::Camera, MediaSourceEnum::Microphone,
                 MediaSinkEnum::Speaker, DeviceEnumerationType::Normal,
                 DeviceEnumerationType::Normal, false, devices)
-            ->Then(GetCurrentThreadSerialEventTarget(), __func__,
-                   [self, devices](bool) {
-                     if (!MediaManager::GetIfExists()) {
-                       return;
-                     }
-
-                     nsTArray<nsString> deviceIDs;
-
-                     for (auto& device : *devices) {
-                       nsString id;
-                       device->GetId(id);
-                       id.ReplaceSubstring(NS_LITERAL_STRING("default: "),
-                                           NS_LITERAL_STRING(""));
-                       if (!deviceIDs.Contains(id)) {
-                         deviceIDs.AppendElement(id);
-                       }
-                     }
-
-                     for (auto& id : self->mDeviceIDs) {
-                       if (deviceIDs.Contains(id)) {
-                         continue;
-                       }
-
-                       // Stop the coresponding SourceListener
-                       nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
-                           nsGlobalWindowInner::GetWindowsTable();
-                       if (!windowsById) {
-                         continue;
-                       }
-
-                       for (auto iter = windowsById->Iter(); !iter.Done();
-                            iter.Next()) {
-                         nsGlobalWindowInner* window = iter.Data();
-                         self->IterateWindowListeners(
-                             window->AsInner(),
-                             [&id](GetUserMediaWindowListener* aListener) {
-                               aListener->StopRawID(id);
-                             });
-                       }
-                     }
-
-                     self->mDeviceIDs = deviceIDs;
-                   },
-                   [](RefPtr<MediaMgrError>&& reason) {});
+            ->Then(
+                GetCurrentThreadSerialEventTarget(), __func__,
+                [self, devices](bool) {
+                  if (!MediaManager::GetIfExists()) {
+                    return;
+                  }
+
+                  nsTArray<nsString> deviceIDs;
+
+                  for (auto& device : *devices) {
+                    nsString id;
+                    device->GetId(id);
+                    id.ReplaceSubstring(NS_LITERAL_STRING("default: "),
+                                        NS_LITERAL_STRING(""));
+                    if (!deviceIDs.Contains(id)) {
+                      deviceIDs.AppendElement(id);
+                    }
+                  }
+
+                  for (auto& id : self->mDeviceIDs) {
+                    if (deviceIDs.Contains(id)) {
+                      continue;
+                    }
+
+                    // Stop the coresponding SourceListener
+                    nsGlobalWindowInner::InnerWindowByIdTable* windowsById =
+                        nsGlobalWindowInner::GetWindowsTable();
+                    if (!windowsById) {
+                      continue;
+                    }
+
+                    for (auto iter = windowsById->Iter(); !iter.Done();
+                         iter.Next()) {
+                      nsGlobalWindowInner* window = iter.Data();
+                      self->IterateWindowListeners(
+                          window->AsInner(),
+                          [&id](const RefPtr<GetUserMediaWindowListener>&
+                                    aListener) { aListener->StopRawID(id); });
+                    }
+                  }
+
+                  self->mDeviceIDs = deviceIDs;
+                },
+                [](RefPtr<MediaMgrError>&& reason) {});
       }));
 }
 
 nsresult MediaManager::GenerateUUID(nsAString& aResult) {
   nsresult rv;
   nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -3415,23 +3396,18 @@ void MediaManager::OnNavigation(uint64_t
   // This is safe since we're on main-thread, and the windowlist can only
   // be added to from the main-thread
   auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
   if (window) {
     IterateWindowListeners(
         window->AsInner(),
         [self = RefPtr<MediaManager>(this),
          windowID = DebugOnly<decltype(aWindowID)>(aWindowID)](
-            GetUserMediaWindowListener* aListener) {
-          // Grab a strong ref since RemoveAll() might destroy the listener
-          // mid-way when clearing the mActiveWindows reference.
-          RefPtr<GetUserMediaWindowListener> listener(aListener);
-
-          listener->Stop();
-          listener->RemoveAll();
+            const RefPtr<GetUserMediaWindowListener>& aListener) {
+          aListener->RemoveAll();
           MOZ_ASSERT(!self->GetWindowListener(windowID));
         });
   } else {
     RemoveWindowID(aWindowID);
   }
   MOZ_ASSERT(!GetWindowListener(aWindowID));
 
   RemoveMediaDevicesCallback(aWindowID);
@@ -3594,17 +3570,16 @@ void MediaManager::Shutdown() {
     // table. We cannot touch the table at point so we grab a copy of the window
     // listeners first.
     nsTArray<RefPtr<GetUserMediaWindowListener>> listeners(
         GetActiveWindows()->Count());
     for (auto iter = GetActiveWindows()->Iter(); !iter.Done(); iter.Next()) {
       listeners.AppendElement(iter.UserData());
     }
     for (auto& listener : listeners) {
-      listener->Stop();
       listener->RemoveAll();
     }
   }
   MOZ_ASSERT(GetActiveWindows()->Count() == 0);
 
   GetActiveWindows()->Clear();
   mActiveCallbacks.Clear();
   mCallIds.Clear();
@@ -3893,58 +3868,58 @@ MediaManager::MediaCaptureWindowState(ns
   CaptureState microphone = CaptureState::Off;
   CaptureState screen = CaptureState::Off;
   CaptureState window = CaptureState::Off;
   CaptureState application = CaptureState::Off;
   CaptureState browser = CaptureState::Off;
 
   nsCOMPtr<nsPIDOMWindowInner> piWin = do_QueryInterface(aCapturedWindow);
   if (piWin) {
-    IterateWindowListeners(piWin, [&camera, &microphone, &screen, &window,
-                                   &application, &browser](
-                                      GetUserMediaWindowListener* aListener) {
-      camera = CombineCaptureState(
-          camera, aListener->CapturingSource(MediaSourceEnum::Camera));
-      microphone = CombineCaptureState(
-          microphone, aListener->CapturingSource(MediaSourceEnum::Microphone));
-      screen = CombineCaptureState(
-          screen, aListener->CapturingSource(MediaSourceEnum::Screen));
-      window = CombineCaptureState(
-          window, aListener->CapturingSource(MediaSourceEnum::Window));
-      application = CombineCaptureState(
-          application,
-          aListener->CapturingSource(MediaSourceEnum::Application));
-      browser = CombineCaptureState(
-          browser, aListener->CapturingSource(MediaSourceEnum::Browser));
-    });
+    IterateWindowListeners(
+        piWin, [&camera, &microphone, &screen, &window, &application,
+                &browser](const RefPtr<GetUserMediaWindowListener>& aListener) {
+          camera = CombineCaptureState(
+              camera, aListener->CapturingSource(MediaSourceEnum::Camera));
+          microphone = CombineCaptureState(
+              microphone,
+              aListener->CapturingSource(MediaSourceEnum::Microphone));
+          screen = CombineCaptureState(
+              screen, aListener->CapturingSource(MediaSourceEnum::Screen));
+          window = CombineCaptureState(
+              window, aListener->CapturingSource(MediaSourceEnum::Window));
+          application = CombineCaptureState(
+              application,
+              aListener->CapturingSource(MediaSourceEnum::Application));
+          browser = CombineCaptureState(
+              browser, aListener->CapturingSource(MediaSourceEnum::Browser));
+        });
   }
 
   *aCamera = FromCaptureState(camera);
   *aMicrophone = FromCaptureState(microphone);
   *aScreen = FromCaptureState(screen);
   *aWindow = FromCaptureState(window);
   *aApplication = FromCaptureState(application);
   *aBrowser = FromCaptureState(browser);
 
-#ifdef DEBUG
   LOG("%s: window %" PRIu64 " capturing %s %s %s %s %s %s", __FUNCTION__,
       piWin ? piWin->WindowID() : -1,
       *aCamera == nsIMediaManagerService::STATE_CAPTURE_ENABLED
           ? "camera (enabled)"
           : (*aCamera == nsIMediaManagerService::STATE_CAPTURE_DISABLED
                  ? "camera (disabled)"
                  : ""),
       *aMicrophone == nsIMediaManagerService::STATE_CAPTURE_ENABLED
           ? "microphone (enabled)"
           : (*aMicrophone == nsIMediaManagerService::STATE_CAPTURE_DISABLED
                  ? "microphone (disabled)"
                  : ""),
       *aScreen ? "screenshare" : "", *aWindow ? "windowshare" : "",
       *aApplication ? "appshare" : "", *aBrowser ? "browsershare" : "");
-#endif
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaManager::SanitizeDeviceIds(int64_t aSinceWhen) {
   MOZ_ASSERT(NS_IsMainThread());
   LOG("%s: sinceWhen = %" PRId64, __FUNCTION__, aSinceWhen);
 
@@ -3957,28 +3932,30 @@ void MediaManager::StopScreensharing(uin
   // that correspond to that outerwindow.
 
   auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowID);
   if (!window) {
     return;
   }
   IterateWindowListeners(
       window->AsInner(),
-      [](GetUserMediaWindowListener* aListener) { aListener->StopSharing(); });
+      [](const RefPtr<GetUserMediaWindowListener>& aListener) {
+        aListener->StopSharing();
+      });
 }
 
 template <typename FunctionType>
 void MediaManager::IterateWindowListeners(nsPIDOMWindowInner* aWindow,
                                           const FunctionType& aCallback) {
   // Iterate the docshell tree to find all the child windows, and for each
   // invoke the callback
   if (aWindow) {
     {
       uint64_t windowID = aWindow->WindowID();
-      GetUserMediaWindowListener* listener = GetWindowListener(windowID);
+      RefPtr<GetUserMediaWindowListener> listener = GetWindowListener(windowID);
       if (listener) {
         aCallback(listener);
       }
       // NB: `listener` might have been destroyed.
     }
 
     // iterate any children of *this* window (iframes, etc)
     nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
@@ -4081,17 +4058,16 @@ bool MediaManager::IsActivelyCapturingOr
     }
   }
   return audio == nsIPermissionManager::ALLOW_ACTION ||
          video == nsIPermissionManager::ALLOW_ACTION;
 }
 
 SourceListener::SourceListener()
     : mStopped(false),
-      mRemoved(false),
       mMainThreadCheck(nullptr),
       mPrincipalHandle(PRINCIPAL_HANDLE_NONE),
       mWindowListener(nullptr) {}
 
 void SourceListener::Register(GetUserMediaWindowListener* aListener) {
   LOG("SourceListener %p registering with window listener %p", this, aListener);
 
   MOZ_ASSERT(aListener, "No listener");
@@ -4241,55 +4217,41 @@ SourceListener::InitializeAsync() {
                return SourceListenerPromise::CreateAndReject(std::move(aResult),
                                                              __func__);
              });
 }
 
 void SourceListener::Stop() {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
 
-  if (mStopped) {
-    return;
-  }
-
-  LOG("SourceListener %p stopping", this);
-
   // StopSharing() has some special logic, at least for audio capture.
   // It must be called when all tracks have stopped, before setting mStopped.
   StopSharing();
 
-  mStopped = true;
-
-  MOZ_ASSERT(Activated(), "There are no devices or any source stream to stop");
-  MOZ_ASSERT(mStream, "Can't end tracks. No source stream.");
-
-  if (mAudioDeviceState && !mAudioDeviceState->mStopped) {
-    StopTrack(kAudioTrack);
+  if (mStopped) {
+    return;
   }
-  if (mVideoDeviceState && !mVideoDeviceState->mStopped) {
-    StopTrack(kVideoTrack);
-  }
-}
-
-void SourceListener::Remove() {
-  MOZ_ASSERT(NS_IsMainThread());
+  mStopped = true;
+
+  LOG("SourceListener %p stopping", this);
 
   if (mAudioDeviceState) {
     mAudioDeviceState->mDisableTimer->Cancel();
+    if (!mAudioDeviceState->mStopped) {
+      StopTrack(kAudioTrack);
+    }
   }
   if (mVideoDeviceState) {
     mVideoDeviceState->mDisableTimer->Cancel();
+    if (!mVideoDeviceState->mStopped) {
+      StopTrack(kVideoTrack);
+    }
   }
 
-  if (!mStream || mRemoved) {
-    return;
-  }
-
-  LOG("SourceListener %p removed on purpose", this);
-  mRemoved = true;  // RemoveListener is async, avoid races
+  mWindowListener->Remove(this);
   mWindowListener = nullptr;
 }
 
 void SourceListener::StopTrack(TrackID aTrackID) {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
   MOZ_ASSERT(Activated(), "No device to stop");
   MOZ_ASSERT(aTrackID == kAudioTrack || aTrackID == kVideoTrack,
              "Unknown track id");
@@ -4306,42 +4268,38 @@ void SourceListener::StopTrack(TrackID a
 
   state.mDisableTimer->Cancel();
 
   MediaManager::PostTask(NewTaskFrom([device = state.mDevice]() {
     device->Stop();
     device->Deallocate();
   }));
 
+  MOZ_ASSERT(mWindowListener, "Should still have window listener");
+  mWindowListener->ChromeAffectingStateChanged();
+
   if ((!mAudioDeviceState || mAudioDeviceState->mStopped) &&
       (!mVideoDeviceState || mVideoDeviceState->mStopped)) {
     LOG("SourceListener %p this was the last track stopped", this);
     Stop();
   }
-
-  MOZ_ASSERT(mWindowListener, "Should still have window listener");
-  mWindowListener->ChromeAffectingStateChanged();
 }
 
 void SourceListener::GetSettingsFor(
     TrackID aTrackID, dom::MediaTrackSettings& aOutSettings) const {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
   GetDeviceStateFor(aTrackID).mDevice->GetSettings(aOutSettings);
 }
 
 void SourceListener::SetEnabledFor(TrackID aTrackID, bool aEnable) {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
   MOZ_ASSERT(Activated(), "No device to set enabled state for");
   MOZ_ASSERT(aTrackID == kAudioTrack || aTrackID == kVideoTrack,
              "Unknown track id");
 
-  if (mRemoved) {
-    return;
-  }
-
   LOG("SourceListener %p %s %s track %d", this,
       aEnable ? "enabling" : "disabling",
       aTrackID == kAudioTrack ? "audio" : "video", aTrackID);
 
   DeviceState& state = GetDeviceStateFor(aTrackID);
 
   state.mTrackEnabled = aEnable;
 
@@ -4396,22 +4354,16 @@ void SourceListener::SetEnabledFor(Track
                        "Device operation hasn't started");
             MOZ_ASSERT(state.mOperationInProgress,
                        "It's our responsibility to reset the inProgress state");
 
             LOG("SourceListener %p %s %s track %d - starting device operation",
                 this, aEnable ? "enabling" : "disabling",
                 aTrackID == kAudioTrack ? "audio" : "video", aTrackID);
 
-            if (mRemoved) {
-              // Listener was removed between timer resolving and this runnable.
-              return DeviceOperationPromise::CreateAndResolve(NS_ERROR_ABORT,
-                                                              __func__);
-            }
-
             if (state.mStopped) {
               // Source was stopped between timer resolving and this runnable.
               return DeviceOperationPromise::CreateAndResolve(NS_ERROR_ABORT,
                                                               __func__);
             }
 
             state.mDeviceEnabled = aEnable;
 
@@ -4496,22 +4448,22 @@ void SourceListener::SetEnabledFor(Track
               SetEnabledFor(aTrackID, false);
             }
           },
           []() { MOZ_ASSERT_UNREACHABLE("Unexpected and unhandled reject"); });
 }
 
 void SourceListener::StopSharing() {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_RELEASE_ASSERT(mWindowListener);
 
   if (mStopped) {
     return;
   }
 
+  MOZ_RELEASE_ASSERT(mWindowListener);
   LOG("SourceListener %p StopSharing", this);
 
   if (mVideoDeviceState && (mVideoDeviceState->mDevice->GetMediaSource() ==
                                 MediaSourceEnum::Screen ||
                             mVideoDeviceState->mDevice->GetMediaSource() ==
                                 MediaSourceEnum::Application ||
                             mVideoDeviceState->mDevice->GetMediaSource() ==
                                 MediaSourceEnum::Window)) {
@@ -4533,37 +4485,16 @@ void SourceListener::StopSharing() {
   }
 }
 
 SourceMediaStream* SourceListener::GetSourceStream() {
   NS_ASSERTION(mStream, "Getting stream from never-activated SourceListener");
   return mStream;
 }
 
-void SourceListener::NotifyRemoved(TrackID aTrackID) {
-  MOZ_ASSERT(NS_IsMainThread());
-  LOG("Track %d for SourceListener %p removed", aTrackID, this);
-
-  StopTrack(aTrackID);
-
-  if (!mStopped) {
-    // There are more live tracks that need to be stopped before removal.
-    return;
-  }
-
-  if (!mWindowListener) {
-    // Removed explicitly before MSG's notification.
-    return;
-  }
-
-  mWindowListener->Remove(this);
-
-  MOZ_ASSERT(!mWindowListener);
-}
-
 bool SourceListener::CapturingVideo() const {
   MOZ_ASSERT(NS_IsMainThread());
   return Activated() && mVideoDeviceState && !mVideoDeviceState->mStopped &&
          (!mVideoDeviceState->mDevice->mSource->IsFake() ||
           Preferences::GetBool("media.navigator.permission.fake"));
 }
 
 bool SourceListener::CapturingAudio() const {