Bug 861716 - queue a gUM request if there has been a pending one. r=jib
authorMunro Mengjue Chiang <mchiang@mozilla.com>
Fri, 12 May 2017 11:32:14 +0800
changeset 363585 80acbcf225a140b5bd1222c5464382751f817899
parent 363584 0a0ee8f86057f00c5c57f33bacecc74701f0197e
child 363586 4f5477c79f4f3526f00236749f7ede14d1d699cd
push id44622
push usercbook@mozilla.com
push dateTue, 13 Jun 2017 09:53:12 +0000
treeherderautoland@95d89b5bcc9c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs861716
milestone56.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 861716 - queue a gUM request if there has been a pending one. r=jib MozReview-Commit-ID: 52KcsN27AR3
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaManager.h"
 
 #include "MediaStreamGraph.h"
 #include "mozilla/dom/MediaStreamTrack.h"
-#include "GetUserMediaRequest.h"
 #include "MediaStreamListener.h"
 #include "nsArray.h"
 #include "nsContentUtils.h"
 #include "nsHashPropertyBag.h"
 #ifdef MOZ_WIDGET_GONK
 #include "nsIAudioManager.h"
 #endif
 #include "nsIEventTarget.h"
@@ -1286,16 +1285,20 @@ public:
       // 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([]() -> void {
+        RefPtr<MediaManager> manager = MediaManager::GetInstance();
+        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.
       RefPtr<Pledge<nsCString>> p =
         media::GetPrincipalKey(mPrincipalInfo, true);
@@ -1534,16 +1537,20 @@ public:
       if (badConstraint) {
         Fail(NS_LITERAL_STRING("OverconstrainedError"),
              NS_LITERAL_STRING(""),
              NS_ConvertUTF8toUTF16(badConstraint));
       } else {
         Fail(NS_LITERAL_STRING("NotReadableError"),
              NS_ConvertUTF8toUTF16(errorMsg));
       }
+      NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
+        RefPtr<MediaManager> manager = MediaManager::GetInstance();
+        manager->SendPendingGUMRequest();
+      }));
       return NS_OK;
     }
     PeerIdentity* peerIdentity = nullptr;
     if (!mConstraints.mPeerIdentity.IsEmpty()) {
       peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
     }
 
     NS_DispatchToMainThread(do_AddRef(
@@ -2465,17 +2472,23 @@ MediaManager::GetUserMedia(nsPIDOMWindow
 
       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
       if (!askPermission) {
         obs->NotifyObservers(devicesCopy, "getUserMedia:privileged:allow",
                              callID.BeginReading());
       } else {
         RefPtr<GetUserMediaRequest> req =
             new GetUserMediaRequest(window, callID, c, isHTTPS);
-        obs->NotifyObservers(req, "getUserMedia:request", nullptr);
+        if (!Preferences::GetBool("media.navigator.permission.force") && array->Length() > 1) {
+          // there is at least 1 pending gUM request
+          // For the scarySources test case, always send the request
+          self->mPendingGUMRequest.AppendElement(req.forget());
+        } else {
+          obs->NotifyObservers(req, "getUserMedia:request", nullptr);
+        }
       }
 
 #ifdef MOZ_WEBRTC
       EnableWebRtcLog();
 #endif
     }, [onFailure](MediaStreamError*& reason) mutable {
       onFailure->OnError(reason);
     });
@@ -2945,16 +2958,17 @@ MediaManager::Shutdown()
 #endif
     prefs->RemoveObserver("media.navigator.audio.full_duplex", this);
   }
 
   // Close off any remaining active windows.
   GetActiveWindows()->Clear();
   mActiveCallbacks.Clear();
   mCallIds.Clear();
+  mPendingGUMRequest.Clear();
 #ifdef MOZ_WEBRTC
   StopWebRtcLog();
 #endif
 
   // Because mMediaThread is not an nsThread, we must dispatch to it so it can
   // clean up BackgroundChild. Continue stopping thread once this is done.
 
   class ShutdownTask : public Runnable
@@ -3019,16 +3033,26 @@ MediaManager::Shutdown()
     // we hold a ref to 'that' which is the same as sSingleton
     sSingleton = nullptr;
 
     return NS_OK;
   }));
   mMediaThread->message_loop()->PostTask(shutdown.forget());
 }
 
+void
+MediaManager::SendPendingGUMRequest()
+{
+  if (mPendingGUMRequest.Length() > 0) {
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    obs->NotifyObservers(mPendingGUMRequest[0], "getUserMedia:request", nullptr);
+    mPendingGUMRequest.RemoveElementAt(0);
+  }
+}
+
 nsresult
 MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
   const char16_t* aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     nsCOMPtr<nsIPrefBranch> branch( do_QueryInterface(aSubject) );
@@ -3127,16 +3151,17 @@ MediaManager::Observe(nsISupports* aSubj
     mActiveCallbacks.Remove(key, getter_AddRefs(task));
     if (task) {
       task->Denied(errorMessage);
       nsTArray<nsString>* array;
       if (!mCallIds.Get(task->GetWindowID(), &array)) {
         return NS_OK;
       }
       array->RemoveElement(key);
+      SendPendingGUMRequest();
     }
     return NS_OK;
 
   } else if (!strcmp(aTopic, "getUserMedia:revoke")) {
     nsresult rv;
     // may be windowid or screen:windowid
     nsDependentString data(aData);
     if (Substring(data, 0, strlen("screen:")).EqualsLiteral("screen:")) {
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_MEDIAMANAGER_H
 #define MOZILLA_MEDIAMANAGER_H
 
 #include "MediaEngine.h"
 #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"
@@ -223,16 +224,17 @@ public:
     return &mActiveWindows;
   }
   GetUserMediaWindowListener *GetWindowListener(uint64_t aWindowId) {
     MOZ_ASSERT(NS_IsMainThread());
     return mActiveWindows.GetWeak(aWindowId);
   }
   void AddWindowID(uint64_t aWindowId, GetUserMediaWindowListener *aListener);
   void RemoveWindowID(uint64_t aWindowId);
+  void SendPendingGUMRequest();
   bool IsWindowStillActive(uint64_t aWindowId) {
     return !!GetWindowListener(aWindowId);
   }
   // Note: also calls aListener->Remove(), even if inactive
   void RemoveFromWindowList(uint64_t aWindowID,
     GetUserMediaWindowListener *aListener);
 
   nsresult GetUserMedia(
@@ -309,16 +311,17 @@ private:
 
   void StopMediaStreams();
   void RemoveMediaDevicesCallback(uint64_t aWindowID);
 
   // ONLY access from MainThread so we don't need to lock
   WindowTable mActiveWindows;
   nsRefPtrHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
   nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
+  nsTArray<RefPtr<dom::GetUserMediaRequest>> mPendingGUMRequest;
 
   // Always exists
   nsAutoPtr<base::Thread> mMediaThread;
   nsCOMPtr<nsIAsyncShutdownBlocker> mShutdownBlocker;
 
   // ONLY accessed from MediaManagerThread
   RefPtr<MediaEngine> mBackend;