livekit-client 2.18.9 → 2.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +5609 -644
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +3553 -2813
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.pt.worker.js +2 -0
- package/dist/livekit-client.pt.worker.js.map +1 -0
- package/dist/livekit-client.pt.worker.mjs +5834 -0
- package/dist/livekit-client.pt.worker.mjs.map +1 -0
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +2 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +8 -7
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +35 -8
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +5 -5
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts +5 -5
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +21 -4
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/sifPayload.d.ts +7 -7
- package/dist/src/e2ee/worker/sifPayload.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/options.d.ts +7 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/packetTrailer/PacketTrailerManager.d.ts +49 -0
- package/dist/src/packetTrailer/PacketTrailerManager.d.ts.map +1 -0
- package/dist/src/packetTrailer/packetTrailer.d.ts +32 -0
- package/dist/src/packetTrailer/packetTrailer.d.ts.map +1 -0
- package/dist/src/packetTrailer/types.d.ts +57 -0
- package/dist/src/packetTrailer/types.d.ts.map +1 -0
- package/dist/src/packetTrailer/utils.d.ts +9 -0
- package/dist/src/packetTrailer/utils.d.ts.map +1 -0
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts +2 -0
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts.map +1 -0
- package/dist/src/room/RTCEngine.d.ts +2 -4
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +7 -3
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +12 -4
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +3 -3
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +3 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts +4 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +2 -2
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/index.d.ts +5 -5
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -1
- package/dist/src/room/data-track/types.d.ts +7 -0
- package/dist/src/room/data-track/types.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +2 -2
- package/dist/src/room/participant/LocalParticipant.d.ts +8 -14
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -1
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +5 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/rpc/client/RpcClientManager.d.ts +39 -0
- package/dist/src/room/rpc/client/RpcClientManager.d.ts.map +1 -0
- package/dist/src/room/rpc/client/events.d.ts +8 -0
- package/dist/src/room/rpc/client/events.d.ts.map +1 -0
- package/dist/src/room/rpc/index.d.ts +6 -0
- package/dist/src/room/rpc/index.d.ts.map +1 -0
- package/dist/src/room/rpc/server/RpcServerManager.d.ts +44 -0
- package/dist/src/room/rpc/server/RpcServerManager.d.ts.map +1 -0
- package/dist/src/room/rpc/server/events.d.ts +8 -0
- package/dist/src/room/rpc/server/events.d.ts.map +1 -0
- package/dist/src/room/{rpc.d.ts → rpc/utils.d.ts} +34 -4
- package/dist/src/room/rpc/utils.d.ts.map +1 -0
- package/dist/src/room/track/PacketTrailerExtractor.d.ts +19 -0
- package/dist/src/room/track/PacketTrailerExtractor.d.ts.map +1 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts +16 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +10 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +4 -3
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/MockMediaStreamTrack.d.ts.map +1 -1
- package/dist/src/utils/dataPacketBuffer.d.ts +1 -1
- package/dist/src/utils/dataPacketBuffer.d.ts.map +1 -1
- package/dist/src/version.d.ts +9 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/ts4.2/api/SignalClient.d.ts +2 -1
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +8 -7
- package/dist/ts4.2/e2ee/types.d.ts +35 -8
- package/dist/ts4.2/e2ee/utils.d.ts +5 -5
- package/dist/ts4.2/e2ee/worker/DataCryptor.d.ts +5 -5
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +21 -4
- package/dist/ts4.2/e2ee/worker/naluUtils.d.ts +1 -1
- package/dist/ts4.2/e2ee/worker/sifPayload.d.ts +7 -7
- package/dist/ts4.2/index.d.ts +5 -1
- package/dist/ts4.2/options.d.ts +7 -0
- package/dist/ts4.2/packetTrailer/PacketTrailerManager.d.ts +49 -0
- package/dist/ts4.2/packetTrailer/packetTrailer.d.ts +32 -0
- package/dist/ts4.2/packetTrailer/types.d.ts +57 -0
- package/dist/ts4.2/packetTrailer/utils.d.ts +9 -0
- package/dist/ts4.2/packetTrailer/worker/packetTrailer.worker.d.ts +2 -0
- package/dist/ts4.2/room/RTCEngine.d.ts +2 -4
- package/dist/ts4.2/room/Room.d.ts +7 -3
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +5 -1
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +12 -4
- package/dist/ts4.2/room/data-track/frame.d.ts +3 -3
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +3 -1
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +4 -1
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +2 -2
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packet/index.d.ts +5 -5
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +1 -1
- package/dist/ts4.2/room/data-track/types.d.ts +7 -0
- package/dist/ts4.2/room/events.d.ts +2 -2
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +8 -14
- package/dist/ts4.2/room/participant/Participant.d.ts +1 -1
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +5 -1
- package/dist/ts4.2/room/rpc/client/RpcClientManager.d.ts +43 -0
- package/dist/ts4.2/room/rpc/client/events.d.ts +8 -0
- package/dist/ts4.2/room/rpc/index.d.ts +7 -0
- package/dist/ts4.2/room/rpc/server/RpcServerManager.d.ts +44 -0
- package/dist/ts4.2/room/rpc/server/events.d.ts +8 -0
- package/dist/ts4.2/room/{rpc.d.ts → rpc/utils.d.ts} +34 -4
- package/dist/ts4.2/room/track/PacketTrailerExtractor.d.ts +19 -0
- package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +16 -0
- package/dist/ts4.2/room/track/Track.d.ts +1 -1
- package/dist/ts4.2/room/track/options.d.ts +10 -0
- package/dist/ts4.2/room/utils.d.ts +4 -3
- package/dist/ts4.2/utils/dataPacketBuffer.d.ts +1 -1
- package/dist/ts4.2/version.d.ts +9 -1
- package/package.json +24 -16
- package/src/api/SignalClient.test.ts +102 -10
- package/src/api/SignalClient.ts +4 -2
- package/src/api/WebSocketStream.test.ts +0 -1
- package/src/e2ee/E2eeManager.ts +82 -30
- package/src/e2ee/types.ts +37 -8
- package/src/e2ee/utils.ts +7 -6
- package/src/e2ee/worker/DataCryptor.ts +6 -6
- package/src/e2ee/worker/FrameCryptor.test.ts +177 -4
- package/src/e2ee/worker/FrameCryptor.ts +94 -14
- package/src/e2ee/worker/ParticipantKeyHandler.test.ts +4 -4
- package/src/e2ee/worker/e2ee.worker.ts +13 -5
- package/src/e2ee/worker/naluUtils.ts +4 -4
- package/src/e2ee/worker/sifPayload.ts +10 -8
- package/src/index.ts +7 -0
- package/src/options.ts +8 -0
- package/src/packetTrailer/PacketTrailerManager.test.ts +172 -0
- package/src/packetTrailer/PacketTrailerManager.ts +250 -0
- package/src/packetTrailer/packetTrailer.test.ts +174 -0
- package/src/packetTrailer/packetTrailer.ts +276 -0
- package/src/packetTrailer/types.ts +75 -0
- package/src/packetTrailer/utils.test.ts +105 -0
- package/src/packetTrailer/utils.ts +50 -0
- package/src/packetTrailer/worker/packetTrailer.worker.ts +155 -0
- package/src/packetTrailer/worker/tsconfig.json +14 -0
- package/src/room/BackOffStrategy.test.ts +1 -1
- package/src/room/RTCEngine.test.ts +219 -0
- package/src/room/RTCEngine.ts +86 -46
- package/src/room/Room.test.ts +62 -1
- package/src/room/Room.ts +111 -86
- package/src/room/data-track/RemoteDataTrack.ts +8 -1
- package/src/room/data-track/depacketizer.test.ts +433 -1
- package/src/room/data-track/depacketizer.ts +79 -61
- package/src/room/data-track/frame.ts +2 -2
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +194 -0
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +21 -1
- package/src/room/data-track/incoming/pipeline.ts +13 -2
- package/src/room/data-track/outgoing/types.ts +3 -2
- package/src/room/data-track/packet/extensions.ts +2 -2
- package/src/room/data-track/packet/index.ts +6 -6
- package/src/room/data-track/packet/serializable.ts +1 -1
- package/src/room/data-track/types.ts +8 -0
- package/src/room/events.ts +2 -2
- package/src/room/participant/LocalParticipant.test.ts +81 -0
- package/src/room/participant/LocalParticipant.ts +64 -187
- package/src/room/participant/Participant.ts +1 -1
- package/src/room/participant/RemoteParticipant.ts +9 -0
- package/src/room/participant/publishUtils.ts +1 -1
- package/src/room/rpc/client/RpcClientManager.test.ts +430 -0
- package/src/room/rpc/client/RpcClientManager.ts +269 -0
- package/src/room/rpc/client/events.ts +9 -0
- package/src/room/rpc/index.ts +14 -0
- package/src/room/rpc/server/RpcServerManager.test.ts +471 -0
- package/src/room/rpc/server/RpcServerManager.ts +293 -0
- package/src/room/rpc/server/events.ts +9 -0
- package/src/room/{rpc.ts → rpc/utils.ts} +49 -8
- package/src/room/track/PacketTrailerExtractor.ts +43 -0
- package/src/room/track/RemoteVideoTrack.ts +23 -2
- package/src/room/track/Track.ts +1 -1
- package/src/room/track/create.ts +0 -4
- package/src/room/track/options.ts +11 -0
- package/src/room/track/record.ts +1 -1
- package/src/room/track/utils.ts +4 -1
- package/src/room/utils.test.ts +14 -1
- package/src/room/utils.ts +19 -4
- package/src/test/MockMediaStreamTrack.ts +0 -1
- package/src/type-polyfills/non-shared-typed-arrays.d.ts +6 -0
- package/src/utils/dataPacketBuffer.ts +1 -1
- package/src/version.ts +11 -1
- package/dist/src/room/rpc.d.ts.map +0 -1
- package/src/room/rpc.test.ts +0 -301
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { appendPacketTrailerToEncodedFrame, processPacketTrailer } from '../packetTrailer';
|
|
2
|
+
import type {
|
|
3
|
+
PTMetadataMessage,
|
|
4
|
+
PTScriptTransformOptions,
|
|
5
|
+
PTWorkerMessage,
|
|
6
|
+
PacketTrailerPublishOptions,
|
|
7
|
+
} from '../types';
|
|
8
|
+
import { hasPacketTrailerPublishOptions } from '../utils';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Holds the trackId currently associated with a pipeline. A mutable
|
|
12
|
+
* wrapper is used so the transform closure always reads the latest
|
|
13
|
+
* trackId after a receiver gets re-bound to a new track.
|
|
14
|
+
*/
|
|
15
|
+
interface PipelineState {
|
|
16
|
+
trackId: string;
|
|
17
|
+
hasPacketTrailer: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const pipelines = new Map<string, PipelineState>();
|
|
21
|
+
|
|
22
|
+
onmessage = (ev: MessageEvent<PTWorkerMessage>) => {
|
|
23
|
+
const msg = ev.data;
|
|
24
|
+
|
|
25
|
+
switch (msg.kind) {
|
|
26
|
+
case 'init':
|
|
27
|
+
postMessage({ kind: 'initAck' });
|
|
28
|
+
break;
|
|
29
|
+
|
|
30
|
+
case 'decode':
|
|
31
|
+
setupDecodeTransform(
|
|
32
|
+
msg.data.readableStream,
|
|
33
|
+
msg.data.writableStream,
|
|
34
|
+
msg.data.trackId,
|
|
35
|
+
msg.data.hasPacketTrailer,
|
|
36
|
+
);
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case 'encode':
|
|
40
|
+
setupEncodeTransform(
|
|
41
|
+
msg.data.readableStream,
|
|
42
|
+
msg.data.writableStream,
|
|
43
|
+
msg.data.packetTrailer,
|
|
44
|
+
);
|
|
45
|
+
break;
|
|
46
|
+
|
|
47
|
+
case 'updateTrackId':
|
|
48
|
+
updateTrackId(msg.data.oldTrackId, msg.data.newTrackId, msg.data.hasPacketTrailer);
|
|
49
|
+
break;
|
|
50
|
+
|
|
51
|
+
default:
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function setupDecodeTransform(
|
|
57
|
+
readable: ReadableStream,
|
|
58
|
+
writable: WritableStream,
|
|
59
|
+
trackId: string,
|
|
60
|
+
hasPacketTrailer: boolean,
|
|
61
|
+
) {
|
|
62
|
+
const state: PipelineState = { trackId, hasPacketTrailer };
|
|
63
|
+
pipelines.set(trackId, state);
|
|
64
|
+
|
|
65
|
+
const transform = new TransformStream({
|
|
66
|
+
transform(
|
|
67
|
+
frame: RTCEncodedVideoFrame,
|
|
68
|
+
controller: TransformStreamDefaultController<RTCEncodedVideoFrame>,
|
|
69
|
+
) {
|
|
70
|
+
try {
|
|
71
|
+
if (state.hasPacketTrailer) {
|
|
72
|
+
const result = processPacketTrailer(frame, state.trackId);
|
|
73
|
+
if (result.data) {
|
|
74
|
+
frame.data = result.data;
|
|
75
|
+
}
|
|
76
|
+
if (result.payload) {
|
|
77
|
+
const msg: PTMetadataMessage = { kind: 'metadata', data: result.payload };
|
|
78
|
+
postMessage(msg);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// Never drop frames on trailer-extraction failure — pass through so
|
|
83
|
+
// video keeps decoding even if metadata is lost for this frame.
|
|
84
|
+
}
|
|
85
|
+
controller.enqueue(frame);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
readable
|
|
90
|
+
.pipeThrough(transform)
|
|
91
|
+
.pipeTo(writable)
|
|
92
|
+
.catch(() => {
|
|
93
|
+
pipelines.delete(state.trackId);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function setupEncodeTransform(
|
|
98
|
+
readable: ReadableStream,
|
|
99
|
+
writable: WritableStream,
|
|
100
|
+
packetTrailer?: PacketTrailerPublishOptions,
|
|
101
|
+
) {
|
|
102
|
+
if (!hasPacketTrailerPublishOptions(packetTrailer)) {
|
|
103
|
+
readable.pipeTo(writable).catch(() => {});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let frameId = 0;
|
|
108
|
+
const transform = new TransformStream({
|
|
109
|
+
transform(
|
|
110
|
+
frame: RTCEncodedVideoFrame,
|
|
111
|
+
controller: TransformStreamDefaultController<RTCEncodedVideoFrame>,
|
|
112
|
+
) {
|
|
113
|
+
try {
|
|
114
|
+
if (packetTrailer?.frameId) {
|
|
115
|
+
frameId = frameId === 0xffffffff ? 1 : frameId + 1;
|
|
116
|
+
}
|
|
117
|
+
appendPacketTrailerToEncodedFrame(frame, packetTrailer, frameId);
|
|
118
|
+
} catch {
|
|
119
|
+
// Never drop frames on trailer-write failure.
|
|
120
|
+
}
|
|
121
|
+
controller.enqueue(frame);
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
readable
|
|
126
|
+
.pipeThrough(transform)
|
|
127
|
+
.pipeTo(writable)
|
|
128
|
+
.catch(() => {});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function updateTrackId(oldTrackId: string, newTrackId: string, hasPacketTrailer: boolean) {
|
|
132
|
+
const state = pipelines.get(oldTrackId);
|
|
133
|
+
if (state) {
|
|
134
|
+
state.trackId = newTrackId;
|
|
135
|
+
state.hasPacketTrailer = hasPacketTrailer;
|
|
136
|
+
pipelines.delete(oldTrackId);
|
|
137
|
+
pipelines.set(newTrackId, state);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Operations using RTCRtpScriptTransform.
|
|
142
|
+
// @ts-ignore
|
|
143
|
+
if (self.RTCTransformEvent) {
|
|
144
|
+
// @ts-ignore
|
|
145
|
+
self.onrtctransform = (event: RTCTransformEvent) => {
|
|
146
|
+
// @ts-ignore
|
|
147
|
+
const transformer = event.transformer;
|
|
148
|
+
const options = transformer.options as PTScriptTransformOptions;
|
|
149
|
+
if (options.kind === 'encode') {
|
|
150
|
+
setupEncodeTransform(transformer.readable, transformer.writable, options.packetTrailer);
|
|
151
|
+
} else {
|
|
152
|
+
setupDecodeTransform(transformer.readable, transformer.writable, options.trackId, true);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
@@ -6,7 +6,7 @@ vi.mock('./utils', async () => {
|
|
|
6
6
|
const actual = await vi.importActual('./utils');
|
|
7
7
|
return {
|
|
8
8
|
...actual,
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
sleep: vi.fn((ms: number) => Promise.resolve()),
|
|
11
11
|
extractProjectFromUrl: vi.fn((url: URL) => {
|
|
12
12
|
// @ts-ignore
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import RTCEngine from './RTCEngine';
|
|
3
|
+
import { roomOptionDefaults } from './defaults';
|
|
4
|
+
|
|
5
|
+
describe('RTCEngine', () => {
|
|
6
|
+
const originalRTCRtpSender = window.RTCRtpSender;
|
|
7
|
+
const originalRTCRtpScriptTransform = (window as unknown as { RTCRtpScriptTransform?: unknown })
|
|
8
|
+
.RTCRtpScriptTransform;
|
|
9
|
+
const originalUserAgent = navigator.userAgent;
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
Object.defineProperty(window, 'RTCRtpSender', {
|
|
13
|
+
configurable: true,
|
|
14
|
+
value: originalRTCRtpSender,
|
|
15
|
+
writable: true,
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(window, 'RTCRtpScriptTransform', {
|
|
18
|
+
configurable: true,
|
|
19
|
+
value: originalRTCRtpScriptTransform,
|
|
20
|
+
writable: true,
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(window.navigator, 'userAgent', {
|
|
23
|
+
configurable: true,
|
|
24
|
+
value: originalUserAgent,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function stubInsertableStreamsSupport() {
|
|
29
|
+
class MockRTCRtpSender {
|
|
30
|
+
createEncodedStreams() {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Object.defineProperty(window, 'RTCRtpSender', {
|
|
34
|
+
configurable: true,
|
|
35
|
+
value: MockRTCRtpSender,
|
|
36
|
+
writable: true,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function stubScriptTransformSupport() {
|
|
41
|
+
Object.defineProperty(window, 'RTCRtpScriptTransform', {
|
|
42
|
+
configurable: true,
|
|
43
|
+
value: class MockRTCRtpScriptTransform {},
|
|
44
|
+
writable: true,
|
|
45
|
+
});
|
|
46
|
+
Object.defineProperty(window.navigator, 'userAgent', {
|
|
47
|
+
configurable: true,
|
|
48
|
+
value:
|
|
49
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function makeRTCConfiguration(engine: RTCEngine) {
|
|
54
|
+
return (
|
|
55
|
+
engine as unknown as { makeRTCConfiguration: () => RTCConfiguration }
|
|
56
|
+
).makeRTCConfiguration();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function setupPacketTrailerSender(engine: RTCEngine, sender: RTCRtpSender, opts = {}) {
|
|
60
|
+
(
|
|
61
|
+
engine as unknown as {
|
|
62
|
+
setupPacketTrailerSender: (sender: RTCRtpSender, opts?: unknown) => void;
|
|
63
|
+
}
|
|
64
|
+
).setupPacketTrailerSender(sender, opts);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
it('does not enable encoded insertable streams without E2EE or a packet trailer worker', () => {
|
|
68
|
+
stubInsertableStreamsSupport();
|
|
69
|
+
|
|
70
|
+
const engine = new RTCEngine(roomOptionDefaults);
|
|
71
|
+
|
|
72
|
+
expect(makeRTCConfiguration(engine).encodedInsertableStreams).toBeUndefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('enables encoded insertable streams when a packet trailer worker is configured', () => {
|
|
76
|
+
stubInsertableStreamsSupport();
|
|
77
|
+
|
|
78
|
+
const engine = new RTCEngine({
|
|
79
|
+
...roomOptionDefaults,
|
|
80
|
+
packetTrailer: { worker: {} as Worker },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(makeRTCConfiguration(engine).encodedInsertableStreams).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('does not enable encoded insertable streams for packet trailers when script transforms are supported', () => {
|
|
87
|
+
stubInsertableStreamsSupport();
|
|
88
|
+
stubScriptTransformSupport();
|
|
89
|
+
|
|
90
|
+
const engine = new RTCEngine({
|
|
91
|
+
...roomOptionDefaults,
|
|
92
|
+
packetTrailer: { worker: {} as Worker },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(makeRTCConfiguration(engine).encodedInsertableStreams).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('enables encoded insertable streams for E2EE', () => {
|
|
99
|
+
stubInsertableStreamsSupport();
|
|
100
|
+
|
|
101
|
+
const engine = new RTCEngine(roomOptionDefaults);
|
|
102
|
+
(
|
|
103
|
+
engine as unknown as {
|
|
104
|
+
signalOpts: {
|
|
105
|
+
autoSubscribe: boolean;
|
|
106
|
+
maxRetries: number;
|
|
107
|
+
e2eeEnabled: boolean;
|
|
108
|
+
websocketTimeout: number;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
).signalOpts = {
|
|
112
|
+
autoSubscribe: true,
|
|
113
|
+
maxRetries: 1,
|
|
114
|
+
e2eeEnabled: true,
|
|
115
|
+
websocketTimeout: 15_000,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
expect(makeRTCConfiguration(engine).encodedInsertableStreams).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('does not create sender encoded streams when packetTrailer has no worker', () => {
|
|
122
|
+
const engine = new RTCEngine({
|
|
123
|
+
...roomOptionDefaults,
|
|
124
|
+
packetTrailer: {} as never,
|
|
125
|
+
});
|
|
126
|
+
const createEncodedStreams = vi.fn();
|
|
127
|
+
const sender = {
|
|
128
|
+
createEncodedStreams,
|
|
129
|
+
} as unknown as RTCRtpSender;
|
|
130
|
+
|
|
131
|
+
setupPacketTrailerSender(engine, sender);
|
|
132
|
+
|
|
133
|
+
expect(createEncodedStreams).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('does not create sender passthrough streams for packet trailers when script transforms are supported', () => {
|
|
137
|
+
stubScriptTransformSupport();
|
|
138
|
+
|
|
139
|
+
const engine = new RTCEngine({
|
|
140
|
+
...roomOptionDefaults,
|
|
141
|
+
packetTrailer: { worker: {} as Worker },
|
|
142
|
+
});
|
|
143
|
+
const createEncodedStreams = vi.fn();
|
|
144
|
+
const sender = {
|
|
145
|
+
createEncodedStreams,
|
|
146
|
+
} as unknown as RTCRtpSender;
|
|
147
|
+
|
|
148
|
+
setupPacketTrailerSender(engine, sender);
|
|
149
|
+
|
|
150
|
+
expect(createEncodedStreams).not.toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('posts sender encode streams to the packet trailer worker when write features are enabled', () => {
|
|
154
|
+
stubInsertableStreamsSupport();
|
|
155
|
+
|
|
156
|
+
const worker = { postMessage: vi.fn() } as unknown as Worker;
|
|
157
|
+
const engine = new RTCEngine({
|
|
158
|
+
...roomOptionDefaults,
|
|
159
|
+
packetTrailer: { worker },
|
|
160
|
+
});
|
|
161
|
+
const readable = {} as ReadableStream;
|
|
162
|
+
const writable = {} as WritableStream;
|
|
163
|
+
const createEncodedStreams = vi.fn(() => ({ readable, writable }));
|
|
164
|
+
const sender = {
|
|
165
|
+
createEncodedStreams,
|
|
166
|
+
} as unknown as RTCRtpSender;
|
|
167
|
+
|
|
168
|
+
setupPacketTrailerSender(engine, sender, { packetTrailer: { timestamp: true, frameId: true } });
|
|
169
|
+
|
|
170
|
+
expect(createEncodedStreams).toHaveBeenCalledTimes(1);
|
|
171
|
+
expect(worker.postMessage).toHaveBeenCalledWith(
|
|
172
|
+
{
|
|
173
|
+
kind: 'encode',
|
|
174
|
+
data: {
|
|
175
|
+
readableStream: readable,
|
|
176
|
+
writableStream: writable,
|
|
177
|
+
packetTrailer: { timestamp: true, frameId: true },
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
[readable, writable],
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('uses RTCRtpScriptTransform for sender packet trailer writes when supported', () => {
|
|
185
|
+
stubScriptTransformSupport();
|
|
186
|
+
|
|
187
|
+
const transform = {};
|
|
188
|
+
const RTCRtpScriptTransform = vi.fn(() => transform);
|
|
189
|
+
Object.defineProperty(window, 'RTCRtpScriptTransform', {
|
|
190
|
+
configurable: true,
|
|
191
|
+
value: RTCRtpScriptTransform,
|
|
192
|
+
writable: true,
|
|
193
|
+
});
|
|
194
|
+
Object.defineProperty(globalThis, 'RTCRtpScriptTransform', {
|
|
195
|
+
configurable: true,
|
|
196
|
+
value: RTCRtpScriptTransform,
|
|
197
|
+
writable: true,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const worker = {} as Worker;
|
|
201
|
+
const engine = new RTCEngine({
|
|
202
|
+
...roomOptionDefaults,
|
|
203
|
+
packetTrailer: { worker },
|
|
204
|
+
});
|
|
205
|
+
const createEncodedStreams = vi.fn();
|
|
206
|
+
const sender = {
|
|
207
|
+
createEncodedStreams,
|
|
208
|
+
} as unknown as RTCRtpSender;
|
|
209
|
+
|
|
210
|
+
setupPacketTrailerSender(engine, sender, { packetTrailer: { timestamp: true } });
|
|
211
|
+
|
|
212
|
+
expect(RTCRtpScriptTransform).toHaveBeenCalledWith(worker, {
|
|
213
|
+
kind: 'encode',
|
|
214
|
+
packetTrailer: { timestamp: true },
|
|
215
|
+
});
|
|
216
|
+
expect((sender as unknown as { transform: unknown }).transform).toBe(transform);
|
|
217
|
+
expect(createEncodedStreams).not.toHaveBeenCalled();
|
|
218
|
+
});
|
|
219
|
+
});
|
package/src/room/RTCEngine.ts
CHANGED
|
@@ -26,7 +26,6 @@ import {
|
|
|
26
26
|
Room as RoomModel,
|
|
27
27
|
RoomMovedResponse,
|
|
28
28
|
RpcAck,
|
|
29
|
-
RpcResponse,
|
|
30
29
|
ServerInfo,
|
|
31
30
|
SessionDescription,
|
|
32
31
|
SignalTarget,
|
|
@@ -54,9 +53,14 @@ import {
|
|
|
54
53
|
toProtoSessionDescription,
|
|
55
54
|
} from '../api/SignalClient';
|
|
56
55
|
import type { BaseE2EEManager } from '../e2ee/E2eeManager';
|
|
57
|
-
import { asEncryptablePacket } from '../e2ee/utils';
|
|
56
|
+
import { asEncryptablePacket, isInsertableStreamSupported } from '../e2ee/utils';
|
|
58
57
|
import log, { LoggerNames, getLogger } from '../logger';
|
|
59
58
|
import type { InternalRoomOptions } from '../options';
|
|
59
|
+
import {
|
|
60
|
+
hasPacketTrailerPublishOptions,
|
|
61
|
+
isPacketTrailerSupported,
|
|
62
|
+
shouldUsePacketTrailerScriptTransform,
|
|
63
|
+
} from '../packetTrailer/utils';
|
|
60
64
|
import TypedPromise from '../utils/TypedPromise';
|
|
61
65
|
import { DataPacketBuffer } from '../utils/dataPacketBuffer';
|
|
62
66
|
import { TTLMap } from '../utils/ttlmap';
|
|
@@ -74,7 +78,6 @@ import {
|
|
|
74
78
|
UnexpectedConnectionState,
|
|
75
79
|
} from './errors';
|
|
76
80
|
import { EngineEvent } from './events';
|
|
77
|
-
import { RpcError } from './rpc';
|
|
78
81
|
import CriticalTimers from './timers';
|
|
79
82
|
import type LocalTrack from './track/LocalTrack';
|
|
80
83
|
import type LocalTrackPublication from './track/LocalTrackPublication';
|
|
@@ -762,7 +765,14 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
762
765
|
): RTCConfiguration {
|
|
763
766
|
const rtcConfig = { ...this.rtcConfig };
|
|
764
767
|
|
|
765
|
-
|
|
768
|
+
// E2EE and packet trailer extraction both rely on encoded frame transforms.
|
|
769
|
+
// Only opt into the createEncodedStreams flavor when that path will be
|
|
770
|
+
// used; RTCRtpScriptTransform does not need the PeerConnection flag.
|
|
771
|
+
const needsInsertableStreams =
|
|
772
|
+
this.signalOpts?.e2eeEnabled ||
|
|
773
|
+
(this.options.packetTrailer?.worker && !shouldUsePacketTrailerScriptTransform());
|
|
774
|
+
|
|
775
|
+
if (needsInsertableStreams && isInsertableStreamSupported()) {
|
|
766
776
|
this.log.debug('E2EE - setting up transports with insertable streams');
|
|
767
777
|
// this makes sure that no data is sent before the transforms are ready
|
|
768
778
|
// @ts-ignore
|
|
@@ -940,8 +950,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
940
950
|
return;
|
|
941
951
|
}
|
|
942
952
|
const decryptedData = await this.e2eeManager?.handleEncryptedData(
|
|
943
|
-
dp.value.value.encryptedValue,
|
|
944
|
-
dp.value.value.iv,
|
|
953
|
+
dp.value.value.encryptedValue as NonSharedUint8Array,
|
|
954
|
+
dp.value.value.iv as NonSharedUint8Array,
|
|
945
955
|
dp.participantIdentity,
|
|
946
956
|
dp.value.value.keyIndex,
|
|
947
957
|
);
|
|
@@ -1004,16 +1014,17 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1004
1014
|
opts: TrackPublishOptions,
|
|
1005
1015
|
encodings?: RTCRtpEncodingParameters[],
|
|
1006
1016
|
) {
|
|
1017
|
+
let sender: RTCRtpSender;
|
|
1007
1018
|
if (supportsTransceiver()) {
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
}
|
|
1011
|
-
if (supportsAddTrack()) {
|
|
1019
|
+
sender = await this.createTransceiverRTCRtpSender(track, opts, encodings);
|
|
1020
|
+
} else if (supportsAddTrack()) {
|
|
1012
1021
|
this.log.warn('using add-track fallback');
|
|
1013
|
-
|
|
1014
|
-
|
|
1022
|
+
sender = await this.createRTCRtpSender(track.mediaStreamTrack);
|
|
1023
|
+
} else {
|
|
1024
|
+
throw new UnexpectedConnectionState('Required webRTC APIs not supported on this device');
|
|
1015
1025
|
}
|
|
1016
|
-
|
|
1026
|
+
this.setupPacketTrailerSender(sender, opts);
|
|
1027
|
+
return sender;
|
|
1017
1028
|
}
|
|
1018
1029
|
|
|
1019
1030
|
async createSimulcastSender(
|
|
@@ -1022,16 +1033,67 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1022
1033
|
opts: TrackPublishOptions,
|
|
1023
1034
|
encodings?: RTCRtpEncodingParameters[],
|
|
1024
1035
|
) {
|
|
1025
|
-
|
|
1036
|
+
let sender: RTCRtpSender | undefined;
|
|
1026
1037
|
if (supportsTransceiver()) {
|
|
1027
|
-
|
|
1028
|
-
}
|
|
1029
|
-
if (supportsAddTrack()) {
|
|
1038
|
+
sender = await this.createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings);
|
|
1039
|
+
} else if (supportsAddTrack()) {
|
|
1030
1040
|
this.log.debug('using add-track fallback');
|
|
1031
|
-
|
|
1041
|
+
sender = await this.createRTCRtpSender(track.mediaStreamTrack);
|
|
1042
|
+
} else {
|
|
1043
|
+
throw new UnexpectedConnectionState('Cannot stream on this device');
|
|
1044
|
+
}
|
|
1045
|
+
if (sender) {
|
|
1046
|
+
this.setupPacketTrailerSender(sender, opts);
|
|
1047
|
+
}
|
|
1048
|
+
return sender;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
private setupPacketTrailerSender(sender: RTCRtpSender, opts: TrackPublishOptions = {}) {
|
|
1052
|
+
if (!this.options.packetTrailer?.worker || this.signalOpts?.e2eeEnabled) {
|
|
1053
|
+
return;
|
|
1032
1054
|
}
|
|
1033
1055
|
|
|
1034
|
-
|
|
1056
|
+
const packetTrailer = opts.packetTrailer;
|
|
1057
|
+
const hasPacketTrailer = hasPacketTrailerPublishOptions(packetTrailer);
|
|
1058
|
+
|
|
1059
|
+
if (shouldUsePacketTrailerScriptTransform()) {
|
|
1060
|
+
if (hasPacketTrailer) {
|
|
1061
|
+
// @ts-ignore
|
|
1062
|
+
sender.transform = new RTCRtpScriptTransform(this.options.packetTrailer.worker, {
|
|
1063
|
+
kind: 'encode',
|
|
1064
|
+
packetTrailer,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
if (
|
|
1071
|
+
!isPacketTrailerSupported(this.options.packetTrailer) ||
|
|
1072
|
+
!('createEncodedStreams' in sender)
|
|
1073
|
+
) {
|
|
1074
|
+
if (hasPacketTrailer) {
|
|
1075
|
+
this.log.warn('packet trailer transform not supported; skipping write', this.logContext);
|
|
1076
|
+
}
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// @ts-ignore
|
|
1081
|
+
const { readable, writable } = sender.createEncodedStreams();
|
|
1082
|
+
if (hasPacketTrailer) {
|
|
1083
|
+
this.options.packetTrailer.worker.postMessage(
|
|
1084
|
+
{
|
|
1085
|
+
kind: 'encode',
|
|
1086
|
+
data: {
|
|
1087
|
+
readableStream: readable,
|
|
1088
|
+
writableStream: writable,
|
|
1089
|
+
packetTrailer,
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
[readable, writable],
|
|
1093
|
+
);
|
|
1094
|
+
} else {
|
|
1095
|
+
readable.pipeTo(writable);
|
|
1096
|
+
}
|
|
1035
1097
|
}
|
|
1036
1098
|
|
|
1037
1099
|
private async createTransceiverRTCRtpSender(
|
|
@@ -1400,30 +1462,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1400
1462
|
});
|
|
1401
1463
|
};
|
|
1402
1464
|
|
|
1403
|
-
/** @internal */
|
|
1404
|
-
async publishRpcResponse(
|
|
1405
|
-
destinationIdentity: string,
|
|
1406
|
-
requestId: string,
|
|
1407
|
-
payload: string | null,
|
|
1408
|
-
error: RpcError | null,
|
|
1409
|
-
) {
|
|
1410
|
-
const packet = new DataPacket({
|
|
1411
|
-
destinationIdentities: [destinationIdentity],
|
|
1412
|
-
kind: DataPacket_Kind.RELIABLE,
|
|
1413
|
-
value: {
|
|
1414
|
-
case: 'rpcResponse',
|
|
1415
|
-
value: new RpcResponse({
|
|
1416
|
-
requestId,
|
|
1417
|
-
value: error
|
|
1418
|
-
? { case: 'error', value: error.toProto() }
|
|
1419
|
-
: { case: 'payload', value: payload ?? '' },
|
|
1420
|
-
}),
|
|
1421
|
-
},
|
|
1422
|
-
});
|
|
1423
|
-
|
|
1424
|
-
await this.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
1465
|
/** @internal */
|
|
1428
1466
|
async publishRpcAck(destinationIdentity: string, requestId: string) {
|
|
1429
1467
|
const packet = new DataPacket({
|
|
@@ -1447,7 +1485,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1447
1485
|
if (this.e2eeManager && this.e2eeManager.isDataChannelEncryptionEnabled) {
|
|
1448
1486
|
const encryptablePacket = asEncryptablePacket(packet);
|
|
1449
1487
|
if (encryptablePacket) {
|
|
1450
|
-
const encryptedData = await this.e2eeManager.encryptData(
|
|
1488
|
+
const encryptedData = await this.e2eeManager.encryptData(
|
|
1489
|
+
encryptablePacket.toBinary() as NonSharedUint8Array,
|
|
1490
|
+
);
|
|
1451
1491
|
packet.value = {
|
|
1452
1492
|
case: 'encryptedPacket',
|
|
1453
1493
|
value: new EncryptedPacket({
|
|
@@ -1464,7 +1504,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1464
1504
|
this.reliableDataSequence += 1;
|
|
1465
1505
|
}
|
|
1466
1506
|
|
|
1467
|
-
const msg = packet.toBinary()
|
|
1507
|
+
const msg = packet.toBinary() as Uint8Array<ArrayBuffer>;
|
|
1468
1508
|
|
|
1469
1509
|
switch (kind) {
|
|
1470
1510
|
case DataChannelKind.LOSSY:
|
|
@@ -1491,7 +1531,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1491
1531
|
|
|
1492
1532
|
/* @internal */
|
|
1493
1533
|
async sendLossyBytes(
|
|
1494
|
-
bytes:
|
|
1534
|
+
bytes: NonSharedUint8Array,
|
|
1495
1535
|
kind: Exclude<DataChannelKind, DataChannelKind.RELIABLE>,
|
|
1496
1536
|
bufferStatusLowBehavior: 'drop' | 'wait' = 'drop',
|
|
1497
1537
|
) {
|
package/src/room/Room.test.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ClientInfo_Capability, JoinResponse } from '@livekit/protocol';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
3
|
import Room from './Room';
|
|
4
|
+
import { roomConnectOptionDefaults, roomOptionDefaults } from './defaults';
|
|
3
5
|
import { RoomEvent } from './events';
|
|
4
6
|
|
|
5
7
|
describe('Active device switch', () => {
|
|
@@ -28,3 +30,62 @@ describe('Active device switch', () => {
|
|
|
28
30
|
expect(kind).toBe('audioinput');
|
|
29
31
|
});
|
|
30
32
|
});
|
|
33
|
+
|
|
34
|
+
describe('Room signaling options', () => {
|
|
35
|
+
it('advertises packet trailer capability when E2EE can handle trailers', async () => {
|
|
36
|
+
const room = new Room();
|
|
37
|
+
const join = vi.fn().mockResolvedValue({
|
|
38
|
+
joinResponse: new JoinResponse({
|
|
39
|
+
room: { name: 'test-room', sid: 'room-sid' },
|
|
40
|
+
participant: { sid: 'participant-sid', identity: 'test-user' },
|
|
41
|
+
}),
|
|
42
|
+
serverInfo: { version: '1.0.0' },
|
|
43
|
+
});
|
|
44
|
+
const engine = { join };
|
|
45
|
+
|
|
46
|
+
(
|
|
47
|
+
room as unknown as {
|
|
48
|
+
e2eeManager: unknown;
|
|
49
|
+
connectSignal: (
|
|
50
|
+
url: string,
|
|
51
|
+
token: string,
|
|
52
|
+
engine: unknown,
|
|
53
|
+
connectOptions: typeof roomConnectOptionDefaults,
|
|
54
|
+
roomOptions: typeof roomOptionDefaults,
|
|
55
|
+
abortController: AbortController,
|
|
56
|
+
) => Promise<JoinResponse>;
|
|
57
|
+
}
|
|
58
|
+
).e2eeManager = {};
|
|
59
|
+
|
|
60
|
+
await (
|
|
61
|
+
room as unknown as {
|
|
62
|
+
connectSignal: (
|
|
63
|
+
url: string,
|
|
64
|
+
token: string,
|
|
65
|
+
engine: unknown,
|
|
66
|
+
connectOptions: typeof roomConnectOptionDefaults,
|
|
67
|
+
roomOptions: typeof roomOptionDefaults,
|
|
68
|
+
abortController: AbortController,
|
|
69
|
+
) => Promise<JoinResponse>;
|
|
70
|
+
}
|
|
71
|
+
).connectSignal(
|
|
72
|
+
'wss://test.livekit.io',
|
|
73
|
+
'test-token',
|
|
74
|
+
engine,
|
|
75
|
+
roomConnectOptionDefaults,
|
|
76
|
+
roomOptionDefaults,
|
|
77
|
+
new AbortController(),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
expect(join).toHaveBeenCalledWith(
|
|
81
|
+
'wss://test.livekit.io',
|
|
82
|
+
'test-token',
|
|
83
|
+
expect.objectContaining({
|
|
84
|
+
clientInfoCapabilities: [ClientInfo_Capability.CAP_PACKET_TRAILER],
|
|
85
|
+
e2eeEnabled: true,
|
|
86
|
+
}),
|
|
87
|
+
expect.any(AbortSignal),
|
|
88
|
+
false,
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
});
|