Bug 861716 - queue a gUM request if there has been a pending one. r?jib
MozReview-Commit-ID: 52KcsN27AR3
--- 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;