bug1913599-shim-createencodedstreams.js (3625B)
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/. */ 4 5 "use strict"; 6 7 /** 8 * Bug 1913599 - Sites that depend on legacy createEncodedStreams() 9 * 10 * Several websites that offer end-to-end encrypted communication in 11 * Chrome fail to work in Firefox, either ghosting the button that 12 * offers this feature or erroring with a message like "Voice/Video 13 * calling is not supported on this browser". 14 * 15 * These webpages rely on the older Chrome-only createEncodedStreams() 16 * API instead of the standard RTCRtpScriptTransform API now available 17 * in all browsers. The following shims the former using the latter. 18 * 19 * Note: this shim has inherent performance limitations being on 20 * main thread. Websites are encouraged to upgrade to the standard 21 * worker-based API directly for optimal performance in Firefox. 22 */ 23 24 /* globals exportFunction, cloneInto */ 25 26 console.info( 27 "createEncodedStreams() is being shimmed for compatibility reasons. Please consider updating to the RTCRtpScriptTransform API for optimal performance! See https://bugzil.la/1913599 for details." 28 ); 29 30 const win = window.wrappedJSObject; 31 if (!win.RTCRtpSender.prototype.createEncodedStreams) { 32 win.RTCRtpSender.prototype.createEncodedStreams = 33 win.RTCRtpReceiver.prototype.createEncodedStreams = exportFunction( 34 function createEncodedStreams() { 35 let onrtctransform; // appease linter 36 function work() { 37 const originals = []; 38 onrtctransform = async ({ transformer: { readable, writable } }) => { 39 const diverter = new TransformStream({ 40 transform: (original, controller) => { 41 originals.push(original); 42 controller.enqueue(original); 43 }, 44 }); 45 const reinserter = new TransformStream({ 46 transform: (frame, controller) => { 47 const original = originals.shift(); 48 original.data = frame.data; 49 controller.enqueue(original); 50 }, 51 }); 52 self.postMessage( 53 { readable: diverter.readable, writable: reinserter.writable }, 54 { transfer: [diverter.readable, reinserter.writable] } 55 ); 56 await readable 57 .pipeThrough({ 58 writable: diverter.writable, 59 readable: reinserter.readable, 60 }) 61 .pipeTo(writable); 62 }; 63 } 64 this._worker = new Worker( 65 `data:text/javascript,(${work.toString()})()` 66 ); 67 this.transform = new window.RTCRtpScriptTransform(this._worker); 68 this._dummy = onrtctransform; // appease linter 69 const readableNow = new TransformStream(); 70 const writableNow = new TransformStream(); 71 const haveData = new Promise( 72 r => (this._worker.onmessage = e => r(e.data)) 73 ); 74 haveData 75 .then(({ readable }) => readable.pipeTo(readableNow.writable)) 76 .catch(e => readableNow.writable.abort(e)); 77 haveData 78 .then(({ writable }) => writableNow.readable.pipeTo(writable)) 79 .catch(e => writableNow.readable.cancel(e)); 80 81 const result = new win.Object(); 82 result.readable = cloneInto(readableNow.readable, window, { 83 wrapReflectors: true, 84 }); 85 result.writable = cloneInto(writableNow.writable, window, { 86 wrapReflectors: true, 87 }); 88 return result; 89 }, 90 window 91 ); 92 }