tenfourfox/mobile/android/chrome/content/WebrtcUI.js
Cameron Kaiser c9b2922b70 hello FPR
2017-04-19 00:56:45 -07:00

280 lines
10 KiB
JavaScript

/* 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";
this.EXPORTED_SYMBOLS = ["WebrtcUI"];
XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ParentalControls", "@mozilla.org/parental-controls-service;1", "nsIParentalControlsService");
var WebrtcUI = {
_notificationId: null,
// Add-ons can override stock permission behavior by doing:
//
// var stockObserve = WebrtcUI.observe;
//
// webrtcUI.observe = function(aSubject, aTopic, aData) {
// switch (aTopic) {
// case "PeerConnection:request": {
// // new code.
// break;
// ...
// default:
// return stockObserve.call(this, aSubject, aTopic, aData);
//
// See browser/modules/webrtcUI.jsm for details.
observe: function(aSubject, aTopic, aData) {
if (aTopic === "getUserMedia:request") {
this.handleGumRequest(aSubject, aTopic, aData);
} else if (aTopic === "PeerConnection:request") {
this.handlePCRequest(aSubject, aTopic, aData);
} else if (aTopic === "recording-device-events") {
switch (aData) {
case "shutdown":
case "starting":
this.notify();
break;
}
}
},
notify: function() {
let windows = MediaManagerService.activeMediaCaptureWindows;
let count = windows.Count();
let msg = {};
if (count == 0) {
if (this._notificationId) {
Notifications.cancel(this._notificationId);
this._notificationId = null;
}
} else {
let notificationOptions = {
title: Strings.brand.GetStringFromName("brandShortName"),
when: null, // hide the date row
light: [0xFF9500FF, 1000, 1000],
ongoing: true
};
let cameraActive = false;
let audioActive = false;
for (let i = 0; i < count; i++) {
let win = windows.GetElementAt(i);
let hasAudio = {};
let hasVideo = {};
MediaManagerService.mediaCaptureWindowState(win, hasVideo, hasAudio);
if (hasVideo.value) cameraActive = true;
if (hasAudio.value) audioActive = true;
}
if (cameraActive && audioActive) {
notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCameraAndMicrophone.message2");
notificationOptions.icon = "drawable:alert_mic_camera";
} else if (cameraActive) {
notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCamera.message2");
notificationOptions.icon = "drawable:alert_camera";
} else if (audioActive) {
notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingMicrophone.message2");
notificationOptions.icon = "drawable:alert_mic";
} else {
// somethings wrong. lets throw
throw "Couldn't find any cameras or microphones being used"
}
if (this._notificationId)
Notifications.update(this._notificationId, notificationOptions);
else
this._notificationId = Notifications.create(notificationOptions);
if (count > 1)
msg.count = count;
}
},
handlePCRequest: function handlePCRequest(aSubject, aTopic, aData) {
aSubject = aSubject.wrappedJSObject;
let { callID } = aSubject;
// Also available: windowID, isSecure, innerWindowID. For contentWindow do:
//
// let contentWindow = Services.wm.getOuterWindowWithId(windowID);
Services.obs.notifyObservers(null, "PeerConnection:response:allow", callID);
},
handleGumRequest: function handleGumRequest(aSubject, aTopic, aData) {
let constraints = aSubject.getConstraints();
let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
contentWindow.navigator.mozGetUserMediaDevices(
constraints,
function (devices) {
if (!ParentalControls.isAllowed(ParentalControls.CAMERA_MICROPHONE)) {
Services.obs.notifyObservers(null, "getUserMedia:response:deny", aSubject.callID);
WebrtcUI.showBlockMessage(devices);
return;
}
WebrtcUI.prompt(contentWindow, aSubject.callID, constraints.audio,
constraints.video, devices);
},
function (error) {
Cu.reportError(error);
},
aSubject.innerWindowID,
aSubject.callID);
},
getDeviceButtons: function(audioDevices, videoDevices, aCallID) {
return [{
label: Strings.browser.GetStringFromName("getUserMedia.denyRequest.label"),
callback: function() {
Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID);
}
},
{
label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"),
callback: function(checked /* ignored */, inputs) {
let allowedDevices = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
let audioId = 0;
if (inputs && inputs.audioDevice != undefined)
audioId = inputs.audioDevice;
if (audioDevices[audioId])
allowedDevices.AppendElement(audioDevices[audioId]);
let videoId = 0;
if (inputs && inputs.videoSource != undefined)
videoId = inputs.videoSource;
if (videoDevices[videoId])
allowedDevices.AppendElement(videoDevices[videoId]);
Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
},
positive: true
}];
},
// Get a list of string names for devices. Ensures that none of the strings are blank
_getList: function(aDevices, aType) {
let defaultCount = 0;
return aDevices.map(function(device) {
// if this is a Camera input, convert the name to something readable
let res = /Camera\ \d+,\ Facing (front|back)/.exec(device.name);
if (res)
return Strings.browser.GetStringFromName("getUserMedia." + aType + "." + res[1] + "Camera");
if (device.name.startsWith("&") && device.name.endsWith(";"))
return Strings.browser.GetStringFromName(device.name.substring(1, device.name.length -1));
if (device.name.trim() == "") {
defaultCount++;
return Strings.browser.formatStringFromName("getUserMedia." + aType + ".default", [defaultCount], 1);
}
return device.name
}, this);
},
_addDevicesToOptions: function(aDevices, aType, aOptions, extraOptions) {
if (aDevices.length) {
// Filter out empty items from the list
let list = this._getList(aDevices, aType);
if (extraOptions)
list = list.concat(extraOptions);
if (list.length > 0) {
aOptions.inputs.push({
id: aType,
type: "menulist",
label: Strings.browser.GetStringFromName("getUserMedia." + aType + ".prompt"),
values: list
});
}
}
},
showBlockMessage: function(aDevices) {
let microphone = false;
let camera = false;
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
if (device.type == "audio") {
microphone = true;
} else if (device.type == "video") {
camera = true;
}
}
let message;
if (microphone && !camera) {
message = Strings.browser.GetStringFromName("getUserMedia.blockedMicrophoneAccess");
} else if (camera && !microphone) {
message = Strings.browser.GetStringFromName("getUserMedia.blockedCameraAccess");
} else {
message = Strings.browser.GetStringFromName("getUserMedia.blockedCameraAndMicrophoneAccess");
}
NativeWindow.doorhanger.show(message, "webrtc-blocked", [], BrowserApp.selectedTab.id, {});
},
prompt: function prompt(aContentWindow, aCallID, aAudioRequested,
aVideoRequested, aDevices) {
let audioDevices = [];
let videoDevices = [];
for (let device of aDevices) {
device = device.QueryInterface(Ci.nsIMediaDevice);
switch (device.type) {
case "audio":
if (aAudioRequested)
audioDevices.push(device);
break;
case "video":
if (aVideoRequested)
videoDevices.push(device);
break;
}
}
let requestType;
if (audioDevices.length && videoDevices.length)
requestType = "CameraAndMicrophone";
else if (audioDevices.length)
requestType = "Microphone";
else if (videoDevices.length)
requestType = "Camera";
else
return;
let host = aContentWindow.document.documentURIObject.host;
let requestor = BrowserApp.manifest ? "'" + BrowserApp.manifest.name + "'" : host;
let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1);
let options = { inputs: [] };
// if the users only option would be to select "No Audio" or "No Video"
// i.e. we're only showing audio or only video and there is only one device for that type
// don't bother showing a menulist to select from
var extraItems = null;
if (videoDevices.length > 1 || audioDevices.length > 0) {
// Only show the No Video option if there are also Audio devices to choose from
if (audioDevices.length > 0)
extraItems = [ Strings.browser.GetStringFromName("getUserMedia.videoSource.none") ];
// videoSource is both the string used for l10n lookup and the object that will be returned
this._addDevicesToOptions(videoDevices, "videoSource", options, extraItems);
}
if (audioDevices.length > 1 || videoDevices.length > 0) {
// Only show the No Audio option if there are also Video devices to choose from
if (videoDevices.length > 0)
extraItems = [ Strings.browser.GetStringFromName("getUserMedia.audioDevice.none") ];
this._addDevicesToOptions(audioDevices, "audioDevice", options, extraItems);
}
let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID);
NativeWindow.doorhanger.show(message, "webrtc-request", buttons, BrowserApp.selectedTab.id, options);
}
}