mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1270572 - allow un-prompted gUM access if the page has a live track connected to the same device; r=florian,gcp,smaug
MozReview-Commit-ID: EvATqR4NNTH --HG-- extra : rebase_source : cf3b08d7f47e8239bdb6ed27a2eaacb491200d48
This commit is contained in:
parent
7e5fc282b8
commit
f0be461749
@ -4943,8 +4943,8 @@ var TabsProgressListener = {
|
||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
if (tab && tab._sharingState) {
|
||||
gBrowser.setBrowserSharing(aBrowser, {});
|
||||
webrtcUI.forgetStreamsFromBrowser(aBrowser);
|
||||
}
|
||||
webrtcUI.forgetStreamsFromBrowser(aBrowser);
|
||||
|
||||
gBrowser.getNotificationBox(aBrowser).removeTransientNotifications();
|
||||
|
||||
@ -7512,6 +7512,7 @@ var gIdentityHandler = {
|
||||
}
|
||||
}
|
||||
browser.messageManager.sendAsyncMessage("webrtc:StopSharing", windowId);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(gBrowser.selectedBrowser);
|
||||
}
|
||||
SitePermissions.remove(gBrowser.currentURI, aPermission.id, browser);
|
||||
|
||||
|
@ -25,6 +25,7 @@ this.ContentWebRTC = {
|
||||
|
||||
this._initialized = true;
|
||||
Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false);
|
||||
Services.obs.addObserver(handleGUMStop, "recording-device-stopped", false);
|
||||
Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false);
|
||||
Services.obs.addObserver(updateIndicators, "recording-device-events", false);
|
||||
Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
|
||||
@ -35,6 +36,7 @@ this.ContentWebRTC = {
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(handleGUMRequest, "getUserMedia:request");
|
||||
Services.obs.removeObserver(handleGUMStop, "recording-device-stopped");
|
||||
Services.obs.removeObserver(handlePCRequest, "PeerConnection:request");
|
||||
Services.obs.removeObserver(updateIndicators, "recording-device-events");
|
||||
Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended");
|
||||
@ -124,6 +126,19 @@ function handlePCRequest(aSubject, aTopic, aData) {
|
||||
mm.sendAsyncMessage("rtcpeer:Request", request);
|
||||
}
|
||||
|
||||
function handleGUMStop(aSubject, aTopic, aData) {
|
||||
let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
|
||||
|
||||
let request = {
|
||||
windowID: aSubject.windowID,
|
||||
rawID: aSubject.rawID,
|
||||
mediaSource: aSubject.mediaSource,
|
||||
};
|
||||
|
||||
let mm = getMessageManagerForWindow(contentWindow);
|
||||
mm.sendAsyncMessage("webrtc:StopRecording", request);
|
||||
}
|
||||
|
||||
function handleGUMRequest(aSubject, aTopic, aData) {
|
||||
let constraints = aSubject.getConstraints();
|
||||
let secure = aSubject.isSecure;
|
||||
|
@ -45,6 +45,7 @@ this.webrtcUI = {
|
||||
mm.addMessageListener("rtcpeer:Request", this);
|
||||
mm.addMessageListener("rtcpeer:CancelRequest", this);
|
||||
mm.addMessageListener("webrtc:Request", this);
|
||||
mm.addMessageListener("webrtc:StopRecording", this);
|
||||
mm.addMessageListener("webrtc:CancelRequest", this);
|
||||
mm.addMessageListener("webrtc:UpdateBrowserIndicators", this);
|
||||
},
|
||||
@ -62,6 +63,7 @@ this.webrtcUI = {
|
||||
mm.removeMessageListener("rtcpeer:Request", this);
|
||||
mm.removeMessageListener("rtcpeer:CancelRequest", this);
|
||||
mm.removeMessageListener("webrtc:Request", this);
|
||||
mm.removeMessageListener("webrtc:StopRecording");
|
||||
mm.removeMessageListener("webrtc:CancelRequest", this);
|
||||
mm.removeMessageListener("webrtc:UpdateBrowserIndicators", this);
|
||||
|
||||
@ -72,6 +74,7 @@ this.webrtcUI = {
|
||||
},
|
||||
|
||||
processIndicators: new Map(),
|
||||
activePerms: new Map(),
|
||||
|
||||
get showGlobalIndicator() {
|
||||
for (let [, indicators] of this.processIndicators) {
|
||||
@ -142,8 +145,13 @@ this.webrtcUI = {
|
||||
}
|
||||
},
|
||||
|
||||
forgetActivePermissionsFromBrowser(aBrowser) {
|
||||
webrtcUI.activePerms.delete(aBrowser.outerWindowID);
|
||||
},
|
||||
|
||||
forgetStreamsFromBrowser(aBrowser) {
|
||||
this._streams = this._streams.filter(stream => stream.browser != aBrowser);
|
||||
webrtcUI.forgetActivePermissionsFromBrowser(aBrowser);
|
||||
},
|
||||
|
||||
showSharingDoorhanger(aActiveStream) {
|
||||
@ -265,6 +273,9 @@ this.webrtcUI = {
|
||||
case "webrtc:Request":
|
||||
prompt(aMessage.target, aMessage.data);
|
||||
break;
|
||||
case "webrtc:StopRecording":
|
||||
stopRecording(aMessage.target, aMessage.data);
|
||||
break;
|
||||
case "webrtc:CancelRequest":
|
||||
removePrompt(aMessage.target, aMessage.data);
|
||||
break;
|
||||
@ -334,6 +345,21 @@ function getHost(uri, href) {
|
||||
return host;
|
||||
}
|
||||
|
||||
function stopRecording(aBrowser, aRequest) {
|
||||
let outerWindowID = aBrowser.outerWindowID;
|
||||
|
||||
if (!webrtcUI.activePerms.has(outerWindowID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aRequest.rawID) {
|
||||
webrtcUI.activePerms.delete(outerWindowID);
|
||||
} else {
|
||||
let set = webrtcUI.activePerms.get(outerWindowID);
|
||||
set.delete(aRequest.windowID + aRequest.mediaSource + aRequest.rawID);
|
||||
}
|
||||
}
|
||||
|
||||
function prompt(aBrowser, aRequest) {
|
||||
let { audioDevices, videoDevices, sharingScreen, sharingAudio,
|
||||
requestTypes } = aRequest;
|
||||
@ -476,18 +502,37 @@ function prompt(aBrowser, aRequest) {
|
||||
if (videoDevices.length && sharingScreen)
|
||||
camAllowed = false;
|
||||
|
||||
if ((!audioDevices.length || micAllowed) &&
|
||||
(!videoDevices.length || camAllowed)) {
|
||||
// All permissions we were about to request are already persistently set.
|
||||
let activeCamera;
|
||||
let activeMic;
|
||||
|
||||
for (let device of videoDevices) {
|
||||
let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
|
||||
if (set && set.has(aRequest.windowID + device.mediaSource + device.id)) {
|
||||
activeCamera = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let device of audioDevices) {
|
||||
let set = webrtcUI.activePerms.get(aBrowser.outerWindowID);
|
||||
if (set && set.has(aRequest.windowID + device.mediaSource + device.id)) {
|
||||
activeMic = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!audioDevices.length || micAllowed || activeMic) &&
|
||||
(!videoDevices.length || camAllowed || activeCamera)) {
|
||||
let allowedDevices = [];
|
||||
if (videoDevices.length && camAllowed) {
|
||||
allowedDevices.push(videoDevices[0].deviceIndex);
|
||||
if (videoDevices.length) {
|
||||
allowedDevices.push((activeCamera || videoDevices[0]).deviceIndex);
|
||||
Services.perms.add(uri, "MediaManagerVideo",
|
||||
Services.perms.ALLOW_ACTION,
|
||||
Services.perms.EXPIRE_SESSION);
|
||||
}
|
||||
if (audioDevices.length && micAllowed)
|
||||
allowedDevices.push(audioDevices[0].deviceIndex);
|
||||
if (audioDevices.length) {
|
||||
allowedDevices.push((activeMic || audioDevices[0]).deviceIndex);
|
||||
}
|
||||
|
||||
// Remember on which URIs we found persistent permissions so that we
|
||||
// can remove them if the user clicks 'Stop Sharing'. There's no
|
||||
@ -680,6 +725,17 @@ function prompt(aBrowser, aRequest) {
|
||||
// (it's really one-shot, not for the entire session)
|
||||
perms.add(uri, "MediaManagerVideo", perms.ALLOW_ACTION,
|
||||
perms.EXPIRE_SESSION);
|
||||
if (!webrtcUI.activePerms.has(aBrowser.outerWindowID)) {
|
||||
webrtcUI.activePerms.set(aBrowser.outerWindowID, new Set());
|
||||
}
|
||||
|
||||
for (let device of videoDevices) {
|
||||
if (device.deviceIndex == videoDeviceIndex) {
|
||||
webrtcUI.activePerms.get(aBrowser.outerWindowID)
|
||||
.add(aRequest.windowID + device.mediaSource + device.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remember)
|
||||
SitePermissions.set(uri, "camera", SitePermissions.ALLOW);
|
||||
} else {
|
||||
@ -693,6 +749,17 @@ function prompt(aBrowser, aRequest) {
|
||||
let allowMic = audioDeviceIndex != "-1";
|
||||
if (allowMic) {
|
||||
allowedDevices.push(audioDeviceIndex);
|
||||
if (!webrtcUI.activePerms.has(aBrowser.outerWindowID)) {
|
||||
webrtcUI.activePerms.set(aBrowser.outerWindowID, new Set());
|
||||
}
|
||||
|
||||
for (let device of audioDevices) {
|
||||
if (device.deviceIndex == audioDeviceIndex) {
|
||||
webrtcUI.activePerms.get(aBrowser.outerWindowID)
|
||||
.add(aRequest.windowID + device.mediaSource + device.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remember)
|
||||
SitePermissions.set(uri, "microphone", SitePermissions.ALLOW);
|
||||
} else {
|
||||
|
@ -25,6 +25,18 @@ GetUserMediaRequest::GetUserMediaRequest(
|
||||
{
|
||||
}
|
||||
|
||||
GetUserMediaRequest::GetUserMediaRequest(
|
||||
nsPIDOMWindowInner* aInnerWindow,
|
||||
const nsAString& aRawId,
|
||||
const nsAString& aMediaSource)
|
||||
: mRawID(aRawId)
|
||||
, mMediaSource(aMediaSource)
|
||||
{
|
||||
if (aInnerWindow && aInnerWindow->GetOuterWindow()) {
|
||||
mOuterWindowID = aInnerWindow->GetOuterWindow()->WindowID();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(GetUserMediaRequest)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(GetUserMediaRequest)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(GetUserMediaRequest)
|
||||
@ -49,6 +61,16 @@ void GetUserMediaRequest::GetCallID(nsString& retval)
|
||||
retval = mCallID;
|
||||
}
|
||||
|
||||
void GetUserMediaRequest::GetRawID(nsString& retval)
|
||||
{
|
||||
retval = mRawID;
|
||||
}
|
||||
|
||||
void GetUserMediaRequest::GetMediaSource(nsString& retval)
|
||||
{
|
||||
retval = mMediaSource;
|
||||
}
|
||||
|
||||
uint64_t GetUserMediaRequest::WindowID()
|
||||
{
|
||||
return mOuterWindowID;
|
||||
|
@ -24,6 +24,9 @@ public:
|
||||
const nsAString& aCallID,
|
||||
const MediaStreamConstraints& aConstraints,
|
||||
bool aIsSecure);
|
||||
GetUserMediaRequest(nsPIDOMWindowInner* aInnerWindow,
|
||||
const nsAString& aRawId,
|
||||
const nsAString& aMediaSource);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GetUserMediaRequest)
|
||||
@ -35,6 +38,8 @@ public:
|
||||
uint64_t InnerWindowID();
|
||||
bool IsSecure();
|
||||
void GetCallID(nsString& retval);
|
||||
void GetRawID(nsString& retval);
|
||||
void GetMediaSource(nsString& retval);
|
||||
void GetConstraints(MediaStreamConstraints &result);
|
||||
|
||||
private:
|
||||
@ -42,6 +47,8 @@ private:
|
||||
|
||||
uint64_t mInnerWindowID, mOuterWindowID;
|
||||
const nsString mCallID;
|
||||
const nsString mRawID;
|
||||
const nsString mMediaSource;
|
||||
nsAutoPtr<MediaStreamConstraints> mConstraints;
|
||||
bool mIsSecure;
|
||||
};
|
||||
|
@ -175,6 +175,7 @@ HostIsHttps(nsIURI &docURI)
|
||||
*/
|
||||
class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
|
||||
{
|
||||
friend MediaManager;
|
||||
public:
|
||||
// Create in an inactive state
|
||||
GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
|
||||
@ -2749,15 +2750,97 @@ MediaManager::RemoveFromWindowList(uint64_t aWindowID,
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsString videoRawId;
|
||||
nsString audioRawId;
|
||||
nsString videoSourceType;
|
||||
nsString audioSourceType;
|
||||
bool hasVideoDevice = aListener->mVideoDevice;
|
||||
bool hasAudioDevice = aListener->mAudioDevice;
|
||||
|
||||
if (hasVideoDevice) {
|
||||
aListener->mVideoDevice->GetRawId(videoRawId);
|
||||
aListener->mVideoDevice->GetMediaSource(videoSourceType);
|
||||
}
|
||||
if (hasAudioDevice) {
|
||||
aListener->mAudioDevice->GetRawId(audioRawId);
|
||||
aListener->mAudioDevice->GetMediaSource(audioSourceType);
|
||||
}
|
||||
|
||||
// This is defined as safe on an inactive GUMCMSListener
|
||||
aListener->Remove(); // really queues the remove
|
||||
|
||||
StreamListeners* listeners = GetWindowListeners(aWindowID);
|
||||
if (!listeners) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
|
||||
RefPtr<nsPIDOMWindowInner> window = globalWindow ? globalWindow->AsInner()
|
||||
: nullptr;
|
||||
if (window != nullptr) {
|
||||
RefPtr<GetUserMediaRequest> req =
|
||||
new GetUserMediaRequest(window, NullString(), NullString());
|
||||
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
listeners->RemoveElement(aListener);
|
||||
if (listeners->Length() == 0) {
|
||||
|
||||
uint32_t length = listeners->Length();
|
||||
|
||||
if (hasVideoDevice) {
|
||||
bool revokeVideoPermission = true;
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
|
||||
listeners->ElementAt(i);
|
||||
if (hasVideoDevice && listener->mVideoDevice) {
|
||||
nsString rawId;
|
||||
listener->mVideoDevice->GetRawId(rawId);
|
||||
if (videoRawId.Equals(rawId)) {
|
||||
revokeVideoPermission = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revokeVideoPermission) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
|
||||
RefPtr<nsPIDOMWindowInner> window = globalWindow ? globalWindow->AsInner()
|
||||
: nullptr;
|
||||
RefPtr<GetUserMediaRequest> req =
|
||||
new GetUserMediaRequest(window, videoRawId, videoSourceType);
|
||||
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAudioDevice) {
|
||||
bool revokeAudioPermission = true;
|
||||
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
|
||||
listeners->ElementAt(i);
|
||||
if (hasAudioDevice && listener->mAudioDevice) {
|
||||
nsString rawId;
|
||||
listener->mAudioDevice->GetRawId(rawId);
|
||||
if (audioRawId.Equals(rawId)) {
|
||||
revokeAudioPermission = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (revokeAudioPermission) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
auto* globalWindow = nsGlobalWindow::GetInnerWindowWithId(aWindowID);
|
||||
RefPtr<nsPIDOMWindowInner> window = globalWindow ? globalWindow->AsInner()
|
||||
: nullptr;
|
||||
RefPtr<GetUserMediaRequest> req =
|
||||
new GetUserMediaRequest(window, audioRawId, audioSourceType);
|
||||
obs->NotifyObservers(req, "recording-device-stopped", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
RemoveWindowID(aWindowID);
|
||||
// listeners has been deleted here
|
||||
}
|
||||
|
@ -6,11 +6,20 @@
|
||||
* This is an internal IDL file
|
||||
*/
|
||||
|
||||
// for gUM request start (getUserMedia:request) notification,
|
||||
// rawID and mediaSource won't be set.
|
||||
// for gUM request stop (recording-device-stopped) notification due to page reload,
|
||||
// only windowID will be set.
|
||||
// for gUM request stop (recording-device-stopped) notification due to track stop,
|
||||
// only windowID, rawID and mediaSource will be set
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface GetUserMediaRequest {
|
||||
readonly attribute unsigned long long windowID;
|
||||
readonly attribute unsigned long long innerWindowID;
|
||||
readonly attribute DOMString callID;
|
||||
readonly attribute DOMString rawID;
|
||||
readonly attribute DOMString mediaSource;
|
||||
MediaStreamConstraints getConstraints();
|
||||
readonly attribute boolean isSecure;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user