From 9e3c08db40b8916968b9f30096c7be3f00ce9647 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:44:51 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../actors/GeckoViewPermissionProcessChild.sys.mjs | 191 +++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 mobile/android/actors/GeckoViewPermissionProcessChild.sys.mjs (limited to 'mobile/android/actors/GeckoViewPermissionProcessChild.sys.mjs') diff --git a/mobile/android/actors/GeckoViewPermissionProcessChild.sys.mjs b/mobile/android/actors/GeckoViewPermissionProcessChild.sys.mjs new file mode 100644 index 0000000000..2c9d271bbd --- /dev/null +++ b/mobile/android/actors/GeckoViewPermissionProcessChild.sys.mjs @@ -0,0 +1,191 @@ +/* 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/. */ + +import { GeckoViewUtils } from "resource://gre/modules/GeckoViewUtils.sys.mjs"; +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +const lazy = {}; + +XPCOMUtils.defineLazyServiceGetter( + lazy, + "MediaManagerService", + "@mozilla.org/mediaManagerService;1", + "nsIMediaManagerService" +); + +const STATUS_RECORDING = "recording"; +const STATUS_INACTIVE = "inactive"; +const TYPE_CAMERA = "camera"; +const TYPE_MICROPHONE = "microphone"; + +export class GeckoViewPermissionProcessChild extends JSProcessActorChild { + getActor(window) { + return window.windowGlobalChild.getActor("GeckoViewPermission"); + } + + /* ---------- nsIObserver ---------- */ + async observe(aSubject, aTopic, aData) { + switch (aTopic) { + case "getUserMedia:ask-device-permission": { + await this.sendQuery("AskDevicePermission", aData); + Services.obs.notifyObservers( + aSubject, + "getUserMedia:got-device-permission" + ); + break; + } + case "getUserMedia:request": { + const { callID } = aSubject; + const allowedDevices = await this.handleMediaRequest(aSubject); + Services.obs.notifyObservers( + allowedDevices, + allowedDevices + ? "getUserMedia:response:allow" + : "getUserMedia:response:deny", + callID + ); + break; + } + case "PeerConnection:request": { + Services.obs.notifyObservers( + null, + "PeerConnection:response:allow", + aSubject.callID + ); + break; + } + case "recording-device-events": { + this.handleRecordingDeviceEvents(aSubject); + break; + } + } + } + + handleRecordingDeviceEvents(aRequest) { + aRequest.QueryInterface(Ci.nsIPropertyBag2); + const contentWindow = aRequest.getProperty("window"); + const devices = []; + + const getStatusString = function (activityStatus) { + switch (activityStatus) { + case lazy.MediaManagerService.STATE_CAPTURE_ENABLED: + case lazy.MediaManagerService.STATE_CAPTURE_DISABLED: + return STATUS_RECORDING; + case lazy.MediaManagerService.STATE_NOCAPTURE: + return STATUS_INACTIVE; + default: + throw new Error("Unexpected activityStatus value"); + } + }; + + const hasCamera = {}; + const hasMicrophone = {}; + const screen = {}; + const window = {}; + const browser = {}; + const mediaDevices = {}; + lazy.MediaManagerService.mediaCaptureWindowState( + contentWindow, + hasCamera, + hasMicrophone, + screen, + window, + browser, + mediaDevices + ); + var cameraStatus = getStatusString(hasCamera.value); + var microphoneStatus = getStatusString(hasMicrophone.value); + if (hasCamera.value != lazy.MediaManagerService.STATE_NOCAPTURE) { + devices.push({ + type: TYPE_CAMERA, + status: cameraStatus, + }); + } + if (hasMicrophone.value != lazy.MediaManagerService.STATE_NOCAPTURE) { + devices.push({ + type: TYPE_MICROPHONE, + status: microphoneStatus, + }); + } + this.getActor(contentWindow).mediaRecordingStatusChanged(devices); + } + + async handleMediaRequest(aRequest) { + const constraints = aRequest.getConstraints(); + const { devices, windowID } = aRequest; + const window = Services.wm.getOuterWindowWithId(windowID); + if (window.closed) { + return null; + } + + // Release the request first + aRequest = undefined; + + const sources = devices.map(device => { + device = device.QueryInterface(Ci.nsIMediaDevice); + return { + type: device.type, + id: device.rawId, + rawId: device.rawId, + name: device.rawName, // unfiltered device name to show to the user + mediaSource: device.mediaSource, + }; + }); + + if ( + constraints.video && + !sources.some(source => source.type === "videoinput") + ) { + console.error("Media device error: no video source"); + return null; + } else if ( + constraints.audio && + !sources.some(source => source.type === "audioinput") + ) { + console.error("Media device error: no audio source"); + return null; + } + + const response = await this.getActor(window).getMediaPermission({ + uri: window.document.documentURI, + video: constraints.video + ? sources.filter(source => source.type === "videoinput") + : null, + audio: constraints.audio + ? sources.filter(source => source.type === "audioinput") + : null, + }); + + if (!response) { + // Rejected. + return null; + } + + const allowedDevices = Cc["@mozilla.org/array;1"].createInstance( + Ci.nsIMutableArray + ); + if (constraints.video) { + const video = devices.find(device => response.video === device.rawId); + if (!video) { + console.error("Media device error: invalid video id"); + return null; + } + await this.getActor(window).addCameraPermission(); + allowedDevices.appendElement(video); + } + if (constraints.audio) { + const audio = devices.find(device => response.audio === device.rawId); + if (!audio) { + console.error("Media device error: invalid audio id"); + return null; + } + allowedDevices.appendElement(audio); + } + return allowedDevices; + } +} + +const { debug, warn } = GeckoViewUtils.initLogging( + "GeckoViewPermissionProcessChild" +); -- cgit v1.2.3