瀏覽代碼

feat(e2ee) add support for WebRTC Encoded Transform

An alternative to Insertable Streams, currently implemented in Safarii / WebKit.

https://w3c.github.io/webrtc-encoded-transform/

Fixes: https://github.com/jitsi/jitsi-meet/issues/9585
dev1
Saúl Ibarra Corretgé 4 年之前
父節點
當前提交
61c977f70a
共有 4 個檔案被更改,包括 99 行新增46 行删除
  1. 13
    0
      modules/browser/BrowserCapabilities.js
  2. 35
    17
      modules/e2ee/E2EEContext.js
  3. 4
    3
      modules/e2ee/E2EEncryption.js
  4. 47
    26
      modules/e2ee/Worker.js

+ 13
- 0
modules/browser/BrowserCapabilities.js 查看文件

235
                     !== 'undefined');
235
                     !== 'undefined');
236
     }
236
     }
237
 
237
 
238
+    /**
239
+     * Checks if the browser supports WebRTC Encoded Transform, an alternative
240
+     * to insertable streams.
241
+     *
242
+     * NOTE: At the time of this writing the only browser supporting this is
243
+     * Safari / WebKit, behind a flag.
244
+     *
245
+     * @returns {boolean} {@code true} if the browser supports it.
246
+     */
247
+    supportsEncodedTransform() {
248
+        return Boolean(window.RTCRtpScriptTransform);
249
+    }
250
+
238
     /**
251
     /**
239
      * Checks if the browser supports insertable streams, needed for E2EE.
252
      * Checks if the browser supports insertable streams, needed for E2EE.
240
      * @returns {boolean} {@code true} if the browser supports insertable streams.
253
      * @returns {boolean} {@code true} if the browser supports insertable streams.

+ 35
- 17
modules/e2ee/E2EEContext.js 查看文件

1
-/* global __filename */
1
+/* global __filename, RTCRtpScriptTransform */
2
 
2
 
3
 import { getLogger } from 'jitsi-meet-logger';
3
 import { getLogger } from 'jitsi-meet-logger';
4
 
4
 
74
         }
74
         }
75
         receiver[kJitsiE2EE] = true;
75
         receiver[kJitsiE2EE] = true;
76
 
76
 
77
-        const receiverStreams = receiver.createEncodedStreams();
78
-
79
-        this._worker.postMessage({
80
-            operation: 'decode',
81
-            readableStream: receiverStreams.readable,
82
-            writableStream: receiverStreams.writable,
83
-            participantId
84
-        }, [ receiverStreams.readable, receiverStreams.writable ]);
77
+        if (window.RTCRtpScriptTransform) {
78
+            const options = {
79
+                operation: 'decode',
80
+                participantId
81
+            };
82
+
83
+            receiver.transform = new RTCRtpScriptTransform(this._worker, options);
84
+        } else {
85
+            const receiverStreams = receiver.createEncodedStreams();
86
+
87
+            this._worker.postMessage({
88
+                operation: 'decode',
89
+                readableStream: receiverStreams.readable,
90
+                writableStream: receiverStreams.writable,
91
+                participantId
92
+            }, [ receiverStreams.readable, receiverStreams.writable ]);
93
+        }
85
     }
94
     }
86
 
95
 
87
     /**
96
     /**
98
         }
107
         }
99
         sender[kJitsiE2EE] = true;
108
         sender[kJitsiE2EE] = true;
100
 
109
 
101
-        const senderStreams = sender.createEncodedStreams();
102
-
103
-        this._worker.postMessage({
104
-            operation: 'encode',
105
-            readableStream: senderStreams.readable,
106
-            writableStream: senderStreams.writable,
107
-            participantId
108
-        }, [ senderStreams.readable, senderStreams.writable ]);
110
+        if (window.RTCRtpScriptTransform) {
111
+            const options = {
112
+                operation: 'encode',
113
+                participantId
114
+            };
115
+
116
+            sender.transform = new RTCRtpScriptTransform(this._worker, options);
117
+        } else {
118
+            const senderStreams = sender.createEncodedStreams();
119
+
120
+            this._worker.postMessage({
121
+                operation: 'encode',
122
+                readableStream: senderStreams.readable,
123
+                writableStream: senderStreams.writable,
124
+                participantId
125
+            }, [ senderStreams.readable, senderStreams.writable ]);
126
+        }
109
     }
127
     }
110
 
128
 
111
     /**
129
     /**

+ 4
- 3
modules/e2ee/E2EEncryption.js 查看文件

96
      * @returns {boolean}
96
      * @returns {boolean}
97
      */
97
      */
98
     static isSupported(config) {
98
     static isSupported(config) {
99
-        return browser.supportsInsertableStreams()
100
-            && OlmAdapter.isSupported()
101
-            && !(config.testing && config.testing.disableE2EE);
99
+        return !(config.testing && config.testing.disableE2EE)
100
+            && (browser.supportsInsertableStreams()
101
+                || (config.enableEncodedTransformSupport && browser.supportsEncodedTransform()))
102
+            && OlmAdapter.isSupported();
102
     }
103
     }
103
 
104
 
104
     /**
105
     /**

+ 47
- 26
modules/e2ee/Worker.js 查看文件

7
 
7
 
8
 const contexts = new Map(); // Map participant id => context
8
 const contexts = new Map(); // Map participant id => context
9
 
9
 
10
-onmessage = async event => {
11
-    const { operation } = event.data;
10
+/**
11
+ * Retrieves the participant {@code Context}, creating it if necessary.
12
+ *
13
+ * @param {string} participantId - The participant whose context we need.
14
+ * @returns {Object} The context.
15
+ */
16
+function getParticipantContext(participantId) {
17
+    if (!contexts.has(participantId)) {
18
+        contexts.set(participantId, new Context(participantId));
19
+    }
12
 
20
 
13
-    if (operation === 'encode') {
14
-        const { readableStream, writableStream, participantId } = event.data;
21
+    return contexts.get(participantId);
22
+}
15
 
23
 
16
-        if (!contexts.has(participantId)) {
17
-            contexts.set(participantId, new Context(participantId));
18
-        }
19
-        const context = contexts.get(participantId);
24
+/**
25
+ * Sets an encode / decode transform.
26
+ *
27
+ * @param {Object} context - The participant context where the transform will be applied.
28
+ * @param {string} operation - Encode / decode.
29
+ * @param {Object} readableStream - Readable stream part.
30
+ * @param {Object} writableStream - Writable stream part.
31
+ */
32
+function handleTransform(context, operation, readableStream, writableStream) {
33
+    if (operation === 'encode' || operation === 'decode') {
34
+        const transformFn = operation === 'encode' ? context.encodeFunction : context.decodeFunction;
20
         const transformStream = new TransformStream({
35
         const transformStream = new TransformStream({
21
-            transform: context.encodeFunction.bind(context)
36
+            transform: transformFn.bind(context)
22
         });
37
         });
23
 
38
 
24
         readableStream
39
         readableStream
25
             .pipeThrough(transformStream)
40
             .pipeThrough(transformStream)
26
             .pipeTo(writableStream);
41
             .pipeTo(writableStream);
27
-    } else if (operation === 'decode') {
28
-        const { readableStream, writableStream, participantId } = event.data;
42
+    } else {
43
+        console.error(`Invalid operation: ${operation}`);
44
+    }
45
+}
29
 
46
 
30
-        if (!contexts.has(participantId)) {
31
-            contexts.set(participantId, new Context(participantId));
32
-        }
33
-        const context = contexts.get(participantId);
34
-        const transformStream = new TransformStream({
35
-            transform: context.decodeFunction.bind(context)
36
-        });
47
+onmessage = async event => {
48
+    const { operation } = event.data;
37
 
49
 
38
-        readableStream
39
-            .pipeThrough(transformStream)
40
-            .pipeTo(writableStream);
50
+    if (operation === 'encode' || operation === 'decode') {
51
+        const { readableStream, writableStream, participantId } = event.data;
52
+        const context = getParticipantContext(participantId);
53
+
54
+        handleTransform(context, operation, readableStream, writableStream);
41
     } else if (operation === 'setKey') {
55
     } else if (operation === 'setKey') {
42
         const { participantId, key, keyIndex } = event.data;
56
         const { participantId, key, keyIndex } = event.data;
43
-
44
-        if (!contexts.has(participantId)) {
45
-            contexts.set(participantId, new Context(participantId));
46
-        }
47
-        const context = contexts.get(participantId);
57
+        const context = getParticipantContext(participantId);
48
 
58
 
49
         if (key) {
59
         if (key) {
50
             context.setKey(key, keyIndex);
60
             context.setKey(key, keyIndex);
59
         console.error('e2ee worker', operation);
69
         console.error('e2ee worker', operation);
60
     }
70
     }
61
 };
71
 };
72
+
73
+// Operations using RTCRtpScriptTransform.
74
+if (self.RTCTransformEvent) {
75
+    self.onrtctransform = event => {
76
+        const transformer = event.transformer;
77
+        const { operation, participantId } = transformer.options;
78
+        const context = getParticipantContext(participantId);
79
+
80
+        handleTransform(context, operation, transformer.readable, transformer.writable);
81
+    };
82
+}

Loading…
取消
儲存