mobile/android/chrome/content/WebrtcUI.js

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:2b6592753f22
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 "use strict";
5
6 XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm");
7
8 var WebrtcUI = {
9 _notificationId: null,
10
11 observe: function(aSubject, aTopic, aData) {
12 if (aTopic === "getUserMedia:request") {
13 this.handleRequest(aSubject, aTopic, aData);
14 } else if (aTopic === "recording-device-events") {
15 switch (aData) {
16 case "shutdown":
17 case "starting":
18 this.notify();
19 break;
20 }
21 }
22 },
23
24 notify: function() {
25 let windows = MediaManagerService.activeMediaCaptureWindows;
26 let count = windows.Count();
27 let msg = {};
28 if (count == 0) {
29 if (this._notificationId) {
30 Notifications.cancel(this._notificationId);
31 this._notificationId = null;
32 }
33 } else {
34 let notificationOptions = {
35 title: Strings.brand.GetStringFromName("brandShortName"),
36 when: null, // hide the date row
37 light: [0xFF9500FF, 1000, 1000],
38 ongoing: true
39 };
40
41 let cameraActive = false;
42 let audioActive = false;
43 for (let i = 0; i < count; i++) {
44 let win = windows.GetElementAt(i);
45 let hasAudio = {};
46 let hasVideo = {};
47 MediaManagerService.mediaCaptureWindowState(win, hasVideo, hasAudio);
48 if (hasVideo.value) cameraActive = true;
49 if (hasAudio.value) audioActive = true;
50 }
51
52 if (cameraActive && audioActive) {
53 notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCameraAndMicrophone.message2");
54 notificationOptions.icon = "drawable:alert_mic_camera";
55 } else if (cameraActive) {
56 notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCamera.message2");
57 notificationOptions.icon = "drawable:alert_camera";
58 } else if (audioActive) {
59 notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingMicrophone.message2");
60 notificationOptions.icon = "drawable:alert_mic";
61 } else {
62 // somethings wrong. lets throw
63 throw "Couldn't find any cameras or microphones being used"
64 }
65
66 if (this._notificationId)
67 Notifications.update(this._notificationId, notificationOptions);
68 else
69 this._notificationId = Notifications.create(notificationOptions);
70 if (count > 1)
71 msg.count = count;
72 }
73 },
74
75 handleRequest: function handleRequest(aSubject, aTopic, aData) {
76 let constraints = aSubject.getConstraints();
77 let contentWindow = Services.wm.getOuterWindowWithId(aSubject.windowID);
78
79 contentWindow.navigator.mozGetUserMediaDevices(
80 constraints,
81 function (devices) {
82 WebrtcUI.prompt(contentWindow, aSubject.callID, constraints.audio,
83 constraints.video, devices);
84 },
85 function (error) {
86 Cu.reportError(error);
87 },
88 aSubject.innerWindowID);
89 },
90
91 getDeviceButtons: function(audioDevices, videoDevices, aCallID) {
92 return [{
93 label: Strings.browser.GetStringFromName("getUserMedia.denyRequest.label"),
94 callback: function() {
95 Services.obs.notifyObservers(null, "getUserMedia:response:deny", aCallID);
96 }
97 },
98 {
99 label: Strings.browser.GetStringFromName("getUserMedia.shareRequest.label"),
100 callback: function(checked /* ignored */, inputs) {
101 let allowedDevices = Cc["@mozilla.org/supports-array;1"].createInstance(Ci.nsISupportsArray);
102
103 let audioId = 0;
104 if (inputs && inputs.audioDevice != undefined)
105 audioId = inputs.audioDevice;
106 if (audioDevices[audioId])
107 allowedDevices.AppendElement(audioDevices[audioId]);
108
109 let videoId = 0;
110 if (inputs && inputs.videoDevice != undefined)
111 videoId = inputs.videoDevice;
112 if (videoDevices[videoId])
113 allowedDevices.AppendElement(videoDevices[videoId]);
114
115 Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
116 }
117 }];
118 },
119
120 // Get a list of string names for devices. Ensures that none of the strings are blank
121 _getList: function(aDevices, aType) {
122 let defaultCount = 0;
123 return aDevices.map(function(device) {
124 // if this is a Camera input, convert the name to something readable
125 let res = /Camera\ \d+,\ Facing (front|back)/.exec(device.name);
126 if (res)
127 return Strings.browser.GetStringFromName("getUserMedia." + aType + "." + res[1] + "Camera");
128
129 if (device.name.startsWith("&") && device.name.endsWith(";"))
130 return Strings.browser.GetStringFromName(device.name.substring(1, device.name.length -1));
131
132 if (device.name.trim() == "") {
133 defaultCount++;
134 return Strings.browser.formatStringFromName("getUserMedia." + aType + ".default", [defaultCount], 1);
135 }
136 return device.name
137 }, this);
138 },
139
140 _addDevicesToOptions: function(aDevices, aType, aOptions, extraOptions) {
141 if (aDevices.length) {
142
143 // Filter out empty items from the list
144 let list = this._getList(aDevices, aType);
145 if (extraOptions)
146 list = list.concat(extraOptions);
147
148 if (list.length > 0) {
149 aOptions.inputs.push({
150 id: aType,
151 type: "menulist",
152 label: Strings.browser.GetStringFromName("getUserMedia." + aType + ".prompt"),
153 values: list
154 });
155
156 }
157 }
158 },
159
160 prompt: function prompt(aContentWindow, aCallID, aAudioRequested,
161 aVideoRequested, aDevices) {
162 let audioDevices = [];
163 let videoDevices = [];
164 for (let device of aDevices) {
165 device = device.QueryInterface(Ci.nsIMediaDevice);
166 switch (device.type) {
167 case "audio":
168 if (aAudioRequested)
169 audioDevices.push(device);
170 break;
171 case "video":
172 if (aVideoRequested)
173 videoDevices.push(device);
174 break;
175 }
176 }
177
178 let requestType;
179 if (audioDevices.length && videoDevices.length)
180 requestType = "CameraAndMicrophone";
181 else if (audioDevices.length)
182 requestType = "Microphone";
183 else if (videoDevices.length)
184 requestType = "Camera";
185 else
186 return;
187
188 let host = aContentWindow.document.documentURIObject.host;
189 let requestor = BrowserApp.manifest ? "'" + BrowserApp.manifest.name + "'" : host;
190 let message = Strings.browser.formatStringFromName("getUserMedia.share" + requestType + ".message", [ requestor ], 1);
191
192 let options = { inputs: [] };
193 // if the users only option would be to select "No Audio" or "No Video"
194 // i.e. we're only showing audio or only video and there is only one device for that type
195 // don't bother showing a menulist to select from
196 var extraItems = null;
197 if (videoDevices.length > 1 || audioDevices.length > 0) {
198 // Only show the No Video option if there are also Audio devices to choose from
199 if (audioDevices.length > 0)
200 extraItems = [ Strings.browser.GetStringFromName("getUserMedia.videoDevice.none") ];
201 this._addDevicesToOptions(videoDevices, "videoDevice", options, extraItems);
202 }
203
204 if (audioDevices.length > 1 || videoDevices.length > 0) {
205 // Only show the No Audio option if there are also Video devices to choose from
206 if (videoDevices.length > 0)
207 extraItems = [ Strings.browser.GetStringFromName("getUserMedia.audioDevice.none") ];
208 this._addDevicesToOptions(audioDevices, "audioDevice", options, extraItems);
209 }
210
211 let buttons = this.getDeviceButtons(audioDevices, videoDevices, aCallID);
212
213 NativeWindow.doorhanger.show(message, "webrtc-request", buttons, BrowserApp.selectedTab.id, options);
214 }
215 }

mercurial