Bug 1299515 - Remove GetUserMediaNotificationEvent. r?jib draft
authorAndreas Pehrson <pehrsons@mozilla.com>
Tue, 14 Nov 2017 11:50:07 +0100
changeset 748932 579bb4d3d316ea7311504d3b277056098bae17c2
parent 748931 ebaf14b8d13311f75188778419a48f73f183ebfe
child 748933 22e12a458cc715908cf336c7ae8e9983de460080
push id97281
push userbmo:apehrson@mozilla.com
push dateTue, 30 Jan 2018 18:29:03 +0000
reviewersjib
bugs1299515
milestone60.0a1
Bug 1299515 - Remove GetUserMediaNotificationEvent. r?jib MozReview-Commit-ID: 3ecH5vCce17
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -6,16 +6,17 @@
 
 #include "MediaManager.h"
 
 #include "MediaStreamGraph.h"
 #include "mozilla/dom/MediaStreamTrack.h"
 #include "MediaStreamListener.h"
 #include "nsArray.h"
 #include "nsContentUtils.h"
+#include "nsGlobalWindow.h"
 #include "nsHashPropertyBag.h"
 #include "nsIEventTarget.h"
 #include "nsIUUIDGenerator.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIPermissionManager.h"
 #include "nsIPopupWindowManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
@@ -25,16 +26,17 @@
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsICryptoHash.h"
 #include "nsICryptoHMAC.h"
 #include "nsIKeyModule.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsIInputStream.h"
 #include "nsILineInputStream.h"
+#include "nsPIDOMWindow.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Types.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/File.h"
@@ -522,25 +524,26 @@ public:
     return true;
   }
 
   void StopSharing();
 
   void StopRawID(const nsString& removedDeviceID);
 
   /**
-   * Called by one of our SourceListeners when one of its tracks has stopped.
+   * Called by one of our SourceListeners when one of its tracks has changed so
+   * that chrome state is affected.
    * Schedules an event for the next stable state to update chrome.
    */
-  void NotifySourceTrackStopped();
+  void ChromeAffectingStateChanged();
 
   /**
    * Called in stable state to send a notification to update chrome.
    */
-  void NotifyChromeOfTrackStops();
+  void NotifyChrome();
 
   bool CapturingVideo() const
   {
     MOZ_ASSERT(NS_IsMainThread());
     for (auto& l : mActiveListeners) {
       if (l->CapturingVideo()) {
         return true;
       }
@@ -1220,19 +1223,18 @@ public:
     mWindowListener->Activate(mSourceListener, stream, mAudioDevice, mVideoDevice);
 
     // Note: includes JS callbacks; must be released on MainThread
     auto callback = MakeRefPtr<Refcountable<UniquePtr<OnTracksAvailableCallback>>>(
         new TracksAvailableCallback(mManager, mOnSuccess.forget(), mWindowID, domStream));
 
     // Dispatch to the media thread to ask it to start the sources,
     // because that can take a while.
-    // Pass ownership of domStream through the lambda to
-    // GetUserMediaNotificationEvent to ensure it's kept alive until the
-    // GetUserMediaNotificationEvent runs or is discarded.
+    // Pass ownership of domStream through the lambda to the nested chrome
+    // notification lambda to ensure it's kept alive until that lambda runs or is discarded.
     RefPtr<GetUserMediaStreamRunnable> self = this;
     MediaManager::PostTask(NewTaskFrom([self, domStream, callback]() mutable {
       MOZ_ASSERT(MediaManager::IsInMediaThread());
       SourceMediaStream* source = self->mSourceListener->GetSourceStream();
 
       RefPtr<MediaMgrError> error = nullptr;
       if (self->mAudioDevice) {
         nsresult rv =
@@ -1280,34 +1282,40 @@ public:
       // Start() queued the tracks to be added synchronously to avoid races
       source->FinishAddTracks();
 
       source->SetPullEnabled(true);
       source->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
       LOG(("started all sources"));
 
-      // Forward onTracksAvailableCallback to GetUserMediaNotificationEvent,
-      // because onTracksAvailableCallback needs to be added to domStream
-      // on the main thread.
-      // The event runnable must always be released on mainthread due to the JS
-      // callbacks in the TracksAvailableCallback.
-      NS_DispatchToMainThread(do_AddRef(
-        new GetUserMediaNotificationEvent(
-          GetUserMediaNotificationEvent::STARTING,
-          domStream.forget(),
-          callback.forget(),
-          self->mWindowID,
-          self->mOnFailure.forget())));
-      NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::SendPendingGUMRequest",
-                                                     []() -> void {
+      // onTracksAvailableCallback must be added to domStream on the main thread.
+      uint64_t windowID = self->mWindowID;
+      NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::NotifyChromeOfStart",
+                                                     [domStream, callback, windowID]() mutable {
         MediaManager* manager = MediaManager::GetIfExists();
         if (!manager) {
           return;
         }
+
+        nsGlobalWindowInner* window =
+          nsGlobalWindowInner::GetInnerWindowWithId(windowID);
+        if (!window) {
+          MOZ_ASSERT_UNREACHABLE("Should have window");
+          return;
+        }
+
+        domStream->OnTracksAvailable(callback->release());
+
+        nsresult rv = MediaManager::NotifyRecordingStatusChange(window->AsInner());
+        if (NS_FAILED(rv)) {
+          MOZ_ASSERT_UNREACHABLE("Should be able to notify chrome");
+          return;
+        }
+
         manager->SendPendingGUMRequest();
       }));
       return NS_OK;
     }));
 
     if (!IsPincipalInfoPrivate(mPrincipalInfo)) {
       // Call GetPrincipalKey again, this time w/persist = true, to promote
       // deviceIds to persistent, in case they're not already. Fire'n'forget.
@@ -2009,18 +2017,17 @@ MediaManager::PostTask(already_AddRefed<
     return;
   }
   NS_ASSERTION(Get(), "MediaManager singleton?");
   NS_ASSERTION(Get()->mMediaThread, "No thread yet");
   Get()->mMediaThread->message_loop()->PostTask(Move(task));
 }
 
 /* static */ nsresult
-MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow,
-                                          const nsString& aMsg)
+MediaManager::NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow)
 {
   NS_ENSURE_ARG(aWindow);
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (!obs) {
     NS_WARNING("Could not get the Observer service for GetUserMedia recording notification.");
     return NS_ERROR_FAILURE;
   }
@@ -2035,17 +2042,17 @@ MediaManager::NotifyRecordingStatusChang
   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",
-                       aMsg.get());
+                       nullptr);
 
   return NS_OK;
 }
 
 int MediaManager::AddDeviceChangeCallback(DeviceChangeCallback* aCallback)
 {
   bool fakeDeviceChangeEventOn = mPrefs.mFakeDeviceChangeEventOn;
   MediaManager::PostTask(NewTaskFrom([fakeDeviceChangeEventOn]() {
@@ -3829,17 +3836,17 @@ SourceListener::StopTrack(TrackID aTrack
     LOG(("SourceListener %p this was the last track stopped", this));
     Stop();
   }
 
   if (!mWindowListener) {
     MOZ_ASSERT(false, "Should still have window listener");
     return;
   }
-  mWindowListener->NotifySourceTrackStopped();
+  mWindowListener->ChromeAffectingStateChanged();
 }
 
 void
 SourceListener::DisableTrack(TrackID aTrackID)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
 
   if (!Activated()) {
@@ -4283,93 +4290,48 @@ GetUserMediaWindowListener::StopRawID(co
       if (removedDeviceID.Equals(id)) {
         source->StopTrack(kVideoTrack);
       }
     }
   }
 }
 
 void
-GetUserMediaWindowListener::NotifySourceTrackStopped()
+GetUserMediaWindowListener::ChromeAffectingStateChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // We wait until stable state before notifying chrome so chrome only does one
   // update if more tracks are stopped in this event loop.
 
   if (mChromeNotificationTaskPosted) {
     return;
   }
 
   nsCOMPtr<nsIRunnable> runnable =
-    NewRunnableMethod("GetUserMediaWindowListener::NotifyChromeOfTrackStops",
+    NewRunnableMethod("GetUserMediaWindowListener::NotifyChrome",
                       this,
-                      &GetUserMediaWindowListener::NotifyChromeOfTrackStops);
+                      &GetUserMediaWindowListener::NotifyChrome);
   nsContentUtils::RunInStableState(runnable.forget());
   mChromeNotificationTaskPosted = true;
 }
 
 void
-GetUserMediaWindowListener::NotifyChromeOfTrackStops()
+GetUserMediaWindowListener::NotifyChrome()
 {
   MOZ_ASSERT(mChromeNotificationTaskPosted);
   mChromeNotificationTaskPosted = false;
 
-  NS_DispatchToMainThread(do_AddRef(new GetUserMediaNotificationEvent(
-    GetUserMediaNotificationEvent::STOPPING, mWindowID)));
-}
-
-GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
-  GetUserMediaStatus aStatus,
-  uint64_t aWindowID)
-  : Runnable("GetUserMediaNotificationEvent")
-  , mStatus(aStatus)
-  , mWindowID(aWindowID)
-{
-}
-
-GetUserMediaNotificationEvent::GetUserMediaNotificationEvent(
-  GetUserMediaStatus aStatus,
-  already_AddRefed<DOMMediaStream> aStream,
-  already_AddRefed<Refcountable<UniquePtr<OnTracksAvailableCallback>>>
-    aOnTracksAvailableCallback,
-  uint64_t aWindowID,
-  already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
-  : Runnable("GetUserMediaNotificationEvent")
-  , mStream(aStream)
-  , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
-  , mStatus(aStatus)
-  , mWindowID(aWindowID)
-  , mOnFailure(aError)
-{
-}
-GetUserMediaNotificationEvent::~GetUserMediaNotificationEvent()
-{
-}
-
-NS_IMETHODIMP
-GetUserMediaNotificationEvent::Run()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  // Make sure mStream is cleared and our reference to the DOMMediaStream
-  // is dropped on the main thread, no matter what happens in this method.
-  // Otherwise this object might be destroyed off the main thread,
-  // releasing DOMMediaStream off the main thread, which is not allowed.
-  RefPtr<DOMMediaStream> stream = mStream.forget();
-
-  nsString msg;
-  switch (mStatus) {
-  case STARTING:
-    msg = NS_LITERAL_STRING("starting");
-    stream->OnTracksAvailable(mOnTracksAvailableCallback->release());
-    break;
-  case STOPPING:
-    msg = NS_LITERAL_STRING("shutdown");
-    break;
-  }
-
-  RefPtr<nsGlobalWindowInner> window = nsGlobalWindowInner::GetInnerWindowWithId(mWindowID);
-  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
-
-  return MediaManager::NotifyRecordingStatusChange(window->AsInner(), msg);
+  NS_DispatchToMainThread(NS_NewRunnableFunction("MediaManager::NotifyChrome",
+                                                 [windowID = mWindowID]() {
+    nsGlobalWindowInner* window =
+      nsGlobalWindowInner::GetInnerWindowWithId(windowID);
+    if (!window) {
+      MOZ_ASSERT_UNREACHABLE("Should have window");
+      return;
+    }
+
+    DebugOnly<nsresult> rv = MediaManager::NotifyRecordingStatusChange(window->AsInner());
+    MOZ_ASSERT(NS_SUCCEEDED(rv), "Should be able to notify chrome");
+  }));
 }
 
 } // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -9,24 +9,22 @@
 #include "mozilla/media/DeviceChangeCallback.h"
 #include "mozilla/dom/GetUserMediaRequest.h"
 #include "mozilla/Services.h"
 #include "mozilla/Unused.h"
 #include "nsAutoPtr.h"
 #include "nsIMediaManager.h"
 
 #include "nsHashKeys.h"
-#include "nsGlobalWindow.h"
 #include "nsClassHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsIObserver.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 
-#include "nsPIDOMWindow.h"
 #include "nsIDOMNavigatorUserMedia.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 #include "mozilla/dom/MediaStreamError.h"
@@ -124,44 +122,16 @@ class AudioDevice : public MediaDevice
 public:
   typedef MediaEngineAudioSource Source;
 
   explicit AudioDevice(Source* aSource);
   NS_IMETHOD GetType(nsAString& aType) override;
   Source* GetSource() override;
 };
 
-class GetUserMediaNotificationEvent: public Runnable
-{
-  public:
-    enum GetUserMediaStatus {
-      STARTING,
-      STOPPING,
-    };
-    GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
-                                  uint64_t aWindowID);
-
-    GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
-                                  already_AddRefed<DOMMediaStream> aStream,
-                                  already_AddRefed<media::Refcountable<UniquePtr<OnTracksAvailableCallback>>> aOnTracksAvailableCallback,
-                                  uint64_t aWindowID,
-                                  already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError);
-    virtual ~GetUserMediaNotificationEvent();
-
-    NS_IMETHOD Run() override;
-
-  protected:
-    RefPtr<GetUserMediaWindowListener> mListener; // threadsafe
-    RefPtr<DOMMediaStream> mStream;
-    RefPtr<media::Refcountable<UniquePtr<OnTracksAvailableCallback>>> mOnTracksAvailableCallback;
-    GetUserMediaStatus mStatus;
-    uint64_t mWindowID;
-    RefPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
-};
-
 typedef enum {
   MEDIA_STOP,
   MEDIA_STOP_TRACK,
   MEDIA_DIRECT_LISTENERS,
 } MediaOperation;
 
 class ReleaseMediaOperationResource : public Runnable
 {
@@ -208,18 +178,17 @@ public:
   static bool IsInMediaThread();
 #endif
 
   static bool Exists()
   {
     return !!sSingleton;
   }
 
-  static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow,
-                                              const nsString& aMsg);
+  static nsresult NotifyRecordingStatusChange(nsPIDOMWindowInner* aWindow);
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEDIAMANAGERSERVICE
 
   media::Parent<media::NonE10s>* GetNonE10sParent();
   MediaEngine* GetBackend(uint64_t aWindowId = 0);