livekit-client 2.0.1 → 2.0.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/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 +53 -18
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +94 -57
- 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/KeyProvider.d.ts +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +1 -0
- package/dist/src/e2ee/worker/FrameCryptor.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/room/Room.d.ts +1 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +5 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +8 -7
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +11 -9
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +2 -2
- package/dist/src/room/track/LocalVideoTrack.d.ts +3 -3
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrack.d.ts +2 -2
- package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +5 -3
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/processor/types.d.ts +4 -0
- package/dist/src/room/track/processor/types.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +1 -1
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +1 -0
- package/dist/ts4.2/src/e2ee/worker/ParticipantKeyHandler.d.ts +2 -2
- package/dist/ts4.2/src/room/Room.d.ts +1 -0
- package/dist/ts4.2/src/room/events.d.ts +5 -1
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +8 -7
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +11 -9
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -2
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +3 -3
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -2
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +5 -3
- package/dist/ts4.2/src/room/track/processor/types.d.ts +4 -0
- package/package.json +1 -1
- package/src/api/SignalClient.ts +1 -1
- package/src/e2ee/KeyProvider.ts +6 -1
- package/src/e2ee/worker/FrameCryptor.ts +26 -0
- package/src/e2ee/worker/ParticipantKeyHandler.ts +9 -5
- package/src/e2ee/worker/e2ee.worker.ts +17 -14
- package/src/room/Room.ts +21 -4
- package/src/room/events.ts +4 -0
- package/src/room/participant/LocalParticipant.ts +0 -1
- package/src/room/track/LocalAudioTrack.ts +9 -11
- package/src/room/track/LocalTrack.ts +78 -56
- package/src/room/track/LocalVideoTrack.ts +3 -3
- package/src/room/track/RemoteAudioTrack.ts +1 -1
- package/src/room/track/RemoteTrack.ts +4 -2
- package/src/room/track/RemoteVideoTrack.ts +1 -1
- package/src/room/track/Track.ts +7 -3
- package/src/room/track/processor/types.ts +4 -0
@@ -3,7 +3,7 @@ import { Mutex } from '../utils';
|
|
3
3
|
import { Track } from './Track';
|
4
4
|
import type { VideoCodec } from './options';
|
5
5
|
import type { TrackProcessor } from './processor/types';
|
6
|
-
export default abstract class LocalTrack extends Track {
|
6
|
+
export default abstract class LocalTrack<TrackKind extends Track.Kind = Track.Kind> extends Track<TrackKind> {
|
7
7
|
/** @internal */
|
8
8
|
sender?: RTCRtpSender;
|
9
9
|
/** @internal */
|
@@ -15,8 +15,10 @@ export default abstract class LocalTrack extends Track {
|
|
15
15
|
protected muteLock: Mutex;
|
16
16
|
protected pauseUpstreamLock: Mutex;
|
17
17
|
protected processorElement?: HTMLMediaElement;
|
18
|
-
protected processor?: TrackProcessor<
|
18
|
+
protected processor?: TrackProcessor<TrackKind, any>;
|
19
19
|
protected processorLock: Mutex;
|
20
|
+
protected audioContext?: AudioContext;
|
21
|
+
private restartLock;
|
20
22
|
/**
|
21
23
|
*
|
22
24
|
* @param mediaTrack
|
@@ -24,7 +26,7 @@ export default abstract class LocalTrack extends Track {
|
|
24
26
|
* @param constraints MediaTrackConstraints that are being used when restarting or reacquiring tracks
|
25
27
|
* @param userProvidedTrack Signals to the SDK whether or not the mediaTrack should be managed (i.e. released and reacquired) internally by the SDK
|
26
28
|
*/
|
27
|
-
protected constructor(mediaTrack: MediaStreamTrack, kind:
|
29
|
+
protected constructor(mediaTrack: MediaStreamTrack, kind: TrackKind, constraints?: MediaTrackConstraints, userProvidedTrack?: boolean, loggerOptions?: LoggerOptions);
|
28
30
|
get id(): string;
|
29
31
|
get dimensions(): Track.Dimensions | undefined;
|
30
32
|
private _isUpstreamPaused;
|
@@ -37,10 +39,10 @@ export default abstract class LocalTrack extends Track {
|
|
37
39
|
* @returns DeviceID of the device that is currently being used for this track
|
38
40
|
*/
|
39
41
|
getDeviceId(): Promise<string | undefined>;
|
40
|
-
mute(): Promise<
|
41
|
-
unmute(): Promise<
|
42
|
-
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<
|
43
|
-
protected restart(constraints?: MediaTrackConstraints): Promise<
|
42
|
+
mute(): Promise<this>;
|
43
|
+
unmute(): Promise<this>;
|
44
|
+
replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<this>;
|
45
|
+
protected restart(constraints?: MediaTrackConstraints): Promise<this>;
|
44
46
|
protected setTrackMuted(muted: boolean): void;
|
45
47
|
protected get needsReAcquisition(): boolean;
|
46
48
|
protected handleAppVisibilityChanged(): Promise<void>;
|
@@ -74,8 +76,8 @@ export default abstract class LocalTrack extends Track {
|
|
74
76
|
* @param showProcessedStreamLocally
|
75
77
|
* @returns
|
76
78
|
*/
|
77
|
-
setProcessor(processor: TrackProcessor<
|
78
|
-
getProcessor(): TrackProcessor<
|
79
|
+
setProcessor(processor: TrackProcessor<TrackKind>, showProcessedStreamLocally?: boolean): Promise<void>;
|
80
|
+
getProcessor(): TrackProcessor<TrackKind, any> | undefined;
|
79
81
|
/**
|
80
82
|
* Stops the track processor
|
81
83
|
* See https://github.com/livekit/track-processors-js for example usage
|
@@ -18,11 +18,11 @@ export default class LocalTrackPublication extends TrackPublication {
|
|
18
18
|
/**
|
19
19
|
* Mute the track associated with this publication
|
20
20
|
*/
|
21
|
-
mute(): Promise<LocalTrack | undefined>;
|
21
|
+
mute(): Promise<LocalTrack<Track.Kind> | undefined>;
|
22
22
|
/**
|
23
23
|
* Unmute track associated with this publication
|
24
24
|
*/
|
25
|
-
unmute(): Promise<LocalTrack | undefined>;
|
25
|
+
unmute(): Promise<LocalTrack<Track.Kind> | undefined>;
|
26
26
|
/**
|
27
27
|
* Pauses the media stream track associated with this publication from being sent to the server
|
28
28
|
* and signals "muted" event to other participants
|
@@ -14,7 +14,7 @@ export declare class SimulcastTrackInfo {
|
|
14
14
|
encodings?: RTCRtpEncodingParameters[];
|
15
15
|
constructor(codec: VideoCodec, mediaStreamTrack: MediaStreamTrack);
|
16
16
|
}
|
17
|
-
export default class LocalVideoTrack extends LocalTrack {
|
17
|
+
export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
18
18
|
signalClient?: SignalClient;
|
19
19
|
private prevStats?;
|
20
20
|
private encodings?;
|
@@ -33,8 +33,8 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
33
33
|
stop(): void;
|
34
34
|
pauseUpstream(): Promise<void>;
|
35
35
|
resumeUpstream(): Promise<void>;
|
36
|
-
mute(): Promise<
|
37
|
-
unmute(): Promise<
|
36
|
+
mute(): Promise<typeof this>;
|
37
|
+
unmute(): Promise<typeof this>;
|
38
38
|
protected setTrackMuted(muted: boolean): void;
|
39
39
|
getSenderStats(): Promise<VideoSenderStats[]>;
|
40
40
|
setPublishingQuality(maxQuality: VideoQuality): void;
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import type { AudioReceiverStats } from '../stats';
|
2
2
|
import type { LoggerOptions } from '../types';
|
3
3
|
import RemoteTrack from './RemoteTrack';
|
4
|
+
import { Track } from './Track';
|
4
5
|
import type { AudioOutputOptions } from './options';
|
5
|
-
export default class RemoteAudioTrack extends RemoteTrack {
|
6
|
+
export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
6
7
|
private prevStats?;
|
7
8
|
private elementVolume;
|
8
9
|
private audioContext?;
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import type { LoggerOptions } from '../types';
|
2
2
|
import { Track } from './Track';
|
3
|
-
export default abstract class RemoteTrack extends Track {
|
3
|
+
export default abstract class RemoteTrack<TrackKind extends Track.Kind = Track.Kind> extends Track<TrackKind> {
|
4
4
|
/** @internal */
|
5
5
|
receiver?: RTCRtpReceiver;
|
6
|
-
constructor(mediaTrack: MediaStreamTrack, sid: string, kind:
|
6
|
+
constructor(mediaTrack: MediaStreamTrack, sid: string, kind: TrackKind, receiver?: RTCRtpReceiver, loggerOptions?: LoggerOptions);
|
7
7
|
/** @internal */
|
8
8
|
setMuted(muted: boolean): void;
|
9
9
|
/** @internal */
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import type { LoggerOptions } from '../types';
|
2
2
|
import RemoteTrack from './RemoteTrack';
|
3
|
+
import { Track } from './Track';
|
3
4
|
import type { AdaptiveStreamSettings } from './types';
|
4
|
-
export default class RemoteVideoTrack extends RemoteTrack {
|
5
|
+
export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
|
5
6
|
private prevStats?;
|
6
7
|
private elementInfos;
|
7
8
|
private adaptiveStreamSettings?;
|
@@ -4,14 +4,15 @@ import { StructuredLogger } from '../../logger';
|
|
4
4
|
import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
|
5
5
|
import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
|
6
6
|
import type { LoggerOptions } from '../types';
|
7
|
+
import type { TrackProcessor } from './processor/types';
|
7
8
|
export declare enum VideoQuality {
|
8
9
|
LOW = 0,
|
9
10
|
MEDIUM = 1,
|
10
11
|
HIGH = 2
|
11
12
|
}
|
12
13
|
declare const Track_base: new () => TypedEventEmitter<TrackEventCallbacks>;
|
13
|
-
export declare abstract class Track extends Track_base {
|
14
|
-
kind:
|
14
|
+
export declare abstract class Track<TrackKind extends Track.Kind = Track.Kind> extends Track_base {
|
15
|
+
readonly kind: TrackKind;
|
15
16
|
attachedElements: HTMLMediaElement[];
|
16
17
|
isMuted: boolean;
|
17
18
|
source: Track.Source;
|
@@ -36,7 +37,7 @@ export declare abstract class Track extends Track_base {
|
|
36
37
|
protected _currentBitrate: number;
|
37
38
|
protected monitorInterval?: ReturnType<typeof setInterval>;
|
38
39
|
protected log: StructuredLogger;
|
39
|
-
protected constructor(mediaTrack: MediaStreamTrack, kind:
|
40
|
+
protected constructor(mediaTrack: MediaStreamTrack, kind: TrackKind, loggerOptions?: LoggerOptions);
|
40
41
|
protected get logContext(): {
|
41
42
|
[x: string]: unknown;
|
42
43
|
};
|
@@ -135,6 +136,7 @@ export type TrackEventCallbacks = {
|
|
135
136
|
elementDetached: (element: HTMLMediaElement) => void;
|
136
137
|
upstreamPaused: (track: any) => void;
|
137
138
|
upstreamResumed: (track: any) => void;
|
139
|
+
trackProcessorUpdate: (processor?: TrackProcessor<Track.Kind, any>) => void;
|
138
140
|
};
|
139
141
|
export {};
|
140
142
|
//# sourceMappingURL=Track.d.ts.map
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import type Room from '../../Room';
|
1
2
|
import type { Track } from '../Track';
|
2
3
|
/**
|
3
4
|
* @experimental
|
@@ -6,6 +7,7 @@ export type ProcessorOptions<T extends Track.Kind> = {
|
|
6
7
|
kind: T;
|
7
8
|
track: MediaStreamTrack;
|
8
9
|
element?: HTMLMediaElement;
|
10
|
+
audioContext?: AudioContext;
|
9
11
|
};
|
10
12
|
/**
|
11
13
|
* @experimental
|
@@ -27,5 +29,7 @@ export interface TrackProcessor<T extends Track.Kind, U extends ProcessorOptions
|
|
27
29
|
restart: (opts: U) => Promise<void>;
|
28
30
|
destroy: () => Promise<void>;
|
29
31
|
processedTrack?: MediaStreamTrack;
|
32
|
+
onPublish?: (room: Room) => Promise<void>;
|
33
|
+
onUnpublish?: () => Promise<void>;
|
30
34
|
}
|
31
35
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
package/src/api/SignalClient.ts
CHANGED
@@ -317,7 +317,7 @@ export class SignalClient {
|
|
317
317
|
let resp: SignalResponse;
|
318
318
|
if (typeof ev.data === 'string') {
|
319
319
|
const json = JSON.parse(ev.data);
|
320
|
-
resp = SignalResponse.fromJson(json);
|
320
|
+
resp = SignalResponse.fromJson(json, { ignoreUnknownFields: true });
|
321
321
|
} else if (ev.data instanceof ArrayBuffer) {
|
322
322
|
resp = SignalResponse.fromBinary(new Uint8Array(ev.data));
|
323
323
|
} else {
|
package/src/e2ee/KeyProvider.ts
CHANGED
@@ -12,7 +12,7 @@ import { createKeyMaterialFromBuffer, createKeyMaterialFromString } from './util
|
|
12
12
|
export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitter<KeyProviderCallbacks>) {
|
13
13
|
private keyInfoMap: Map<string, KeyInfo>;
|
14
14
|
|
15
|
-
private options: KeyProviderOptions;
|
15
|
+
private readonly options: KeyProviderOptions;
|
16
16
|
|
17
17
|
constructor(options: Partial<KeyProviderOptions> = {}) {
|
18
18
|
super();
|
@@ -29,6 +29,11 @@ export class BaseKeyProvider extends (EventEmitter as new () => TypedEventEmitte
|
|
29
29
|
*/
|
30
30
|
protected onSetEncryptionKey(key: CryptoKey, participantIdentity?: string, keyIndex?: number) {
|
31
31
|
const keyInfo: KeyInfo = { key, participantIdentity, keyIndex };
|
32
|
+
if (!this.options.sharedKey && !participantIdentity) {
|
33
|
+
throw new Error(
|
34
|
+
'participant identity needs to be passed for encryption key if sharedKey option is false',
|
35
|
+
);
|
36
|
+
}
|
32
37
|
this.keyInfoMap.set(`${participantIdentity ?? 'shared'}-${keyIndex ?? 0}`, keyInfo);
|
33
38
|
this.emit(KeyProviderEvent.SetKey, keyInfo);
|
34
39
|
}
|
@@ -83,6 +83,14 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
83
83
|
this.sifGuard = new SifGuard();
|
84
84
|
}
|
85
85
|
|
86
|
+
private get logContext() {
|
87
|
+
return {
|
88
|
+
identity: this.participantIdentity,
|
89
|
+
trackId: this.trackId,
|
90
|
+
fallbackCodec: this.videoCodec,
|
91
|
+
};
|
92
|
+
}
|
93
|
+
|
86
94
|
/**
|
87
95
|
* Assign a different participant to the cryptor.
|
88
96
|
* useful for transceiver re-use
|
@@ -96,6 +104,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
96
104
|
}
|
97
105
|
|
98
106
|
unsetParticipant() {
|
107
|
+
workerLogger.debug('unsetting participant', this.logContext);
|
99
108
|
this.participantIdentity = undefined;
|
100
109
|
}
|
101
110
|
|
@@ -143,6 +152,13 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
143
152
|
this.videoCodec = codec;
|
144
153
|
}
|
145
154
|
|
155
|
+
workerLogger.debug('Setting up frame cryptor transform', {
|
156
|
+
operation,
|
157
|
+
passedTrackId: trackId,
|
158
|
+
codec,
|
159
|
+
...this.logContext,
|
160
|
+
});
|
161
|
+
|
146
162
|
const transformFn = operation === 'encode' ? this.encodeFunction : this.decodeFunction;
|
147
163
|
const transformStream = new TransformStream({
|
148
164
|
transform: transformFn.bind(this),
|
@@ -159,6 +175,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
159
175
|
}
|
160
176
|
|
161
177
|
setSifTrailer(trailer: Uint8Array) {
|
178
|
+
workerLogger.debug('setting SIF trailer', { ...this.logContext, trailer });
|
162
179
|
this.sifTrailer = trailer;
|
163
180
|
}
|
164
181
|
|
@@ -212,6 +229,8 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
212
229
|
encodedFrame.timestamp,
|
213
230
|
);
|
214
231
|
let frameInfo = this.getUnencryptedBytes(encodedFrame);
|
232
|
+
workerLogger.debug('frameInfo for encoded frame', { ...frameInfo, ...this.logContext });
|
233
|
+
|
215
234
|
// Thіs is not encrypted and contains the VP8 payload descriptor or the Opus TOC byte.
|
216
235
|
const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);
|
217
236
|
|
@@ -262,6 +281,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
262
281
|
workerLogger.error(e);
|
263
282
|
}
|
264
283
|
} else {
|
284
|
+
workerLogger.debug('failed to decrypt, emitting error', this.logContext);
|
265
285
|
this.emit(
|
266
286
|
CryptorEvent.Error,
|
267
287
|
new CryptorError(`encryption key missing for encoding`, CryptorErrorReason.MissingKey),
|
@@ -284,11 +304,13 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
284
304
|
// skip for decryption for empty dtx frames
|
285
305
|
encodedFrame.data.byteLength === 0
|
286
306
|
) {
|
307
|
+
workerLogger.debug('skipping empty frame', this.logContext);
|
287
308
|
this.sifGuard.recordUserFrame();
|
288
309
|
return controller.enqueue(encodedFrame);
|
289
310
|
}
|
290
311
|
|
291
312
|
if (isFrameServerInjected(encodedFrame.data, this.sifTrailer)) {
|
313
|
+
workerLogger.debug('enqueue SIF', this.logContext);
|
292
314
|
this.sifGuard.recordSif();
|
293
315
|
|
294
316
|
if (this.sifGuard.isSifAllowed()) {
|
@@ -312,6 +334,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
312
334
|
const decodedFrame = await this.decryptFrame(encodedFrame, keyIndex);
|
313
335
|
this.keys.decryptionSuccess();
|
314
336
|
if (decodedFrame) {
|
337
|
+
workerLogger.debug('enqueue decrypted frame', this.logContext);
|
315
338
|
return controller.enqueue(decodedFrame);
|
316
339
|
}
|
317
340
|
} catch (error) {
|
@@ -352,6 +375,8 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
352
375
|
throw new TypeError(`no encryption key found for decryption of ${this.participantIdentity}`);
|
353
376
|
}
|
354
377
|
let frameInfo = this.getUnencryptedBytes(encodedFrame);
|
378
|
+
workerLogger.debug('frameInfo for decoded frame', { ...frameInfo, ...this.logContext });
|
379
|
+
|
355
380
|
// Construct frame trailer. Similar to the frame header described in
|
356
381
|
// https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2
|
357
382
|
// but we put it at the end.
|
@@ -566,6 +591,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
566
591
|
// @ts-expect-error payloadType is not yet part of the typescript definition and currently not supported in Safari
|
567
592
|
const payloadType = frame.getMetadata().payloadType;
|
568
593
|
const codec = payloadType ? this.rtpMap.get(payloadType) : undefined;
|
594
|
+
workerLogger.debug('reading codec from frame', { codec, ...this.logContext });
|
569
595
|
return codec;
|
570
596
|
}
|
571
597
|
}
|
@@ -133,15 +133,19 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
133
133
|
|
134
134
|
/**
|
135
135
|
* takes in a key material with `deriveBits` and `deriveKey` set as key usages
|
136
|
-
* and derives encryption keys from the material and sets it on the key ring
|
136
|
+
* and derives encryption keys from the material and sets it on the key ring buffers
|
137
137
|
* together with the material
|
138
138
|
* also updates the currentKeyIndex
|
139
139
|
*/
|
140
|
-
async setKeyFromMaterial(material: CryptoKey, keyIndex
|
141
|
-
const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : -1;
|
142
|
-
workerLogger.debug(`setting new key with index ${newIndex}`);
|
140
|
+
async setKeyFromMaterial(material: CryptoKey, keyIndex: number, emitRatchetEvent = false) {
|
143
141
|
const keySet = await deriveKeys(material, this.keyProviderOptions.ratchetSalt);
|
144
|
-
|
142
|
+
const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : this.currentKeyIndex;
|
143
|
+
workerLogger.debug(`setting new key with index ${keyIndex}`, {
|
144
|
+
usage: material.usages,
|
145
|
+
algorithm: material.algorithm,
|
146
|
+
ratchetSalt: this.keyProviderOptions.ratchetSalt,
|
147
|
+
});
|
148
|
+
this.setKeySet(keySet, newIndex, emitRatchetEvent);
|
145
149
|
if (newIndex >= 0) this.currentKeyIndex = newIndex;
|
146
150
|
}
|
147
151
|
|
@@ -21,8 +21,6 @@ let isEncryptionEnabled: boolean = false;
|
|
21
21
|
|
22
22
|
let useSharedKey: boolean = false;
|
23
23
|
|
24
|
-
let sharedKey: CryptoKey | undefined;
|
25
|
-
|
26
24
|
let sifTrailer: Uint8Array | undefined;
|
27
25
|
|
28
26
|
let keyProviderOptions: KeyProviderOptions = KEY_PROVIDER_DEFAULTS;
|
@@ -72,10 +70,9 @@ onmessage = (ev) => {
|
|
72
70
|
break;
|
73
71
|
case 'setKey':
|
74
72
|
if (useSharedKey) {
|
75
|
-
workerLogger.warn('set shared key');
|
76
73
|
setSharedKey(data.key, data.keyIndex);
|
77
74
|
} else if (data.participantIdentity) {
|
78
|
-
workerLogger.
|
75
|
+
workerLogger.info(
|
79
76
|
`set participant sender key ${data.participantIdentity} index ${data.keyIndex}`,
|
80
77
|
);
|
81
78
|
getParticipantKeyHandler(data.participantIdentity).setKey(data.key, data.keyIndex);
|
@@ -84,7 +81,7 @@ onmessage = (ev) => {
|
|
84
81
|
}
|
85
82
|
break;
|
86
83
|
case 'removeTransform':
|
87
|
-
unsetCryptorParticipant(data.trackId);
|
84
|
+
unsetCryptorParticipant(data.trackId, data.participantIdentity);
|
88
85
|
break;
|
89
86
|
case 'updateCodec':
|
90
87
|
getTrackCryptor(data.participantIdentity, data.trackId).setVideoCodec(data.codec);
|
@@ -144,8 +141,7 @@ function getTrackCryptor(participantIdentity: string, trackId: string) {
|
|
144
141
|
// assign new participant id to track cryptor and pass in correct key handler
|
145
142
|
cryptor.setParticipant(participantIdentity, getParticipantKeyHandler(participantIdentity));
|
146
143
|
}
|
147
|
-
|
148
|
-
}
|
144
|
+
|
149
145
|
return cryptor;
|
150
146
|
}
|
151
147
|
|
@@ -156,9 +152,6 @@ function getParticipantKeyHandler(participantIdentity: string) {
|
|
156
152
|
let keys = participantKeys.get(participantIdentity);
|
157
153
|
if (!keys) {
|
158
154
|
keys = new ParticipantKeyHandler(participantIdentity, keyProviderOptions);
|
159
|
-
if (sharedKey) {
|
160
|
-
keys.setKey(sharedKey);
|
161
|
-
}
|
162
155
|
keys.on(KeyHandlerEvent.KeyRatcheted, emitRatchetedKeys);
|
163
156
|
participantKeys.set(participantIdentity, keys);
|
164
157
|
}
|
@@ -167,22 +160,32 @@ function getParticipantKeyHandler(participantIdentity: string) {
|
|
167
160
|
|
168
161
|
function getSharedKeyHandler() {
|
169
162
|
if (!sharedKeyHandler) {
|
163
|
+
workerLogger.debug('creating new shared key handler');
|
170
164
|
sharedKeyHandler = new ParticipantKeyHandler('shared-key', keyProviderOptions);
|
171
165
|
}
|
172
166
|
return sharedKeyHandler;
|
173
167
|
}
|
174
168
|
|
175
|
-
function unsetCryptorParticipant(trackId: string) {
|
176
|
-
participantCryptors.find(
|
169
|
+
function unsetCryptorParticipant(trackId: string, participantIdentity: string) {
|
170
|
+
const cryptor = participantCryptors.find(
|
171
|
+
(c) => c.getParticipantIdentity() === participantIdentity && c.getTrackId() === trackId,
|
172
|
+
);
|
173
|
+
if (!cryptor) {
|
174
|
+
workerLogger.warn('Could not unset participant on cryptor', { trackId, participantIdentity });
|
175
|
+
} else {
|
176
|
+
cryptor.unsetParticipant();
|
177
|
+
}
|
177
178
|
}
|
178
179
|
|
179
180
|
function setEncryptionEnabled(enable: boolean, participantIdentity: string) {
|
181
|
+
workerLogger.debug(`setting encryption enabled for all tracks of ${participantIdentity}`, {
|
182
|
+
enable,
|
183
|
+
});
|
180
184
|
encryptionEnabledMap.set(participantIdentity, enable);
|
181
185
|
}
|
182
186
|
|
183
187
|
function setSharedKey(key: CryptoKey, index?: number) {
|
184
|
-
workerLogger.
|
185
|
-
sharedKey = key;
|
188
|
+
workerLogger.info('set shared key', { index });
|
186
189
|
getSharedKeyHandler().setKey(key, index);
|
187
190
|
}
|
188
191
|
|
package/src/room/Room.ts
CHANGED
@@ -60,6 +60,7 @@ import type RemoteTrack from './track/RemoteTrack';
|
|
60
60
|
import RemoteTrackPublication from './track/RemoteTrackPublication';
|
61
61
|
import { Track } from './track/Track';
|
62
62
|
import type { TrackPublication } from './track/TrackPublication';
|
63
|
+
import type { TrackProcessor } from './track/processor/types';
|
63
64
|
import type { AdaptiveStreamSettings } from './track/types';
|
64
65
|
import { getNewAudioContext, sourceToKind } from './track/utils';
|
65
66
|
import type { SimulationOptions, SimulationScenario } from './types';
|
@@ -573,16 +574,23 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
573
574
|
this.localParticipant.sid = pi.sid;
|
574
575
|
this.localParticipant.identity = pi.identity;
|
575
576
|
|
577
|
+
if (this.options.e2ee && this.e2eeManager) {
|
578
|
+
try {
|
579
|
+
this.e2eeManager.setSifTrailer(joinResponse.sifTrailer);
|
580
|
+
} catch (e: any) {
|
581
|
+
this.log.error(e instanceof Error ? e.message : 'Could not set SifTrailer', {
|
582
|
+
...this.logContext,
|
583
|
+
error: e,
|
584
|
+
});
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
576
588
|
// populate remote participants, these should not trigger new events
|
577
589
|
this.handleParticipantUpdates([pi, ...joinResponse.otherParticipants]);
|
578
590
|
|
579
591
|
if (joinResponse.room) {
|
580
592
|
this.handleRoomUpdate(joinResponse.room);
|
581
593
|
}
|
582
|
-
|
583
|
-
if (this.options.e2ee && this.e2eeManager) {
|
584
|
-
this.e2eeManager.setSifTrailer(joinResponse.sifTrailer);
|
585
|
-
}
|
586
594
|
};
|
587
595
|
|
588
596
|
private attemptConnection = async (
|
@@ -1775,8 +1783,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1775
1783
|
this.emit(RoomEvent.TrackUnmuted, pub, this.localParticipant);
|
1776
1784
|
};
|
1777
1785
|
|
1786
|
+
private onTrackProcessorUpdate = (processor?: TrackProcessor<Track.Kind, any>) => {
|
1787
|
+
processor?.onPublish?.(this);
|
1788
|
+
};
|
1789
|
+
|
1778
1790
|
private onLocalTrackPublished = async (pub: LocalTrackPublication) => {
|
1791
|
+
pub.track?.on(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
|
1792
|
+
pub.track?.getProcessor()?.onPublish?.(this);
|
1793
|
+
|
1779
1794
|
this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
|
1795
|
+
|
1780
1796
|
if (pub.track instanceof LocalAudioTrack) {
|
1781
1797
|
const trackIsSilent = await pub.track.checkForSilence();
|
1782
1798
|
if (trackIsSilent) {
|
@@ -1796,6 +1812,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1796
1812
|
};
|
1797
1813
|
|
1798
1814
|
private onLocalTrackUnpublished = (pub: LocalTrackPublication) => {
|
1815
|
+
pub.track?.off(TrackEvent.TrackProcessorUpdate, this.onTrackProcessorUpdate);
|
1799
1816
|
this.emit(RoomEvent.LocalTrackUnpublished, pub, this.localParticipant);
|
1800
1817
|
};
|
1801
1818
|
|
package/src/room/events.ts
CHANGED
@@ -6,17 +6,17 @@ import { isWeb, unwrapConstraint } from '../utils';
|
|
6
6
|
import LocalTrack from './LocalTrack';
|
7
7
|
import { Track } from './Track';
|
8
8
|
import type { AudioCaptureOptions } from './options';
|
9
|
-
import type { TrackProcessor } from './processor/types';
|
9
|
+
import type { AudioProcessorOptions, TrackProcessor } from './processor/types';
|
10
10
|
import { constraintsForOptions, detectSilence } from './utils';
|
11
11
|
|
12
|
-
export default class LocalAudioTrack extends LocalTrack {
|
12
|
+
export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {
|
13
13
|
/** @internal */
|
14
14
|
stopOnMute: boolean = false;
|
15
15
|
|
16
|
-
private audioContext?: AudioContext;
|
17
|
-
|
18
16
|
private prevStats?: AudioSenderStats;
|
19
17
|
|
18
|
+
protected processor?: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions> | undefined;
|
19
|
+
|
20
20
|
/**
|
21
21
|
*
|
22
22
|
* @param mediaTrack
|
@@ -48,7 +48,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
48
48
|
);
|
49
49
|
}
|
50
50
|
|
51
|
-
async mute(): Promise<
|
51
|
+
async mute(): Promise<typeof this> {
|
52
52
|
const unlock = await this.muteLock.lock();
|
53
53
|
try {
|
54
54
|
// disabled special handling as it will cause BT headsets to switch communication modes
|
@@ -64,7 +64,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
64
64
|
}
|
65
65
|
}
|
66
66
|
|
67
|
-
async unmute(): Promise<
|
67
|
+
async unmute(): Promise<typeof this> {
|
68
68
|
const unlock = await this.muteLock.lock();
|
69
69
|
try {
|
70
70
|
const deviceHasChanged =
|
@@ -99,7 +99,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
99
99
|
await this.restart(constraints);
|
100
100
|
}
|
101
101
|
|
102
|
-
protected async restart(constraints?: MediaTrackConstraints): Promise<
|
102
|
+
protected async restart(constraints?: MediaTrackConstraints): Promise<typeof this> {
|
103
103
|
const track = await super.restart(constraints);
|
104
104
|
this.checkForSilence();
|
105
105
|
return track;
|
@@ -139,7 +139,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
139
139
|
this.prevStats = stats;
|
140
140
|
};
|
141
141
|
|
142
|
-
async setProcessor(processor: TrackProcessor<
|
142
|
+
async setProcessor(processor: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions>) {
|
143
143
|
const unlock = await this.processorLock.lock();
|
144
144
|
try {
|
145
145
|
if (!this.audioContext) {
|
@@ -150,9 +150,6 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
150
150
|
if (this.processor) {
|
151
151
|
await this.stopProcessor();
|
152
152
|
}
|
153
|
-
if (this.kind === 'unknown') {
|
154
|
-
throw TypeError('cannot set processor on track of unknown kind');
|
155
|
-
}
|
156
153
|
|
157
154
|
const processorOptions = {
|
158
155
|
kind: this.kind,
|
@@ -166,6 +163,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
166
163
|
if (this.processor.processedTrack) {
|
167
164
|
await this.sender?.replaceTrack(this.processor.processedTrack);
|
168
165
|
}
|
166
|
+
this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
|
169
167
|
} finally {
|
170
168
|
unlock();
|
171
169
|
}
|