Bug 861716 - queue a gUM request if there has been a pending one. r?jib draft
authorMunro Mengjue Chiang <mchiang@mozilla.com>
Fri, 12 May 2017 11:32:14 +0800
changeset 592986 c28b246a96db93a0c7b4d6f06b3143697812b169
parent 592979 2a3a253806d129c0bb6f2b76bf75630457a24492
child 592987 a965439d0c7abfea15c999d330d9a1039f5695af
push id63567
push userbmo:mchiang@mozilla.com
push dateTue, 13 Jun 2017 02:25:20 +0000
reviewersjib
bugs861716
milestone56.0a1
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;