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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 import { GeckoViewUtils } from "resource://gre/modules/GeckoViewUtils.sys.mjs";
6 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
10 XPCOMUtils.defineLazyServiceGetter(
12 "MediaManagerService",
13 "@mozilla.org/mediaManagerService;1",
14 "nsIMediaManagerService"
17 const STATUS_RECORDING = "recording";
18 const STATUS_INACTIVE = "inactive";
19 const TYPE_CAMERA = "camera";
20 const TYPE_MICROPHONE = "microphone";
22 export class GeckoViewPermissionProcessChild extends JSProcessActorChild {
24 return window.windowGlobalChild.getActor("GeckoViewPermission");
27 /* ---------- nsIObserver ---------- */
28 async observe(aSubject, aTopic, aData) {
30 case "getUserMedia:ask-device-permission": {
31 await this.sendQuery("AskDevicePermission", aData);
32 Services.obs.notifyObservers(
34 "getUserMedia:got-device-permission"
38 case "getUserMedia:request": {
39 const { callID } = aSubject;
40 const allowedDevices = await this.handleMediaRequest(aSubject);
41 Services.obs.notifyObservers(
44 ? "getUserMedia:response:allow"
45 : "getUserMedia:response:deny",
50 case "PeerConnection:request": {
51 Services.obs.notifyObservers(
53 "PeerConnection:response:allow",
58 case "recording-device-events": {
59 this.handleRecordingDeviceEvents(aSubject);
65 handleRecordingDeviceEvents(aRequest) {
66 aRequest.QueryInterface(Ci.nsIPropertyBag2);
67 const contentWindow = aRequest.getProperty("window");
70 const getStatusString = function (activityStatus) {
71 switch (activityStatus) {
72 case lazy.MediaManagerService.STATE_CAPTURE_ENABLED:
73 case lazy.MediaManagerService.STATE_CAPTURE_DISABLED:
74 return STATUS_RECORDING;
75 case lazy.MediaManagerService.STATE_NOCAPTURE:
76 return STATUS_INACTIVE;
78 throw new Error("Unexpected activityStatus value");
83 const hasMicrophone = {};
87 const mediaDevices = {};
88 lazy.MediaManagerService.mediaCaptureWindowState(
97 var cameraStatus = getStatusString(hasCamera.value);
98 var microphoneStatus = getStatusString(hasMicrophone.value);
99 if (hasCamera.value != lazy.MediaManagerService.STATE_NOCAPTURE) {
102 status: cameraStatus,
105 if (hasMicrophone.value != lazy.MediaManagerService.STATE_NOCAPTURE) {
107 type: TYPE_MICROPHONE,
108 status: microphoneStatus,
111 this.getActor(contentWindow).mediaRecordingStatusChanged(devices);
114 async handleMediaRequest(aRequest) {
115 const constraints = aRequest.getConstraints();
116 const { devices, windowID } = aRequest;
117 const window = Services.wm.getOuterWindowWithId(windowID);
122 // Release the request first
123 aRequest = undefined;
125 const sources = devices.map(device => {
126 device = device.QueryInterface(Ci.nsIMediaDevice);
131 name: device.rawName, // unfiltered device name to show to the user
132 mediaSource: device.mediaSource,
138 !sources.some(source => source.type === "videoinput")
140 console.error("Media device error: no video source");
144 !sources.some(source => source.type === "audioinput")
146 console.error("Media device error: no audio source");
150 const response = await this.getActor(window).getMediaPermission({
151 uri: window.document.documentURI,
152 video: constraints.video
153 ? sources.filter(source => source.type === "videoinput")
155 audio: constraints.audio
156 ? sources.filter(source => source.type === "audioinput")
165 const allowedDevices = Cc["@mozilla.org/array;1"].createInstance(
168 if (constraints.video) {
169 const video = devices.find(device => response.video === device.rawId);
171 console.error("Media device error: invalid video id");
174 await this.getActor(window).addCameraPermission();
175 allowedDevices.appendElement(video);
177 if (constraints.audio) {
178 const audio = devices.find(device => response.audio === device.rawId);
180 console.error("Media device error: invalid audio id");
183 allowedDevices.appendElement(audio);
185 return allowedDevices;
189 const { debug, warn } = GeckoViewUtils.initLogging(
190 "GeckoViewPermissionProcessChild"