livekit-client 2.0.1 → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|