summaryrefslogtreecommitdiffstats
path: root/browser/modules/ContentWebRTC.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules/ContentWebRTC.jsm')
-rw-r--r--browser/modules/ContentWebRTC.jsm393
1 files changed, 0 insertions, 393 deletions
diff --git a/browser/modules/ContentWebRTC.jsm b/browser/modules/ContentWebRTC.jsm
deleted file mode 100644
index fd50176a0..000000000
--- a/browser/modules/ContentWebRTC.jsm
+++ /dev/null
@@ -1,393 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
-
-this.EXPORTED_SYMBOLS = [ "ContentWebRTC" ];
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyServiceGetter(this, "MediaManagerService",
- "@mozilla.org/mediaManagerService;1",
- "nsIMediaManagerService");
-
-const kBrowserURL = "chrome://browser/content/browser.xul";
-
-this.ContentWebRTC = {
- _initialized: false,
-
- init: function() {
- if (this._initialized)
- return;
-
- this._initialized = true;
- Services.obs.addObserver(handleGUMRequest, "getUserMedia:request", false);
- Services.obs.addObserver(handlePCRequest, "PeerConnection:request", false);
- Services.obs.addObserver(updateIndicators, "recording-device-events", false);
- Services.obs.addObserver(removeBrowserSpecificIndicator, "recording-window-ended", false);
-
- if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
- Services.obs.addObserver(processShutdown, "content-child-shutdown", false);
- },
-
- uninit: function() {
- Services.obs.removeObserver(handleGUMRequest, "getUserMedia:request");
- Services.obs.removeObserver(handlePCRequest, "PeerConnection:request");
- Services.obs.removeObserver(updateIndicators, "recording-device-events");
- Services.obs.removeObserver(removeBrowserSpecificIndicator, "recording-window-ended");
-
- if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT)
- Services.obs.removeObserver(processShutdown, "content-child-shutdown");
-
- this._initialized = false;
- },
-
- // Called only for 'unload' to remove pending gUM prompts in reloaded frames.
- handleEvent: function(aEvent) {
- let contentWindow = aEvent.target.defaultView;
- let mm = getMessageManagerForWindow(contentWindow);
- for (let key of contentWindow.pendingGetUserMediaRequests.keys()) {
- mm.sendAsyncMessage("webrtc:CancelRequest", key);
- }
- for (let key of contentWindow.pendingPeerConnectionRequests.keys()) {
- mm.sendAsyncMessage("rtcpeer:CancelRequest", key);
- }
- },
-
- receiveMessage: function(aMessage) {
- switch (aMessage.name) {
- case "rtcpeer:Allow":
- case "rtcpeer:Deny": {
- let callID = aMessage.data.callID;
- let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID);
- forgetPCRequest(contentWindow, callID);
- let topic = (aMessage.name == "rtcpeer:Allow") ? "PeerConnection:response:allow" :
- "PeerConnection:response:deny";
- Services.obs.notifyObservers(null, topic, callID);
- break;
- }
- case "webrtc:Allow": {
- let callID = aMessage.data.callID;
- let contentWindow = Services.wm.getOuterWindowWithId(aMessage.data.windowID);
- let devices = contentWindow.pendingGetUserMediaRequests.get(callID);
- forgetGUMRequest(contentWindow, callID);
-
- let allowedDevices = Cc["@mozilla.org/array;1"]
- .createInstance(Ci.nsIMutableArray);
- for (let deviceIndex of aMessage.data.devices)
- allowedDevices.appendElement(devices[deviceIndex], /* weak =*/ false);
-
- Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", callID);
- break;
- }
- case "webrtc:Deny":
- denyGUMRequest(aMessage.data);
- break;
- case "webrtc:StopSharing":
- Services.obs.notifyObservers(null, "getUserMedia:revoke", aMessage.data);
- break;
- }
- }
-};
-
-function handlePCRequest(aSubject, aTopic, aData) {
- let { windowID, innerWindowID, callID, isSecure } = aSubject;
- let contentWindow = Services.wm.getOuterWindowWithId(windowID);
-
- let mm = getMessageManagerForWindow(contentWindow);
- if (!mm) {
- // Workaround for Bug 1207784. To use WebRTC, add-ons right now use
- // hiddenWindow.mozRTCPeerConnection which is only privileged on OSX. Other
- // platforms end up here without a message manager.
- // TODO: Remove once there's a better way (1215591).
-
- // Skip permission check in the absence of a message manager.
- Services.obs.notifyObservers(null, "PeerConnection:response:allow", callID);
- return;
- }
-
- if (!contentWindow.pendingPeerConnectionRequests) {
- setupPendingListsInitially(contentWindow);
- }
- contentWindow.pendingPeerConnectionRequests.add(callID);
-
- let request = {
- windowID: windowID,
- innerWindowID: innerWindowID,
- callID: callID,
- documentURI: contentWindow.document.documentURI,
- secure: isSecure,
- };
- mm.sendAsyncMessage("rtcpeer:Request", request);
-}
-
-function handleGUMRequest(aSubject, aTopic, aData) {
- let constraints = aSubject.getConstraints();
- let secure = aSubject.isSecure;
- let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
-
- contentWindow.navigator.mozGetUserMediaDevices(
- constraints,
- 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);
- },
- function (error) {
- // bug 827146 -- In the future, the UI should catch NotFoundError
- // and allow the user to plug in a device, instead of immediately failing.
- denyGUMRequest({callID: aSubject.callID}, error);
- },
- aSubject.innerWindowID,
- aSubject.callID);
-}
-
-function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSecure) {
- let audioDevices = [];
- let videoDevices = [];
- let devices = [];
-
- // MediaStreamConstraints defines video as 'boolean or MediaTrackConstraints'.
- let video = aConstraints.video || aConstraints.picture;
- let audio = aConstraints.audio;
- let sharingScreen = video && typeof(video) != "boolean" &&
- video.mediaSource != "camera";
- let sharingAudio = audio && typeof(audio) != "boolean" &&
- audio.mediaSource != "microphone";
- for (let device of aDevices) {
- device = device.QueryInterface(Ci.nsIMediaDevice);
- switch (device.type) {
- case "audio":
- // Check that if we got a microphone, we have not requested an audio
- // capture, and if we have requested an audio capture, we are not
- // getting a microphone instead.
- if (audio && (device.mediaSource == "microphone") != sharingAudio) {
- audioDevices.push({name: device.name, deviceIndex: devices.length,
- id: device.rawId, mediaSource: device.mediaSource});
- devices.push(device);
- }
- break;
- case "video":
- // Verify that if we got a camera, we haven't requested a screen share,
- // or that if we requested a screen share we aren't getting a camera.
- if (video && (device.mediaSource == "camera") != sharingScreen) {
- let deviceObject = {name: device.name, deviceIndex: devices.length,
- id: device.rawId, mediaSource: device.mediaSource};
- if (device.scary)
- deviceObject.scary = true;
- videoDevices.push(deviceObject);
- devices.push(device);
- }
- break;
- }
- }
-
- let requestTypes = [];
- if (videoDevices.length)
- requestTypes.push(sharingScreen ? "Screen" : "Camera");
- if (audioDevices.length)
- requestTypes.push(sharingAudio ? "AudioCapture" : "Microphone");
-
- if (!requestTypes.length) {
- denyGUMRequest({callID: aCallID}, "NotFoundError");
- return;
- }
-
- if (!aContentWindow.pendingGetUserMediaRequests) {
- setupPendingListsInitially(aContentWindow);
- }
- aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
-
- let request = {
- callID: aCallID,
- windowID: aWindowID,
- origin: aContentWindow.origin,
- documentURI: aContentWindow.document.documentURI,
- secure: aSecure,
- requestTypes: requestTypes,
- sharingScreen: sharingScreen,
- sharingAudio: sharingAudio,
- audioDevices: audioDevices,
- videoDevices: videoDevices
- };
-
- let mm = getMessageManagerForWindow(aContentWindow);
- mm.sendAsyncMessage("webrtc:Request", request);
-}
-
-function denyGUMRequest(aData, aError) {
- let msg = null;
- if (aError) {
- msg = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
- msg.data = aError;
- }
- Services.obs.notifyObservers(msg, "getUserMedia:response:deny", aData.callID);
-
- if (!aData.windowID)
- return;
- let contentWindow = Services.wm.getOuterWindowWithId(aData.windowID);
- if (contentWindow.pendingGetUserMediaRequests)
- forgetGUMRequest(contentWindow, aData.callID);
-}
-
-function forgetGUMRequest(aContentWindow, aCallID) {
- aContentWindow.pendingGetUserMediaRequests.delete(aCallID);
- forgetPendingListsEventually(aContentWindow);
-}
-
-function forgetPCRequest(aContentWindow, aCallID) {
- aContentWindow.pendingPeerConnectionRequests.delete(aCallID);
- forgetPendingListsEventually(aContentWindow);
-}
-
-function setupPendingListsInitially(aContentWindow) {
- if (aContentWindow.pendingGetUserMediaRequests) {
- return;
- }
- aContentWindow.pendingGetUserMediaRequests = new Map();
- aContentWindow.pendingPeerConnectionRequests = new Set();
- aContentWindow.addEventListener("unload", ContentWebRTC);
-}
-
-function forgetPendingListsEventually(aContentWindow) {
- if (aContentWindow.pendingGetUserMediaRequests.size ||
- aContentWindow.pendingPeerConnectionRequests.size) {
- return;
- }
- aContentWindow.pendingGetUserMediaRequests = null;
- aContentWindow.pendingPeerConnectionRequests = null;
- aContentWindow.removeEventListener("unload", ContentWebRTC);
-}
-
-function updateIndicators(aSubject, aTopic, aData) {
- if (aSubject instanceof Ci.nsIPropertyBag &&
- aSubject.getProperty("requestURL") == kBrowserURL) {
- // Ignore notifications caused by the browser UI showing previews.
- return;
- }
-
- let contentWindowArray = MediaManagerService.activeMediaCaptureWindows;
- let count = contentWindowArray.length;
-
- let state = {
- showGlobalIndicator: count > 0,
- showCameraIndicator: false,
- showMicrophoneIndicator: false,
- showScreenSharingIndicator: ""
- };
-
- let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
- .getService(Ci.nsIMessageSender);
- cpmm.sendAsyncMessage("webrtc:UpdatingIndicators");
-
- // If several iframes in the same page use media streams, it's possible to
- // have the same top level window several times. We use a Set to avoid
- // sending duplicate notifications.
- let contentWindows = new Set();
- for (let i = 0; i < count; ++i) {
- contentWindows.add(contentWindowArray.queryElementAt(i, Ci.nsISupports).top);
- }
-
- for (let contentWindow of contentWindows) {
- if (contentWindow.document.documentURI == kBrowserURL) {
- // There may be a preview shown at the same time as other streams.
- continue;
- }
-
- let tabState = getTabStateForContentWindow(contentWindow);
- if (tabState.camera)
- state.showCameraIndicator = true;
- if (tabState.microphone)
- state.showMicrophoneIndicator = true;
- if (tabState.screen) {
- if (tabState.screen == "Screen") {
- state.showScreenSharingIndicator = "Screen";
- }
- else if (tabState.screen == "Window") {
- if (state.showScreenSharingIndicator != "Screen")
- state.showScreenSharingIndicator = "Window";
- }
- else if (tabState.screen == "Application") {
- if (!state.showScreenSharingIndicator)
- state.showScreenSharingIndicator = "Application";
- }
- else if (tabState.screen == "Browser") {
- if (!state.showScreenSharingIndicator)
- state.showScreenSharingIndicator = "Browser";
- }
- }
- let mm = getMessageManagerForWindow(contentWindow);
- mm.sendAsyncMessage("webrtc:UpdateBrowserIndicators", tabState);
- }
-
- cpmm.sendAsyncMessage("webrtc:UpdateGlobalIndicators", state);
-}
-
-function removeBrowserSpecificIndicator(aSubject, aTopic, aData) {
- let contentWindow = Services.wm.getOuterWindowWithId(aData).top;
- if (contentWindow.document.documentURI == kBrowserURL) {
- // Ignore notifications caused by the browser UI showing previews.
- return;
- }
-
- let tabState = getTabStateForContentWindow(contentWindow);
- if (!tabState.camera && !tabState.microphone && !tabState.screen)
- tabState = {windowId: tabState.windowId};
-
- let mm = getMessageManagerForWindow(contentWindow);
- if (mm)
- mm.sendAsyncMessage("webrtc:UpdateBrowserIndicators", tabState);
-}
-
-function getTabStateForContentWindow(aContentWindow) {
- let camera = {}, microphone = {}, screen = {}, window = {}, app = {}, browser = {};
- MediaManagerService.mediaCaptureWindowState(aContentWindow, camera, microphone,
- screen, window, app, browser);
- let tabState = {camera: camera.value, microphone: microphone.value};
- if (screen.value)
- tabState.screen = "Screen";
- else if (window.value)
- tabState.screen = "Window";
- else if (app.value)
- tabState.screen = "Application";
- else if (browser.value)
- tabState.screen = "Browser";
-
- tabState.windowId = getInnerWindowIDForWindow(aContentWindow);
- tabState.documentURI = aContentWindow.document.documentURI;
-
- return tabState;
-}
-
-function getInnerWindowIDForWindow(aContentWindow) {
- return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .currentInnerWindowID;
-}
-
-function getMessageManagerForWindow(aContentWindow) {
- let ir = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDocShell)
- .sameTypeRootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor);
- try {
- // If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
- return ir.getInterface(Ci.nsIContentFrameMessageManager);
- } catch (e) {
- if (e.result == Cr.NS_NOINTERFACE) {
- return null;
- }
- throw e;
- }
-}
-
-function processShutdown() {
- ContentWebRTC.uninit();
-}