Bug 1709474 move mozGetUserMediaDevices from Navigator to GetUserMediaRequest r=jib,webidl,geckoview-reviewers,smaug,agi

Differential Revision: https://phabricator.services.mozilla.com/D111565
This commit is contained in:
Karl Tomlinson 2021-05-05 23:04:13 +00:00
Родитель 57e201057c
Коммит 10fe97e403
12 изменённых файлов: 68 добавлений и 174 удалений

Просмотреть файл

@ -270,31 +270,14 @@ function handleGUMRequest(aSubject, aTopic, aData) {
let isHandlingUserInput = aSubject.isHandlingUserInput;
let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
contentWindow.navigator.mozGetUserMediaDevices(
function(devices) {
// If the window has been closed while we were waiting for the list of
// devices, there's nothing to do in the callback anymore.
if (contentWindow.closed) {
return;
}
prompt(
contentWindow,
aSubject.windowID,
aSubject.callID,
constraints,
devices,
secure,
isHandlingUserInput
);
},
function(error) {
// Device enumeration is done ahead of handleGUMRequest, so we're not
// responsible for handling the NotFoundError spec case.
denyGUMRequest({ callID: aSubject.callID });
},
aSubject.innerWindowID,
aSubject.callID
prompt(
contentWindow,
aSubject.windowID,
aSubject.callID,
constraints,
aSubject.devices,
secure,
isHandlingUserInput
);
}

Просмотреть файл

@ -1325,22 +1325,6 @@ void Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
});
}
void Navigator::MozGetUserMediaDevices(
MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError, uint64_t aInnerWindowID,
const nsAString& aCallID, ErrorResult& aRv) {
if (!mWindow || !mWindow->GetOuterWindow() ||
mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return;
}
RefPtr<MediaManager> manager = MediaManager::Get();
// XXXbz aOnError seems to be unused?
nsCOMPtr<nsPIDOMWindowInner> window(mWindow);
aRv =
manager->GetUserMediaDevices(window, aOnSuccess, aInnerWindowID, aCallID);
}
//*****************************************************************************
// Navigator::nsINavigatorBattery
//*****************************************************************************

Просмотреть файл

@ -67,7 +67,6 @@ class Gamepad;
class GamepadServiceTest;
class NavigatorUserMediaSuccessCallback;
class NavigatorUserMediaErrorCallback;
class MozGetUserMediaDevicesSuccessCallback;
struct MIDIOptions;
@ -201,11 +200,6 @@ class Navigator final : public nsISupports, public nsWrapperCache {
NavigatorUserMediaSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
CallerType aCallerType, ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void MozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
uint64_t aInnerWindowID, const nsAString& aCallID,
ErrorResult& aRv);
already_AddRefed<ServiceWorkerContainer> ServiceWorker();

Просмотреть файл

@ -1922,6 +1922,8 @@ addExternalIface('nsIEventTarget', nativeType='nsIEventTarget', notflattened=Tru
addExternalIface('nsIFile', nativeType='nsIFile', notflattened=True)
addExternalIface('nsILoadGroup', nativeType='nsILoadGroup',
headerFile='nsILoadGroup.h', notflattened=True)
addExternalIface('nsIMediaDevice', nativeType='nsIMediaDevice',
notflattened=True)
addExternalIface('nsIPrintSettings', nativeType='nsIPrintSettings',
notflattened=True)
addExternalIface('nsISelectionListener', nativeType='nsISelectionListener')

Просмотреть файл

@ -5,9 +5,11 @@
#include "GetUserMediaRequest.h"
#include "base/basictypes.h"
#include "MediaManager.h"
#include "mozilla/dom/MediaDevicesBinding.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/GetUserMediaRequestBinding.h"
#include "nsIMediaDevice.h"
#include "nsIScriptGlobalObject.h"
#include "nsPIDOMWindow.h"
@ -15,11 +17,13 @@ namespace mozilla::dom {
GetUserMediaRequest::GetUserMediaRequest(
nsPIDOMWindowInner* aInnerWindow, const nsAString& aCallID,
RefPtr<MediaDeviceSetRefCnt> aMediaDeviceSet,
const MediaStreamConstraints& aConstraints, bool aIsSecure,
bool aIsHandlingUserInput)
: mInnerWindowID(aInnerWindow->WindowID()),
mOuterWindowID(aInnerWindow->GetOuterWindow()->WindowID()),
mCallID(aCallID),
mMediaDeviceSet(std::move(aMediaDeviceSet)),
mConstraints(new MediaStreamConstraints(aConstraints)),
mType(GetUserMediaRequestType::Getusermedia),
mIsSecure(aIsSecure),
@ -27,11 +31,13 @@ GetUserMediaRequest::GetUserMediaRequest(
GetUserMediaRequest::GetUserMediaRequest(
nsPIDOMWindowInner* aInnerWindow, const nsAString& aCallID,
RefPtr<MediaDeviceSetRefCnt> aMediaDeviceSet,
const AudioOutputOptions& aAudioOutputOptions, bool aIsSecure,
bool aIsHandlingUserInput)
: mInnerWindowID(aInnerWindow->WindowID()),
mOuterWindowID(aInnerWindow->GetOuterWindow()->WindowID()),
mCallID(aCallID),
mMediaDeviceSet(std::move(aMediaDeviceSet)),
mAudioOutputOptions(new AudioOutputOptions(aAudioOutputOptions)),
mType(GetUserMediaRequestType::Selectaudiooutput),
mIsSecure(aIsSecure),
@ -53,6 +59,8 @@ GetUserMediaRequest::GetUserMediaRequest(nsPIDOMWindowInner* aInnerWindow,
}
}
GetUserMediaRequest::~GetUserMediaRequest() = default;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(GetUserMediaRequest)
NS_IMPL_CYCLE_COLLECTING_ADDREF(GetUserMediaRequest)
NS_IMPL_CYCLE_COLLECTING_RELEASE(GetUserMediaRequest)
@ -88,6 +96,17 @@ bool GetUserMediaRequest::IsHandlingUserInput() const {
return mIsHandlingUserInput;
}
void GetUserMediaRequest::GetDevices(
nsTArray<RefPtr<nsIMediaDevice>>& retval) const {
MOZ_ASSERT(retval.Length() == 0);
if (!mMediaDeviceSet) {
return;
}
for (const auto& device : *mMediaDeviceSet) {
retval.AppendElement(device);
}
}
void GetUserMediaRequest::GetConstraints(MediaStreamConstraints& result) {
MOZ_ASSERT(result.mAudio.IsBoolean() && !result.mAudio.GetAsBoolean() &&
result.mVideo.IsBoolean() && !result.mVideo.GetAsBoolean(),

Просмотреть файл

@ -14,9 +14,18 @@
#include "nsString.h"
#include "nsWrapperCache.h"
class nsIMediaDevice;
class nsPIDOMWindowInner;
namespace mozilla {
class MediaDevice;
namespace media {
template <typename T>
class Refcountable;
}
namespace dom {
struct AudioOutputOptions;
@ -25,14 +34,19 @@ enum class GetUserMediaRequestType : uint8_t;
class GetUserMediaRequest : public nsISupports, public nsWrapperCache {
public:
using MediaDeviceSetRefCnt =
media::Refcountable<nsTArray<RefPtr<MediaDevice>>>;
// For getUserMedia "getUserMedia:request"
GetUserMediaRequest(nsPIDOMWindowInner* aInnerWindow,
const nsAString& aCallID,
RefPtr<MediaDeviceSetRefCnt> aMediaDeviceSet,
const MediaStreamConstraints& aConstraints,
bool aIsSecure, bool aIsHandlingUserInput);
// For selectAudioOutput "getUserMedia:request"
GetUserMediaRequest(nsPIDOMWindowInner* aInnerWindow,
const nsAString& aCallID,
RefPtr<MediaDeviceSetRefCnt> aMediaDeviceSet,
const AudioOutputOptions& aAudioOutputOptions,
bool aIsSecure, bool aIsHandlingUserInput);
// For "recording-device-stopped"
@ -54,16 +68,18 @@ class GetUserMediaRequest : public nsISupports, public nsWrapperCache {
void GetCallID(nsString& retval);
void GetRawID(nsString& retval);
void GetMediaSource(nsString& retval);
void GetDevices(nsTArray<RefPtr<nsIMediaDevice>>& retval) const;
void GetConstraints(MediaStreamConstraints& result);
void GetAudioOutputOptions(AudioOutputOptions& result);
private:
virtual ~GetUserMediaRequest() = default;
virtual ~GetUserMediaRequest();
uint64_t mInnerWindowID, mOuterWindowID;
const nsString mCallID;
const nsString mRawID;
const nsString mMediaSource;
const RefPtr<MediaDeviceSetRefCnt> mMediaDeviceSet;
UniquePtr<MediaStreamConstraints> mConstraints;
UniquePtr<AudioOutputOptions> mAudioOutputOptions;
GetUserMediaRequestType mType;

Просмотреть файл

@ -57,7 +57,6 @@
#include "nsNetUtil.h"
#include "nsPIDOMWindow.h"
#include "nsProxyRelease.h"
#include "nsVariant.h"
#include "nspr.h"
#include "nss.h"
#include "pk11pub.h"
@ -186,7 +185,6 @@ using dom::MediaStreamTrackSource;
using dom::MediaTrackConstraints;
using dom::MediaTrackConstraintSet;
using dom::MediaTrackSettings;
using dom::MozGetUserMediaDevicesSuccessCallback;
using dom::OwningBooleanOrMediaTrackConstraints;
using dom::OwningStringOrStringSequence;
using dom::OwningStringOrStringSequenceOrConstrainDOMStringParameters;
@ -1264,12 +1262,10 @@ class GetUserMediaTask {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GetUserMediaTask)
GetUserMediaTask(uint64_t aWindowID, const ipc::PrincipalInfo& aPrincipalInfo,
CallerType aCallerType,
RefPtr<MediaManager::MediaDeviceSetRefCnt> aMediaDeviceSet)
CallerType aCallerType)
: mPrincipalInfo(aPrincipalInfo),
mWindowID(aWindowID),
mCallerType(aCallerType),
mMediaDeviceSet(std::move(aMediaDeviceSet)) {}
mCallerType(aCallerType) {}
virtual void Denied(MediaMgrError::Name aName,
const nsCString& aMessage = ""_ns) = 0;
@ -1324,9 +1320,6 @@ class GetUserMediaTask {
const uint64_t mWindowID;
// Whether the JS caller of getUserMedia() has system (subject) principal
const enum CallerType mCallerType;
public:
const RefPtr<MediaManager::MediaDeviceSetRefCnt> mMediaDeviceSet;
};
/**
@ -1345,11 +1338,8 @@ class GetUserMediaStreamTask final : public GetUserMediaTask {
RefPtr<DeviceListener> aAudioDeviceListener,
RefPtr<DeviceListener> aVideoDeviceListener,
const MediaEnginePrefs& aPrefs, const ipc::PrincipalInfo& aPrincipalInfo,
enum CallerType aCallerType,
RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aMediaDeviceSet,
bool aShouldFocusSource)
: GetUserMediaTask(aWindowID, aPrincipalInfo, aCallerType,
std::move(aMediaDeviceSet)),
enum CallerType aCallerType, bool aShouldFocusSource)
: GetUserMediaTask(aWindowID, aPrincipalInfo, aCallerType),
mConstraints(aConstraints),
mHolder(std::move(aHolder)),
mWindowListener(std::move(aWindowListener)),
@ -1710,13 +1700,10 @@ void GetUserMediaStreamTask::PrepareDOMStream() {
*/
class SelectAudioOutputTask final : public GetUserMediaTask {
public:
SelectAudioOutputTask(
MozPromiseHolder<MediaManager::DevicePromise>&& aHolder,
uint64_t aWindowID, enum CallerType aCallerType,
const ipc::PrincipalInfo& aPrincipalInfo,
RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aMediaDeviceSet)
: GetUserMediaTask(aWindowID, aPrincipalInfo, aCallerType,
std::move(aMediaDeviceSet)),
SelectAudioOutputTask(MozPromiseHolder<MediaManager::DevicePromise>&& aHolder,
uint64_t aWindowID, enum CallerType aCallerType,
const ipc::PrincipalInfo& aPrincipalInfo)
: GetUserMediaTask(aWindowID, aPrincipalInfo, aCallerType),
mHolder(std::move(aHolder)) {}
void Allowed(RefPtr<MediaDevice> aAudioOutput) {
@ -2858,7 +2845,7 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
auto task = MakeRefPtr<GetUserMediaStreamTask>(
c, std::move(holder), windowID, std::move(windowListener),
std::move(audioListener), std::move(videoListener), prefs,
principalInfo, aCallerType, std::move(devices), focusSource);
principalInfo, aCallerType, focusSource);
size_t taskCount =
self->AddTaskAndGetCount(windowID, callID, std::move(task));
@ -2869,7 +2856,8 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
callID.get());
} else {
auto req = MakeRefPtr<GetUserMediaRequest>(
window, callID, c, isSecure, isHandlingUserInput);
window, callID, std::move(devices), c, isSecure,
isHandlingUserInput);
if (!Preferences::GetBool("media.navigator.permission.force") &&
taskCount > 1) {
// there is at least 1 pending gUM request
@ -2971,31 +2959,6 @@ nsresult MediaManager::AnonymizeId(nsAString& aId,
return NS_OK;
}
/* static */
already_AddRefed<nsIWritableVariant> MediaManager::ToJSArray(
MediaDeviceSet& aDevices) {
MOZ_ASSERT(NS_IsMainThread());
auto var = MakeRefPtr<nsVariantCC>();
size_t len = aDevices.Length();
if (len) {
nsTArray<nsIMediaDevice*> tmp(len);
for (auto& device : aDevices) {
tmp.AppendElement(device);
}
auto* elements = static_cast<const void*>(tmp.Elements());
nsresult rv = var->SetAsArray(nsIDataType::VTYPE_INTERFACE,
&NS_GET_IID(nsIMediaDevice), len,
const_cast<void*>(elements));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
} else {
var->SetAsEmptyArray(); // because SetAsArray() fails on zero length
// arrays.
}
return var.forget();
}
RefPtr<MediaManager::MgrPromise> MediaManager::EnumerateDevicesImpl(
nsPIDOMWindowInner* aWindow, MediaSourceEnum aVideoInputType,
MediaSourceEnum aAudioInputType, MediaSinkEnum aAudioOutputType,
@ -3273,40 +3236,6 @@ RefPtr<SinkInfoPromise> MediaManager::GetSinkDevice(nsPIDOMWindowInner* aWindow,
});
}
/*
* GetUserMediaDevices - called by the UI-part of getUserMedia from chrome JS.
*/
nsresult MediaManager::GetUserMediaDevices(
nsPIDOMWindowInner* aWindow,
MozGetUserMediaDevicesSuccessCallback& aOnSuccess, uint64_t aWindowId,
const nsAString& aCallID) {
MOZ_ASSERT(NS_IsMainThread());
if (!aWindowId) {
aWindowId = aWindow->WindowID();
}
// Locate + return already-constrained list.
nsTArray<nsString>* callIDs;
if (!mCallIds.Get(aWindowId, &callIDs)) {
return NS_ERROR_UNEXPECTED;
}
for (auto& callID : *callIDs) {
RefPtr<GetUserMediaTask> task;
if (!aCallID.Length() || aCallID == callID) {
if (mActiveCallbacks.Get(callID, getter_AddRefs(task))) {
nsCOMPtr<nsIWritableVariant> array =
MediaManager::ToJSArray(*task->mMediaDeviceSet);
aOnSuccess.Call(array);
return NS_OK;
}
}
}
return NS_ERROR_UNEXPECTED;
}
MediaEngine* MediaManager::GetBackend() {
MOZ_ASSERT(MediaManager::IsInMediaThread());
// Plugin backends as appropriate. The default engine also currently

Просмотреть файл

@ -232,11 +232,6 @@ class MediaManager final : public nsIMediaManagerService,
const dom::MediaStreamConstraints& aConstraints,
dom::CallerType aCallerType);
MOZ_CAN_RUN_SCRIPT
nsresult GetUserMediaDevices(
nsPIDOMWindowInner* aWindow,
dom::MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
uint64_t aInnerWindowID = 0, const nsAString& aCallID = nsString());
RefPtr<DeviceSetPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow,
dom::CallerType aCallerType);
@ -281,8 +276,6 @@ class MediaManager final : public nsIMediaManagerService,
static void AnonymizeDevices(MediaDeviceSet& aDevices,
const nsACString& aOriginKey,
const uint64_t aWindowId);
static already_AddRefed<nsIWritableVariant> ToJSArray(
MediaDeviceSet& aDevices);
/**
* This function tries to guess the group id for a video device in aDevices

Просмотреть файл

@ -17,17 +17,11 @@ let observe = topic => new Promise(r => Services.obs.addObserver(function o(...a
}, topic));
let getDevices = async constraints => {
let [{ windowID, innerWindowID, callID }] = await Promise.race([
let [{ windowID, innerWindowID, callID, devices }] = await Promise.race([
getUserMedia(constraints),
observe("getUserMedia:request")
]);
let window = Services.wm.getOuterWindowWithId(windowID);
let devices = await new Promise((resolve, reject) => {
resolve = SpecialPowers.wrapCallback(resolve);
reject = SpecialPowers.wrapCallback(reject);
window.navigator.mozGetUserMediaDevices(resolve, reject,
innerWindowID, callID);
});
return devices.map(SpecialPowers.wrapCallback(d => d.QueryInterface(Ci.nsIMediaDevice)));
};

Просмотреть файл

@ -6,6 +6,8 @@
* This is an internal IDL file
*/
interface nsIMediaDevice;
// For gUM request start (getUserMedia:request) notification,
// rawID, mediaSource and audioOutputOptions won't be set.
// For selectAudioOutput request start (getUserMedia:request) notification,
@ -30,6 +32,9 @@ interface GetUserMediaRequest {
readonly attribute DOMString callID;
readonly attribute DOMString rawID;
readonly attribute DOMString mediaSource;
// The set of devices to consider
[Constant, Cached, Frozen]
readonly attribute sequence<nsIMediaDevice> devices;
MediaStreamConstraints getConstraints();
AudioOutputOptions getAudioOutputOptions();
readonly attribute boolean isSecure;

Просмотреть файл

@ -256,24 +256,6 @@ partial interface Navigator {
NavigatorUserMediaErrorCallback errorCallback);
};
// nsINavigatorUserMedia
callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
partial interface Navigator {
[Throws, ChromeOnly]
void mozGetUserMediaDevices(MozGetUserMediaDevicesSuccessCallback onsuccess,
NavigatorUserMediaErrorCallback onerror,
// The originating innerWindowID is needed to
// avoid calling the callbacks if the window has
// navigated away. It is optional only as legacy.
optional unsigned long long innerWindowID = 0,
// The callID is needed in case of multiple
// concurrent requests to find the right one.
// It is optional only as legacy.
// TODO: Rewrite to not need this method anymore,
// now that devices are enumerated earlier.
optional DOMString callID = "");
};
// Service Workers/Navigation Controllers
partial interface Navigator {
[Func="ServiceWorkerContainer::IsEnabled", SameObject]

Просмотреть файл

@ -91,23 +91,16 @@ class GeckoViewPermission {
handleMediaRequest(aRequest) {
const constraints = aRequest.getConstraints();
const callId = aRequest.callID;
const { callId, devices } = aRequest;
const denyRequest = _ => {
Services.obs.notifyObservers(null, "getUserMedia:response:deny", callId);
};
const win = Services.wm.getOuterWindowWithId(aRequest.windowID);
new Promise((resolve, reject) => {
win.navigator.mozGetUserMediaDevices(
resolve,
reject,
aRequest.innerWindowID,
callId
);
// Release the request first.
aRequest = undefined;
})
.then(devices => {
// Release the request first.
aRequest = undefined;
Promise.resolve()
.then(() => {
if (win.closed) {
return Promise.resolve();
}