1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/chrome/content/WebrtcUI.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,215 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +"use strict"; 1.8 + 1.9 +XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); 1.10 + 1.11 +var WebrtcUI = { 1.12 + _notificationId: null, 1.13 + 1.14 + observe: function(aSubject, aTopic, aData) { 1.15 + if (aTopic === "getUserMedia:request") { 1.16 + this.handleRequest(aSubject, aTopic, aData); 1.17 + } else if (aTopic === "recording-device-events") { 1.18 + switch (aData) { 1.19 + case "shutdown": 1.20 + case "starting": 1.21 + this.notify(); 1.22 + break; 1.23 + } 1.24 + } 1.25 + }, 1.26 + 1.27 + notify: function() { 1.28 + let windows = MediaManagerService.activeMediaCaptureWindows; 1.29 + let count = windows.Count(); 1.30 + let msg = {}; 1.31 + if (count == 0) { 1.32 + if (this._notificationId) { 1.33 + Notifications.cancel(this._notificationId); 1.34 + this._notificationId = null; 1.35 + } 1.36 + } else { 1.37 + let notificationOptions = { 1.38 + title: Strings.brand.GetStringFromName("brandShortName"), 1.39 + when: null, // hide the date row 1.40 + light: [0xFF9500FF, 1000, 1000], 1.41 + ongoing: true 1.42 + }; 1.43 + 1.44 + let cameraActive = false; 1.45 + let audioActive = false; 1.46 + for (let i = 0; i < count; i++) { 1.47 + let win = windows.GetElementAt(i); 1.48 + let hasAudio = {}; 1.49 + let hasVideo = {}; 1.50 + MediaManagerService.mediaCaptureWindowState(win, hasVideo, hasAudio); 1.51 + if (hasVideo.value) cameraActive = true; 1.52 + if (hasAudio.value) audioActive = true; 1.53 + } 1.54 + 1.55 + if (cameraActive && audioActive) { 1.56 + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCameraAndMicrophone.message2"); 1.57 + notificationOptions.icon = "drawable:alert_mic_camera"; 1.58 + } else if (cameraActive) { 1.59 + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCamera.message2"); 1.60 + notificationOptions.icon = "drawable:alert_camera"; 1.61 + } else if (audioActive) { 1.62 + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingMicrophone.message2"); 1.63 + notificationOptions.icon = "drawable:alert_mic"; 1.64 + } else { 1.65 + // somethings wrong. lets throw 1.66 + throw "Couldn't find any cameras or microphones being used" 1.67 + } 1.68 + 1.69 + if (this._notificationId) 1.70 + Notifications.update(this._notificationId, notificationOptions); 1.71 + else 1.72 + this._notificationId = Notifications.create(notificationOptions); 1.73 + if (count > 1) 1.74 + msg.count = count; 1.75 + } 1.76 + }, 1.77 + 1.78 + handleRequest: function handleRequest(aSubject, aTopic, aData) { 1.79 + let constraints = aSubject.getConstraints(); 1.80 + let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID); 1.81 + 1.82 + contentWindow.navigator.mozGetUserMediaDevices( 1.83 + constraints, 1.84 + function (devices) { 1.85 + WebrtcUI.prompt(contentWindow, aSubject.callID, constraints.audio, 1.86 + constraints.video, devices); 1.87 + }, 1.88 + function (error) { 1.89 + Cu.reportError(error); 1.90 + }, 1.91 + aSubject.innerWindowID); 1.92 + }, 1.93 + 1.94 + getDeviceButtons: function(audioDevices, videoDevices, aCallID) { 1.95 + return [{ 1.96 + label: Strings.browser.GetStringFromName("getUserMedia.denyRequest.label"), 1.97 + callback: function() { 1.98 + Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID); 1.99 + } 1.100 + }, 1.101 + { 1.102 + label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"), 1.103 + callback: function(checked /* ignored */, inputs) { 1.104 + let allowedDevices = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray); 1.105 + 1.106 + let audioId = 0; 1.107 + if (inputs && inputs.audioDevice != undefined) 1.108 + audioId = inputs.audioDevice; 1.109 + if (audioDevices[audioId]) 1.110 + allowedDevices.AppendElement(audioDevices[audioId]); 1.111 + 1.112 + let videoId = 0; 1.113 + if (inputs && inputs.videoDevice != undefined) 1.114 + videoId = inputs.videoDevice; 1.115 + if (videoDevices[videoId]) 1.116 + allowedDevices.AppendElement(videoDevices[videoId]); 1.117 + 1.118 + Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID); 1.119 + } 1.120 + }]; 1.121 + }, 1.122 + 1.123 + // Get a list of string names for devices. Ensures that none of the strings are blank 1.124 + _getList: function(aDevices, aType) { 1.125 + let defaultCount = 0; 1.126 + return aDevices.map(function(device) { 1.127 + // if this is a Camera input, convert the name to something readable 1.128 + let res = /Camera\ \d+,\ Facing (front|back)/.exec(device.name); 1.129 + if (res) 1.130 + return Strings.browser.GetStringFromName("getUserMedia." + aType + "." + res[1] + "Camera"); 1.131 + 1.132 + if (device.name.startsWith("&") && device.name.endsWith(";")) 1.133 + return Strings.browser.GetStringFromName(device.name.substring(1, device.name.length -1)); 1.134 + 1.135 + if (device.name.trim() == "") { 1.136 + defaultCount++; 1.137 + return Strings.browser.formatStringFromName("getUserMedia." + aType + ".default", [defaultCount], 1); 1.138 + } 1.139 + return device.name 1.140 + }, this); 1.141 + }, 1.142 + 1.143 + _addDevicesToOptions: function(aDevices, aType, aOptions, extraOptions) { 1.144 + if (aDevices.length) { 1.145 + 1.146 + // Filter out empty items from the list 1.147 + let list = this._getList(aDevices, aType); 1.148 + if (extraOptions) 1.149 + list = list.concat(extraOptions); 1.150 + 1.151 + if (list.length > 0) { 1.152 + aOptions.inputs.push({ 1.153 + id: aType, 1.154 + type: "menulist", 1.155 + label: Strings.browser.GetStringFromName("getUserMedia." + aType + ".prompt"), 1.156 + values: list 1.157 + }); 1.158 + 1.159 + } 1.160 + } 1.161 + }, 1.162 + 1.163 + prompt: function prompt(aContentWindow, aCallID, aAudioRequested, 1.164 + aVideoRequested, aDevices) { 1.165 + let audioDevices = []; 1.166 + let videoDevices = []; 1.167 + for (let device of aDevices) { 1.168 + device = device.QueryInterface(Ci.nsIMediaDevice); 1.169 + switch (device.type) { 1.170 + case "audio": 1.171 + if (aAudioRequested) 1.172 + audioDevices.push(device); 1.173 + break; 1.174 + case "video": 1.175 + if (aVideoRequested) 1.176 + videoDevices.push(device); 1.177 + break; 1.178 + } 1.179 + } 1.180 + 1.181 + let requestType; 1.182 + if (audioDevices.length && videoDevices.length) 1.183 + requestType = "CameraAndMicrophone"; 1.184 + else if (audioDevices.length) 1.185 + requestType = "Microphone"; 1.186 + else if (videoDevices.length) 1.187 + requestType = "Camera"; 1.188 + else 1.189 + return; 1.190 + 1.191 + let host = aContentWindow.document.documentURIObject.host; 1.192 + let requestor = BrowserApp.manifest ? "'" + BrowserApp.manifest.name + "'" : host; 1.193 + let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1); 1.194 + 1.195 + let options = { inputs: [] }; 1.196 + // if the users only option would be to select "No Audio" or "No Video" 1.197 + // i.e. we're only showing audio or only video and there is only one device for that type 1.198 + // don't bother showing a menulist to select from 1.199 + var extraItems = null; 1.200 + if (videoDevices.length > 1 || audioDevices.length > 0) { 1.201 + // Only show the No Video option if there are also Audio devices to choose from 1.202 + if (audioDevices.length > 0) 1.203 + extraItems = [ Strings.browser.GetStringFromName("getUserMedia.videoDevice.none") ]; 1.204 + this._addDevicesToOptions(videoDevices, "videoDevice", options, extraItems); 1.205 + } 1.206 + 1.207 + if (audioDevices.length > 1 || videoDevices.length > 0) { 1.208 + // Only show the No Audio option if there are also Video devices to choose from 1.209 + if (videoDevices.length > 0) 1.210 + extraItems = [ Strings.browser.GetStringFromName("getUserMedia.audioDevice.none") ]; 1.211 + this._addDevicesToOptions(audioDevices, "audioDevice", options, extraItems); 1.212 + } 1.213 + 1.214 + let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID); 1.215 + 1.216 + NativeWindow.doorhanger.show(message, "webrtc-request", buttons, BrowserApp.selectedTab.id, options); 1.217 + } 1.218 +}