livekit-client 2.17.1 → 2.17.3
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/README.md +7 -5
- 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 +21 -14
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +2087 -1920
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +2 -0
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +2 -0
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/events.d.ts +1 -1
- package/dist/src/e2ee/events.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +1 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/index.d.ts +7 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +2 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -4
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts +2 -4
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +51 -0
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -0
- package/dist/src/room/data-track/e2ee.d.ts +12 -0
- package/dist/src/room/data-track/e2ee.d.ts.map +1 -0
- package/dist/src/room/data-track/frame.d.ts +7 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -0
- package/dist/src/room/data-track/handle.d.ts +6 -7
- package/dist/src/room/data-track/handle.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +76 -0
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/errors.d.ts +64 -0
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +22 -0
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -0
- package/dist/src/room/data-track/outgoing/types.d.ts +31 -0
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/index.d.ts +3 -3
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +43 -0
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -0
- package/dist/src/room/data-track/track.d.ts +30 -0
- package/dist/src/room/data-track/track.d.ts.map +1 -0
- package/dist/src/room/data-track/utils.d.ts +34 -2
- package/dist/src/room/data-track/utils.d.ts.map +1 -1
- package/dist/src/room/debounce.d.ts +11 -0
- package/dist/src/room/debounce.d.ts.map +1 -0
- package/dist/src/room/events.d.ts +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +0 -2
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +6 -1
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/subscribeToEvents.d.ts +12 -0
- package/dist/src/utils/subscribeToEvents.d.ts.map +1 -0
- package/dist/src/utils/throws.d.ts +4 -2
- package/dist/src/utils/throws.d.ts.map +1 -1
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +2 -0
- package/dist/ts4.2/e2ee/KeyProvider.d.ts +2 -0
- package/dist/ts4.2/e2ee/events.d.ts +1 -1
- package/dist/ts4.2/e2ee/types.d.ts +1 -0
- package/dist/ts4.2/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
- package/dist/ts4.2/index.d.ts +7 -3
- package/dist/ts4.2/logger.d.ts +2 -1
- package/dist/ts4.2/room/PCTransport.d.ts +1 -6
- package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +2 -4
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +51 -0
- package/dist/ts4.2/room/data-track/e2ee.d.ts +12 -0
- package/dist/ts4.2/room/data-track/frame.d.ts +7 -0
- package/dist/ts4.2/room/data-track/handle.d.ts +6 -7
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +77 -0
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +64 -0
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +22 -0
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +31 -0
- package/dist/ts4.2/room/data-track/packet/index.d.ts +3 -3
- package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -0
- package/dist/ts4.2/room/data-track/track.d.ts +30 -0
- package/dist/ts4.2/room/data-track/utils.d.ts +34 -2
- package/dist/ts4.2/room/debounce.d.ts +11 -0
- package/dist/ts4.2/room/events.d.ts +1 -1
- package/dist/ts4.2/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/ts4.2/room/track/LocalTrack.d.ts +2 -1
- package/dist/ts4.2/room/types.d.ts +0 -2
- package/dist/ts4.2/room/utils.d.ts +6 -1
- package/dist/ts4.2/utils/subscribeToEvents.d.ts +12 -0
- package/dist/ts4.2/utils/throws.d.ts +4 -2
- package/package.json +4 -5
- package/src/e2ee/E2eeManager.ts +9 -5
- package/src/e2ee/KeyProvider.ts +10 -1
- package/src/e2ee/events.ts +1 -1
- package/src/e2ee/types.ts +1 -0
- package/src/e2ee/worker/ParticipantKeyHandler.ts +7 -4
- package/src/e2ee/worker/e2ee.worker.ts +20 -10
- package/src/index.ts +15 -5
- package/src/logger.ts +1 -0
- package/src/room/PCTransport.ts +2 -1
- package/src/room/PCTransportManager.ts +27 -9
- package/src/room/RTCEngine.ts +13 -2
- package/src/room/Room.ts +11 -5
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +5 -25
- package/src/room/data-stream/incoming/StreamReader.ts +56 -73
- package/src/room/data-track/depacketizer.test.ts +442 -0
- package/src/room/data-track/depacketizer.ts +298 -0
- package/src/room/data-track/e2ee.ts +14 -0
- package/src/room/data-track/frame.ts +8 -0
- package/src/room/data-track/handle.test.ts +1 -1
- package/src/room/data-track/handle.ts +9 -14
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +392 -0
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +302 -0
- package/src/room/data-track/outgoing/errors.ts +157 -0
- package/src/room/data-track/outgoing/pipeline.ts +76 -0
- package/src/room/data-track/outgoing/types.ts +37 -0
- package/src/room/data-track/packet/index.test.ts +9 -9
- package/src/room/data-track/packet/index.ts +11 -9
- package/src/room/data-track/packet/serializable.ts +1 -1
- package/src/room/data-track/packetizer.test.ts +131 -0
- package/src/room/data-track/packetizer.ts +132 -0
- package/src/room/data-track/track.ts +50 -0
- package/src/room/data-track/utils.test.ts +27 -1
- package/src/room/data-track/utils.ts +125 -5
- package/src/room/debounce.ts +115 -0
- package/src/room/events.ts +1 -1
- package/src/room/participant/LocalParticipant.ts +2 -0
- package/src/room/track/LocalAudioTrack.ts +10 -10
- package/src/room/track/LocalTrack.ts +14 -5
- package/src/room/track/LocalVideoTrack.ts +1 -1
- package/src/room/track/RemoteVideoTrack.ts +1 -1
- package/src/room/types.ts +0 -2
- package/src/room/utils.ts +7 -2
- package/src/utils/subscribeToEvents.ts +63 -0
- package/src/utils/throws.ts +3 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ChatMessage as ChatMessageModel, ClientInfo, DisconnectReason, Transcription as TranscriptionModel } from '@livekit/protocol';
|
|
2
2
|
import TypedPromise from '../utils/TypedPromise';
|
|
3
3
|
import type { BrowserDetails } from '../utils/browserParser';
|
|
4
|
+
import type { Throws } from '../utils/throws';
|
|
4
5
|
import type { ConnectionError } from './errors';
|
|
5
6
|
import type LocalParticipant from './participant/LocalParticipant';
|
|
6
7
|
import type Participant from './participant/Participant';
|
|
@@ -71,8 +72,12 @@ export declare function getEmptyVideoStreamTrack(): MediaStreamTrack;
|
|
|
71
72
|
export declare function createDummyVideoStreamTrack(width?: number, height?: number, enabled?: boolean, paintContent?: boolean): MediaStreamTrack;
|
|
72
73
|
export declare function getEmptyAudioStreamTrack(): MediaStreamTrack;
|
|
73
74
|
export declare function getStereoAudioStreamTrack(): MediaStreamTrack;
|
|
75
|
+
/** An object that represents a serialized version of a `new Promise((resolve, reject) => {})`
|
|
76
|
+
* constructor. Wait for a promise resolution with `await future.promise` and explicitly resolve or
|
|
77
|
+
* reject the inner promise with `future.resolve(...)` or `future.reject(...)`.
|
|
78
|
+
*/
|
|
74
79
|
export declare class Future<T, E extends Error> {
|
|
75
|
-
promise: Promise<T
|
|
80
|
+
promise: Promise<Throws<T, E>>;
|
|
76
81
|
resolve?: (arg: T) => void;
|
|
77
82
|
reject?: (e: E) => void;
|
|
78
83
|
onFinally?: () => void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EventMap } from 'typed-emitter';
|
|
2
|
+
import type TypedEventEmitter from 'typed-emitter';
|
|
3
|
+
/** A test helper to listen to events received by an event emitter and allow them to be imperatively
|
|
4
|
+
* queried after the fact. */
|
|
5
|
+
export declare function subscribeToEvents<Callbacks extends EventMap, EventNames extends keyof Callbacks = keyof Callbacks>(eventEmitter: TypedEventEmitter<Callbacks>, eventNames: Array<EventNames>): {
|
|
6
|
+
/** Listen for the next occurrance of an event to be emitted, or return the last event that was
|
|
7
|
+
* buffered (but hasn't been processed yet). */
|
|
8
|
+
waitFor<EventPayload extends Parameters<Callbacks[EventName]>[0], EventName extends EventNames = EventNames>(eventName: EventName): Promise<EventPayload>;
|
|
9
|
+
/** Cleanup any lingering subscriptions. */
|
|
10
|
+
unsubscribe: () => void;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=subscribeToEvents.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type Primitives = null | undefined | string | number | bigint | boolean | symbol;
|
|
1
2
|
/**
|
|
2
3
|
* Branded type that encodes possible thrown errors in the return type.
|
|
3
4
|
*
|
|
@@ -11,9 +12,9 @@
|
|
|
11
12
|
*
|
|
12
13
|
* For more info about how this is checked, see ./throws-transformer at the root of this repo.
|
|
13
14
|
*/
|
|
14
|
-
export type Throws<T, E extends Error> = T & {
|
|
15
|
+
export type Throws<T, E extends Error> = (T & {
|
|
15
16
|
readonly __throws?: E;
|
|
16
|
-
}
|
|
17
|
+
}) | Extract<T, Primitives>;
|
|
17
18
|
/**
|
|
18
19
|
* Extract the error types from a Throws type.
|
|
19
20
|
*/
|
|
@@ -34,4 +35,5 @@ export type CombineErrors<T extends any[]> = T extends [
|
|
|
34
35
|
* throwing functions and wants to propagate their errors.
|
|
35
36
|
*/
|
|
36
37
|
export type PropagatesErrors<T, AdditionalErrors extends Error = never> = Throws<ExtractSuccess<T>, ExtractErrors<T> | AdditionalErrors>;
|
|
38
|
+
export {};
|
|
37
39
|
//# sourceMappingURL=throws.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "livekit-client",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.3",
|
|
4
4
|
"description": "JavaScript/TypeScript client SDK for LiveKit",
|
|
5
5
|
"main": "./dist/livekit-client.umd.js",
|
|
6
6
|
"unpkg": "./dist/livekit-client.umd.js",
|
|
@@ -42,7 +42,6 @@
|
|
|
42
42
|
"jose": "^6.1.0",
|
|
43
43
|
"loglevel": "^1.9.2",
|
|
44
44
|
"sdp-transform": "^2.15.0",
|
|
45
|
-
"ts-debounce": "^4.0.0",
|
|
46
45
|
"tslib": "2.8.1",
|
|
47
46
|
"typed-emitter": "^2.1.0",
|
|
48
47
|
"webrtc-adapter": "^9.0.1"
|
|
@@ -79,11 +78,11 @@
|
|
|
79
78
|
"eslint-plugin-import-x": "^4.16.1",
|
|
80
79
|
"eslint-plugin-prettier": "^5.5.4",
|
|
81
80
|
"gh-pages": "6.3.0",
|
|
82
|
-
"glob": "^13.0.
|
|
83
|
-
"happy-dom": "^
|
|
81
|
+
"glob": "^13.0.6",
|
|
82
|
+
"happy-dom": "^20.0.0",
|
|
84
83
|
"jsdom": "^26.1.0",
|
|
85
84
|
"prettier": "^3.4.2",
|
|
86
|
-
"rollup": "4.
|
|
85
|
+
"rollup": "4.59.0",
|
|
87
86
|
"rollup-plugin-delete": "^2.1.0",
|
|
88
87
|
"rollup-plugin-typescript2": "0.36.0",
|
|
89
88
|
"size-limit": "^11.2.0",
|
package/src/e2ee/E2eeManager.ts
CHANGED
|
@@ -169,7 +169,7 @@ export class E2EEManager
|
|
|
169
169
|
case 'initAck':
|
|
170
170
|
if (data.enabled) {
|
|
171
171
|
this.keyProvider.getKeys().forEach((keyInfo) => {
|
|
172
|
-
this.postKey(keyInfo);
|
|
172
|
+
this.postKey(keyInfo, false);
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
break;
|
|
@@ -177,7 +177,7 @@ export class E2EEManager
|
|
|
177
177
|
case 'enable':
|
|
178
178
|
if (data.enabled) {
|
|
179
179
|
this.keyProvider.getKeys().forEach((keyInfo) => {
|
|
180
|
-
this.postKey(keyInfo);
|
|
180
|
+
this.postKey(keyInfo, false);
|
|
181
181
|
});
|
|
182
182
|
}
|
|
183
183
|
if (
|
|
@@ -274,8 +274,9 @@ export class E2EEManager
|
|
|
274
274
|
if (!this.room) {
|
|
275
275
|
throw new TypeError(`expected room to be present on signal connect`);
|
|
276
276
|
}
|
|
277
|
+
const latestKeyIndex = keyProvider.getLatestManuallySetKeyIndex();
|
|
277
278
|
keyProvider.getKeys().forEach((keyInfo) => {
|
|
278
|
-
this.postKey(keyInfo);
|
|
279
|
+
this.postKey(keyInfo, latestKeyIndex === (keyInfo.keyIndex ?? 0));
|
|
279
280
|
});
|
|
280
281
|
this.setParticipantCryptorEnabled(
|
|
281
282
|
this.room.localParticipant.isE2EEEnabled,
|
|
@@ -305,7 +306,9 @@ export class E2EEManager
|
|
|
305
306
|
});
|
|
306
307
|
|
|
307
308
|
keyProvider
|
|
308
|
-
.on(KeyProviderEvent.SetKey, (keyInfo) =>
|
|
309
|
+
.on(KeyProviderEvent.SetKey, (keyInfo, updateCurrentKeyIndex) =>
|
|
310
|
+
this.postKey(keyInfo, updateCurrentKeyIndex ?? true),
|
|
311
|
+
)
|
|
309
312
|
.on(KeyProviderEvent.RatchetRequest, (participantId, keyIndex) =>
|
|
310
313
|
this.postRatchetRequest(participantId, keyIndex),
|
|
311
314
|
);
|
|
@@ -376,7 +379,7 @@ export class E2EEManager
|
|
|
376
379
|
this.worker.postMessage(msg);
|
|
377
380
|
}
|
|
378
381
|
|
|
379
|
-
private postKey({ key, participantIdentity, keyIndex }: KeyInfo) {
|
|
382
|
+
private postKey({ key, participantIdentity, keyIndex }: KeyInfo, updateCurrentKeyIndex: boolean) {
|
|
380
383
|
if (!this.worker) {
|
|
381
384
|
throw Error('could not set key, worker is missing');
|
|
382
385
|
}
|
|
@@ -387,6 +390,7 @@ export class E2EEManager
|
|
|
387
390
|
isPublisher: participantIdentity === this.room?.localParticipant.identity,
|
|
388
391
|
key,
|
|
389
392
|
keyIndex,
|
|
393
|
+
updateCurrentKeyIndex,
|
|
390
394
|
},
|
|
391
395
|
};
|
|
392
396
|
this.worker.postMessage(msg);
|
package/src/e2ee/KeyProvider.ts
CHANGED
|
@@ -14,6 +14,8 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
|
14
14
|
|
|
15
15
|
private readonly options: KeyProviderOptions;
|
|
16
16
|
|
|
17
|
+
private latestManuallySetKeyIndex = 0;
|
|
18
|
+
|
|
17
19
|
constructor(options: Partial<KeyProviderOptions> = {}) {
|
|
18
20
|
super();
|
|
19
21
|
this.keyInfoMap = new Map();
|
|
@@ -35,7 +37,10 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
|
35
37
|
);
|
|
36
38
|
}
|
|
37
39
|
this.keyInfoMap.set(`${participantIdentity ?? 'shared'}-${keyIndex ?? 0}`, keyInfo);
|
|
38
|
-
|
|
40
|
+
if (keyIndex !== undefined) {
|
|
41
|
+
this.latestManuallySetKeyIndex = keyIndex;
|
|
42
|
+
}
|
|
43
|
+
this.emit(KeyProviderEvent.SetKey, keyInfo, keyIndex !== undefined);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/**
|
|
@@ -59,6 +64,10 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
|
59
64
|
return Array.from(this.keyInfoMap.values());
|
|
60
65
|
}
|
|
61
66
|
|
|
67
|
+
getLatestManuallySetKeyIndex() {
|
|
68
|
+
return this.latestManuallySetKeyIndex;
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
getOptions() {
|
|
63
72
|
return this.options;
|
|
64
73
|
}
|
package/src/e2ee/events.ts
CHANGED
|
@@ -12,7 +12,7 @@ export enum KeyProviderEvent {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export type KeyProviderCallbacks = {
|
|
15
|
-
[KeyProviderEvent.SetKey]: (keyInfo: KeyInfo) => void;
|
|
15
|
+
[KeyProviderEvent.SetKey]: (keyInfo: KeyInfo, updateCurrentKeyIndex: boolean) => void;
|
|
16
16
|
[KeyProviderEvent.RatchetRequest]: (participantIdentity?: string, keyIndex?: number) => void;
|
|
17
17
|
[KeyProviderEvent.KeyRatcheted]: (
|
|
18
18
|
ratchetedResult: RatchetResult,
|
package/src/e2ee/types.ts
CHANGED
|
@@ -154,9 +154,11 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
|
154
154
|
* together with the material
|
|
155
155
|
* also resets the valid key property and updates the currentKeyIndex
|
|
156
156
|
*/
|
|
157
|
-
async setKey(material: CryptoKey, keyIndex = 0) {
|
|
158
|
-
await this.setKeyFromMaterial(material, keyIndex);
|
|
159
|
-
|
|
157
|
+
async setKey(material: CryptoKey, keyIndex = 0, updateCurrentKeyIndex = true) {
|
|
158
|
+
await this.setKeyFromMaterial(material, keyIndex, null, updateCurrentKeyIndex);
|
|
159
|
+
if (updateCurrentKeyIndex) {
|
|
160
|
+
this.resetKeyStatus(keyIndex);
|
|
161
|
+
}
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
/**
|
|
@@ -169,6 +171,7 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
|
169
171
|
material: CryptoKey,
|
|
170
172
|
keyIndex: number,
|
|
171
173
|
ratchetedResult: RatchetResult | null = null,
|
|
174
|
+
updateCurrentKeyIndex = true,
|
|
172
175
|
) {
|
|
173
176
|
const keySet = await deriveKeys(material, this.keyProviderOptions.ratchetSalt);
|
|
174
177
|
const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : this.currentKeyIndex;
|
|
@@ -178,7 +181,7 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
|
178
181
|
ratchetSalt: this.keyProviderOptions.ratchetSalt,
|
|
179
182
|
});
|
|
180
183
|
this.setKeySet(keySet, newIndex, ratchetedResult);
|
|
181
|
-
if (newIndex >= 0) this.currentKeyIndex = newIndex;
|
|
184
|
+
if (newIndex >= 0 && updateCurrentKeyIndex) this.currentKeyIndex = newIndex;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
setKeySet(keySet: KeySet, keyIndex: number, ratchetedResult: RatchetResult | null = null) {
|
|
@@ -141,12 +141,16 @@ onmessage = (ev) => {
|
|
|
141
141
|
|
|
142
142
|
case 'setKey':
|
|
143
143
|
if (useSharedKey) {
|
|
144
|
-
await setSharedKey(data.key, data.keyIndex);
|
|
144
|
+
await setSharedKey(data.key, data.keyIndex, data.updateCurrentKeyIndex);
|
|
145
145
|
} else if (data.participantIdentity) {
|
|
146
146
|
workerLogger.info(
|
|
147
147
|
`set participant sender key ${data.participantIdentity} index ${data.keyIndex}`,
|
|
148
148
|
);
|
|
149
|
-
await getParticipantKeyHandler(data.participantIdentity).setKey(
|
|
149
|
+
await getParticipantKeyHandler(data.participantIdentity).setKey(
|
|
150
|
+
data.key,
|
|
151
|
+
data.keyIndex,
|
|
152
|
+
data.updateCurrentKeyIndex,
|
|
153
|
+
);
|
|
150
154
|
} else {
|
|
151
155
|
workerLogger.error('no participant Id was provided and shared key usage is disabled');
|
|
152
156
|
}
|
|
@@ -281,9 +285,9 @@ function setEncryptionEnabled(enable: boolean, participantIdentity: string) {
|
|
|
281
285
|
encryptionEnabledMap.set(participantIdentity, enable);
|
|
282
286
|
}
|
|
283
287
|
|
|
284
|
-
async function setSharedKey(key: CryptoKey, index?: number) {
|
|
288
|
+
async function setSharedKey(key: CryptoKey, index?: number, updateCurrentKeyIndex?: boolean) {
|
|
285
289
|
workerLogger.info('set shared key', { index });
|
|
286
|
-
await getSharedKeyHandler().setKey(key, index);
|
|
290
|
+
await getSharedKeyHandler().setKey(key, index, updateCurrentKeyIndex);
|
|
287
291
|
}
|
|
288
292
|
|
|
289
293
|
function setupCryptorErrorEvents(cryptor: FrameCryptor) {
|
|
@@ -325,17 +329,23 @@ function handleSifTrailer(trailer: Uint8Array) {
|
|
|
325
329
|
// Operations using RTCRtpScriptTransform.
|
|
326
330
|
// @ts-ignore
|
|
327
331
|
if (self.RTCTransformEvent) {
|
|
328
|
-
workerLogger.debug('setup transform event');
|
|
329
332
|
// @ts-ignore
|
|
330
333
|
self.onrtctransform = (event: RTCTransformEvent) => {
|
|
331
334
|
// @ts-ignore
|
|
332
335
|
const transformer = event.transformer;
|
|
333
|
-
workerLogger.debug('transformer', transformer);
|
|
334
|
-
|
|
335
336
|
const { kind, participantIdentity, trackId, codec } =
|
|
336
337
|
transformer.options as ScriptTransformOptions;
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
338
|
+
messageQueue.run(async () => {
|
|
339
|
+
const cryptor = getTrackCryptor(participantIdentity, trackId);
|
|
340
|
+
workerLogger.debug('onrtctransform setup', { participantIdentity, trackId, codec });
|
|
341
|
+
cryptor.setupTransform(
|
|
342
|
+
kind,
|
|
343
|
+
transformer.readable,
|
|
344
|
+
transformer.writable,
|
|
345
|
+
trackId,
|
|
346
|
+
false,
|
|
347
|
+
codec,
|
|
348
|
+
);
|
|
349
|
+
});
|
|
340
350
|
};
|
|
341
351
|
}
|
package/src/index.ts
CHANGED
|
@@ -9,11 +9,18 @@ import {
|
|
|
9
9
|
import { LogLevel, LoggerNames, getLogger, setLogExtension, setLogLevel } from './logger';
|
|
10
10
|
import DefaultReconnectPolicy from './room/DefaultReconnectPolicy';
|
|
11
11
|
import type { ReconnectContext, ReconnectPolicy } from './room/ReconnectPolicy';
|
|
12
|
-
import Room, { ConnectionState } from './room/Room';
|
|
13
|
-
import type { RoomEventCallbacks } from './room/Room';
|
|
12
|
+
import Room, { ConnectionState, type RoomEventCallbacks } from './room/Room';
|
|
14
13
|
import * as attributes from './room/attribute-typings';
|
|
14
|
+
// FIXME: remove this import in a follow up data track pull request.
|
|
15
|
+
import './room/data-track/depacketizer';
|
|
16
|
+
// FIXME: remove this import in a follow up data track pull request.
|
|
17
|
+
import './room/data-track/outgoing/OutgoingDataTrackManager';
|
|
15
18
|
import LocalParticipant from './room/participant/LocalParticipant';
|
|
16
|
-
import Participant, {
|
|
19
|
+
import Participant, {
|
|
20
|
+
ConnectionQuality,
|
|
21
|
+
type ParticipantEventCallbacks,
|
|
22
|
+
ParticipantKind,
|
|
23
|
+
} from './room/participant/Participant';
|
|
17
24
|
import type { ParticipantTrackPermission } from './room/participant/ParticipantTrackPermission';
|
|
18
25
|
import RemoteParticipant from './room/participant/RemoteParticipant';
|
|
19
26
|
import type {
|
|
@@ -32,8 +39,8 @@ import RemoteTrack from './room/track/RemoteTrack';
|
|
|
32
39
|
import RemoteTrackPublication from './room/track/RemoteTrackPublication';
|
|
33
40
|
import type { ElementInfo } from './room/track/RemoteVideoTrack';
|
|
34
41
|
import RemoteVideoTrack from './room/track/RemoteVideoTrack';
|
|
35
|
-
import { TrackPublication } from './room/track/TrackPublication';
|
|
36
|
-
import type { LiveKitReactNativeInfo } from './room/types';
|
|
42
|
+
import { type PublicationEventCallbacks, TrackPublication } from './room/track/TrackPublication';
|
|
43
|
+
import type { LiveKitReactNativeInfo, TextStreamInfo } from './room/types';
|
|
37
44
|
import type { AudioAnalyserOptions } from './room/utils';
|
|
38
45
|
import {
|
|
39
46
|
compareVersions,
|
|
@@ -140,6 +147,7 @@ export type {
|
|
|
140
147
|
AudioAnalyserOptions,
|
|
141
148
|
ElementInfo,
|
|
142
149
|
LiveKitReactNativeInfo,
|
|
150
|
+
TextStreamInfo,
|
|
143
151
|
ParticipantTrackPermission,
|
|
144
152
|
AudioReceiverStats,
|
|
145
153
|
AudioSenderStats,
|
|
@@ -148,6 +156,8 @@ export type {
|
|
|
148
156
|
ReconnectContext,
|
|
149
157
|
ReconnectPolicy,
|
|
150
158
|
RoomEventCallbacks,
|
|
159
|
+
ParticipantEventCallbacks,
|
|
160
|
+
PublicationEventCallbacks,
|
|
151
161
|
};
|
|
152
162
|
export { DataTrackPacket, type DataTrackPacketHeader } from './room/data-track/packet';
|
|
153
163
|
export {
|
package/src/logger.ts
CHANGED
package/src/room/PCTransport.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Mutex } from '@livekit/mutex';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import { parse, write } from 'sdp-transform';
|
|
4
|
-
import { debounce } from 'ts-debounce';
|
|
5
4
|
import type { MediaDescription, SessionDescription } from 'sdp-transform';
|
|
6
5
|
import log, { LoggerNames, getLogger } from '../logger';
|
|
6
|
+
import { debounce } from './debounce';
|
|
7
7
|
import { NegotiationError, UnexpectedConnectionState } from './errors';
|
|
8
8
|
import type { LoggerOptions } from './types';
|
|
9
9
|
import { ddExtensionURI, isSVCCodec, isSafari } from './utils';
|
|
@@ -278,6 +278,7 @@ export default class PCTransport extends EventEmitter {
|
|
|
278
278
|
await this._pc.setRemoteDescription(currentSD);
|
|
279
279
|
} else {
|
|
280
280
|
this.renegotiate = true;
|
|
281
|
+
this.log.debug('requesting renegotiation', { ...this.logContext });
|
|
281
282
|
return;
|
|
282
283
|
}
|
|
283
284
|
} else if (!this._pc || this._pc.signalingState === 'closed') {
|
|
@@ -229,28 +229,46 @@ export class PCTransportManager {
|
|
|
229
229
|
|
|
230
230
|
async negotiate(abortController: AbortController) {
|
|
231
231
|
return new TypedPromise<void, NegotiationError | Error>(async (resolve, reject) => {
|
|
232
|
-
|
|
232
|
+
let negotiationTimeout = setTimeout(() => {
|
|
233
233
|
reject(new NegotiationError('negotiation timed out'));
|
|
234
234
|
}, this.peerConnectionTimeout);
|
|
235
235
|
|
|
236
|
-
const
|
|
236
|
+
const cleanup = () => {
|
|
237
237
|
clearTimeout(negotiationTimeout);
|
|
238
|
+
this.publisher.off(PCEvents.NegotiationStarted, onNegotiationStarted);
|
|
239
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const abortHandler = () => {
|
|
243
|
+
cleanup();
|
|
238
244
|
reject(new NegotiationError('negotiation aborted'));
|
|
239
245
|
};
|
|
240
246
|
|
|
241
|
-
|
|
242
|
-
|
|
247
|
+
// Reset the timeout each time a renegotiation cycle starts. This
|
|
248
|
+
// prevents premature timeouts when the negotiation machinery is
|
|
249
|
+
// actively renegotiating (offers going out, answers coming back) but
|
|
250
|
+
// NegotiationComplete hasn't fired yet because new requirements keep
|
|
251
|
+
// arriving between offer/answer round-trips.
|
|
252
|
+
const onNegotiationStarted = () => {
|
|
243
253
|
if (abortController.signal.aborted) {
|
|
244
254
|
return;
|
|
245
255
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
256
|
+
clearTimeout(negotiationTimeout);
|
|
257
|
+
negotiationTimeout = setTimeout(() => {
|
|
258
|
+
cleanup();
|
|
259
|
+
reject(new NegotiationError('negotiation timed out'));
|
|
260
|
+
}, this.peerConnectionTimeout);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
abortController.signal.addEventListener('abort', abortHandler);
|
|
264
|
+
this.publisher.on(PCEvents.NegotiationStarted, onNegotiationStarted);
|
|
265
|
+
this.publisher.once(PCEvents.NegotiationComplete, () => {
|
|
266
|
+
cleanup();
|
|
267
|
+
resolve();
|
|
250
268
|
});
|
|
251
269
|
|
|
252
270
|
await this.publisher.negotiate((e) => {
|
|
253
|
-
|
|
271
|
+
cleanup();
|
|
254
272
|
if (e instanceof Error) {
|
|
255
273
|
reject(e);
|
|
256
274
|
} else {
|
package/src/room/RTCEngine.ts
CHANGED
|
@@ -1477,8 +1477,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1477
1477
|
if (!this.pcManager) {
|
|
1478
1478
|
return false;
|
|
1479
1479
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1480
|
+
const allowedConnectionStates: PCTransportState[] = [
|
|
1481
|
+
PCTransportState.CONNECTING,
|
|
1482
|
+
PCTransportState.CONNECTED,
|
|
1483
|
+
];
|
|
1484
|
+
if (!allowedConnectionStates.includes(this.pcManager.currentState)) {
|
|
1482
1485
|
return false;
|
|
1483
1486
|
}
|
|
1484
1487
|
|
|
@@ -1521,6 +1524,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1521
1524
|
reject(new NegotiationError('cannot negotiate on closed engine'));
|
|
1522
1525
|
}
|
|
1523
1526
|
this.on(EngineEvent.Closing, handleClosed);
|
|
1527
|
+
this.on(EngineEvent.Restarting, handleClosed);
|
|
1524
1528
|
|
|
1525
1529
|
this.pcManager.publisher.once(
|
|
1526
1530
|
PCEvents.RTPVideoPayloadTypes,
|
|
@@ -1540,6 +1544,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1540
1544
|
await this.pcManager.negotiate(abortController);
|
|
1541
1545
|
resolve();
|
|
1542
1546
|
} catch (e: unknown) {
|
|
1547
|
+
if (abortController.signal.aborted) {
|
|
1548
|
+
// negotiation was aborted due to engine close or restart, resolve
|
|
1549
|
+
// cleanly to avoid triggering a cascading reconnect loop
|
|
1550
|
+
resolve();
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1543
1553
|
if (e instanceof NegotiationError) {
|
|
1544
1554
|
this.fullReconnectOnNext = true;
|
|
1545
1555
|
}
|
|
@@ -1551,6 +1561,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
|
1551
1561
|
}
|
|
1552
1562
|
} finally {
|
|
1553
1563
|
this.off(EngineEvent.Closing, handleClosed);
|
|
1564
|
+
this.off(EngineEvent.Restarting, handleClosed);
|
|
1554
1565
|
}
|
|
1555
1566
|
});
|
|
1556
1567
|
}
|
package/src/room/Room.ts
CHANGED
|
@@ -740,7 +740,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
|
740
740
|
`Initial connection failed with ConnectionError: ${error.message}. Retrying with another region: ${nextUrl}`,
|
|
741
741
|
this.logContext,
|
|
742
742
|
);
|
|
743
|
-
this.recreateEngine();
|
|
743
|
+
this.recreateEngine(true);
|
|
744
744
|
await connectFn(resolve, reject, nextUrl);
|
|
745
745
|
} else {
|
|
746
746
|
this.handleDisconnect(
|
|
@@ -866,7 +866,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
|
866
866
|
) {
|
|
867
867
|
this.log.info('Reconnection attempt replaced by new connection attempt', this.logContext);
|
|
868
868
|
// make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
|
|
869
|
-
this.recreateEngine();
|
|
869
|
+
this.recreateEngine(true);
|
|
870
870
|
} else {
|
|
871
871
|
// create engine if previously disconnected
|
|
872
872
|
this.maybeCreateEngine();
|
|
@@ -1380,8 +1380,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
|
1380
1380
|
);
|
|
1381
1381
|
}
|
|
1382
1382
|
|
|
1383
|
-
private recreateEngine() {
|
|
1384
|
-
this.engine
|
|
1383
|
+
private recreateEngine(sendLeave?: boolean) {
|
|
1384
|
+
const oldEngine = this.engine;
|
|
1385
|
+
|
|
1386
|
+
if (sendLeave && oldEngine && !oldEngine.client.isDisconnected) {
|
|
1387
|
+
oldEngine.client.sendLeave().finally(() => oldEngine.close());
|
|
1388
|
+
} else {
|
|
1389
|
+
oldEngine?.close();
|
|
1390
|
+
}
|
|
1385
1391
|
/* @ts-ignore */
|
|
1386
1392
|
this.engine = undefined;
|
|
1387
1393
|
this.isResuming = false;
|
|
@@ -2307,7 +2313,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
|
2307
2313
|
engine: this.engine
|
|
2308
2314
|
? {
|
|
2309
2315
|
closed: this.engine.isClosed,
|
|
2310
|
-
|
|
2316
|
+
transportsConnectedOrConnecting: this.engine.verifyTransport(),
|
|
2311
2317
|
}
|
|
2312
2318
|
: undefined,
|
|
2313
2319
|
});
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import log from '../../../logger';
|
|
9
9
|
import { DataStreamError, DataStreamErrorReason } from '../../errors';
|
|
10
10
|
import { type ByteStreamInfo, type StreamController, type TextStreamInfo } from '../../types';
|
|
11
|
-
import {
|
|
11
|
+
import { bigIntToNumber } from '../../utils';
|
|
12
12
|
import {
|
|
13
13
|
type ByteStreamHandler,
|
|
14
14
|
ByteStreamReader,
|
|
@@ -78,11 +78,11 @@ export default class IncomingDataStreamManager {
|
|
|
78
78
|
DataStreamErrorReason.AbnormalEnd,
|
|
79
79
|
);
|
|
80
80
|
for (const [id, controller] of byteStreamsBeingSentByDisconnectingParticipant) {
|
|
81
|
-
controller.
|
|
81
|
+
controller.controller.error(abnormalEndError);
|
|
82
82
|
this.byteStreamControllers.delete(id);
|
|
83
83
|
}
|
|
84
84
|
for (const [id, controller] of textStreamsBeingSentByDisconnectingParticipant) {
|
|
85
|
-
controller.
|
|
85
|
+
controller.controller.error(abnormalEndError);
|
|
86
86
|
this.textStreamControllers.delete(id);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -121,10 +121,6 @@ export default class IncomingDataStreamManager {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
let streamController: ReadableStreamDefaultController<DataStream_Chunk>;
|
|
124
|
-
const outOfBandFailureRejectingFuture = new Future<never, Error>();
|
|
125
|
-
outOfBandFailureRejectingFuture.promise.catch((err) => {
|
|
126
|
-
this.log.error(err);
|
|
127
|
-
});
|
|
128
124
|
|
|
129
125
|
const info: ByteStreamInfo = {
|
|
130
126
|
id: streamHeader.streamId,
|
|
@@ -152,17 +148,11 @@ export default class IncomingDataStreamManager {
|
|
|
152
148
|
controller: streamController,
|
|
153
149
|
startTime: Date.now(),
|
|
154
150
|
sendingParticipantIdentity: participantIdentity,
|
|
155
|
-
outOfBandFailureRejectingFuture,
|
|
156
151
|
});
|
|
157
152
|
},
|
|
158
153
|
});
|
|
159
154
|
streamHandlerCallback(
|
|
160
|
-
new ByteStreamReader(
|
|
161
|
-
info,
|
|
162
|
-
stream,
|
|
163
|
-
bigIntToNumber(streamHeader.totalLength),
|
|
164
|
-
outOfBandFailureRejectingFuture,
|
|
165
|
-
),
|
|
155
|
+
new ByteStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)),
|
|
166
156
|
{
|
|
167
157
|
identity: participantIdentity,
|
|
168
158
|
},
|
|
@@ -178,10 +168,6 @@ export default class IncomingDataStreamManager {
|
|
|
178
168
|
}
|
|
179
169
|
|
|
180
170
|
let streamController: ReadableStreamDefaultController<DataStream_Chunk>;
|
|
181
|
-
const outOfBandFailureRejectingFuture = new Future<never, Error>();
|
|
182
|
-
outOfBandFailureRejectingFuture.promise.catch((err) => {
|
|
183
|
-
this.log.error(err);
|
|
184
|
-
});
|
|
185
171
|
|
|
186
172
|
const info: TextStreamInfo = {
|
|
187
173
|
id: streamHeader.streamId,
|
|
@@ -210,17 +196,11 @@ export default class IncomingDataStreamManager {
|
|
|
210
196
|
controller: streamController,
|
|
211
197
|
startTime: Date.now(),
|
|
212
198
|
sendingParticipantIdentity: participantIdentity,
|
|
213
|
-
outOfBandFailureRejectingFuture,
|
|
214
199
|
});
|
|
215
200
|
},
|
|
216
201
|
});
|
|
217
202
|
streamHandlerCallback(
|
|
218
|
-
new TextStreamReader(
|
|
219
|
-
info,
|
|
220
|
-
stream,
|
|
221
|
-
bigIntToNumber(streamHeader.totalLength),
|
|
222
|
-
outOfBandFailureRejectingFuture,
|
|
223
|
-
),
|
|
203
|
+
new TextStreamReader(info, stream, bigIntToNumber(streamHeader.totalLength)),
|
|
224
204
|
{ identity: participantIdentity },
|
|
225
205
|
);
|
|
226
206
|
}
|