commit d2c66790e1eb1254120756f33b7e0af3ed0769a8
parent c14352afe04ae145b13cf0d752beaed5db22f6a2
Author: Jan-Ivar Bruaroey <jib@mozilla.com>
Date: Fri, 31 Oct 2025 15:54:28 +0000
Bug 1913599 - Interventions for some websites relying on createEncodedStreams(). r=twisniewski,webcompat-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D268638
Diffstat:
2 files changed, 208 insertions(+), 0 deletions(-)
diff --git a/browser/extensions/webcompat/data/interventions.json b/browser/extensions/webcompat/data/interventions.json
@@ -5273,6 +5273,122 @@
}
]
},
+ "1913599": {
+ "label": "createEncodedStreams shim test-page",
+ "bugs": {
+ "1913599": {
+ "issue": "broken-meetings",
+ "matches": ["https://jan-ivar.github.io/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": ["all"],
+ "only_channels": ["nightly"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
+ "1896361": {
+ "label": "Meta Messenger",
+ "bugs": {
+ "1896361": {
+ "issue": "broken-meetings",
+ "matches": ["https://www.facebook.com/*", "https://www.messenger.com/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": ["all"],
+ "only_channels": ["nightly"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
+ "1896424": {
+ "label": "meet.google.com legacy group calls (exploratory)",
+ "bugs": {
+ "1896424": {
+ "issue": "broken-meetings",
+ "matches": ["https://meet.google.com/calling/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": [],
+ "only_channels": ["nightly"],
+ "not_platforms": ["android"],
+ "ua_string": ["Chrome_with_FxQuantum"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
+ "1902507": {
+ "label": "riverside.fm",
+ "bugs": {
+ "1902507": {
+ "issue": "broken-meetings",
+ "matches": ["https://riverside.fm/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": ["all"],
+ "only_channels": ["nightly"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
+ "1902508": {
+ "label": "goto.com",
+ "bugs": {
+ "1902508": {
+ "issue": "broken-meetings",
+ "matches": ["https://*.goto.com/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": ["all"],
+ "only_channels": ["nightly"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
+ "1904141": {
+ "label": "mega.nz",
+ "bugs": {
+ "1904141": {
+ "issue": "broken-meetings",
+ "matches": ["https://mega.nz/*"]
+ }
+ },
+ "interventions": [
+ {
+ "platforms": ["all"],
+ "only_channels": ["nightly"],
+ "content_scripts": {
+ "all_frames": true,
+ "js": ["bug1913599-shim-createencodedstreams.js"]
+ }
+ }
+ ]
+ },
"1973019": {
"label": "mitsukoshi.mistore.jp",
"bugs": {
diff --git a/browser/extensions/webcompat/injections/js/bug1913599-shim-createencodedstreams.js b/browser/extensions/webcompat/injections/js/bug1913599-shim-createencodedstreams.js
@@ -0,0 +1,92 @@
+/* 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";
+
+/**
+ * Bug 1913599 - Sites that depend on legacy createEncodedStreams()
+ *
+ * Several websites that offer end-to-end encrypted communication in
+ * Chrome fail to work in Firefox, either ghosting the button that
+ * offers this feature or erroring with a message like "Voice/Video
+ * calling is not supported on this browser".
+ *
+ * These webpages rely on the older Chrome-only createEncodedStreams()
+ * API instead of the standard RTCRtpScriptTransform API now available
+ * in all browsers. The following shims the former using the latter.
+ *
+ * Note: this shim has inherent performance limitations being on
+ * main thread. Websites are encouraged to upgrade to the standard
+ * worker-based API directly for optimal performance in Firefox.
+ */
+
+/* globals exportFunction, cloneInto */
+
+console.info(
+ "createEncodedStreams() is being shimmed for compatibility reasons. Please consider updating to the RTCRtpScriptTransform API for optimal performance! See https://bugzil.la/1913599 for details."
+);
+
+const win = window.wrappedJSObject;
+if (!win.RTCRtpSender.prototype.createEncodedStreams) {
+ win.RTCRtpSender.prototype.createEncodedStreams =
+ win.RTCRtpReceiver.prototype.createEncodedStreams = exportFunction(
+ function createEncodedStreams() {
+ let onrtctransform; // appease linter
+ function work() {
+ const originals = [];
+ onrtctransform = async ({ transformer: { readable, writable } }) => {
+ const diverter = new TransformStream({
+ transform: (original, controller) => {
+ originals.push(original);
+ controller.enqueue(original);
+ },
+ });
+ const reinserter = new TransformStream({
+ transform: (frame, controller) => {
+ const original = originals.shift();
+ original.data = frame.data;
+ controller.enqueue(original);
+ },
+ });
+ self.postMessage(
+ { readable: diverter.readable, writable: reinserter.writable },
+ { transfer: [diverter.readable, reinserter.writable] }
+ );
+ await readable
+ .pipeThrough({
+ writable: diverter.writable,
+ readable: reinserter.readable,
+ })
+ .pipeTo(writable);
+ };
+ }
+ this._worker = new Worker(
+ `data:text/javascript,(${work.toString()})()`
+ );
+ this.transform = new window.RTCRtpScriptTransform(this._worker);
+ this._dummy = onrtctransform; // appease linter
+ const readableNow = new TransformStream();
+ const writableNow = new TransformStream();
+ const haveData = new Promise(
+ r => (this._worker.onmessage = e => r(e.data))
+ );
+ haveData
+ .then(({ readable }) => readable.pipeTo(readableNow.writable))
+ .catch(e => readableNow.writable.abort(e));
+ haveData
+ .then(({ writable }) => writableNow.readable.pipeTo(writable))
+ .catch(e => writableNow.readable.cancel(e));
+
+ const result = new win.Object();
+ result.readable = cloneInto(readableNow.readable, window, {
+ wrapReflectors: true,
+ });
+ result.writable = cloneInto(writableNow.writable, window, {
+ wrapReflectors: true,
+ });
+ return result;
+ },
+ window
+ );
+}