diff options
Diffstat (limited to 'browser/modules/ContentWebRTC.jsm')
-rw-r--r-- | browser/modules/ContentWebRTC.jsm | 393 |
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(); -} |