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
@@ -11,7 +11,9 @@ import type { TrackProcessor } from './processor/types';
|
|
11
11
|
|
12
12
|
const defaultDimensionsTimeout = 1000;
|
13
13
|
|
14
|
-
export default abstract class LocalTrack
|
14
|
+
export default abstract class LocalTrack<
|
15
|
+
TrackKind extends Track.Kind = Track.Kind,
|
16
|
+
> extends Track<TrackKind> {
|
15
17
|
/** @internal */
|
16
18
|
sender?: RTCRtpSender;
|
17
19
|
|
@@ -34,10 +36,14 @@ export default abstract class LocalTrack extends Track {
|
|
34
36
|
|
35
37
|
protected processorElement?: HTMLMediaElement;
|
36
38
|
|
37
|
-
protected processor?: TrackProcessor<
|
39
|
+
protected processor?: TrackProcessor<TrackKind, any>;
|
38
40
|
|
39
41
|
protected processorLock: Mutex;
|
40
42
|
|
43
|
+
protected audioContext?: AudioContext;
|
44
|
+
|
45
|
+
private restartLock: Mutex;
|
46
|
+
|
41
47
|
/**
|
42
48
|
*
|
43
49
|
* @param mediaTrack
|
@@ -47,7 +53,7 @@ export default abstract class LocalTrack extends Track {
|
|
47
53
|
*/
|
48
54
|
protected constructor(
|
49
55
|
mediaTrack: MediaStreamTrack,
|
50
|
-
kind:
|
56
|
+
kind: TrackKind,
|
51
57
|
constraints?: MediaTrackConstraints,
|
52
58
|
userProvidedTrack = false,
|
53
59
|
loggerOptions?: LoggerOptions,
|
@@ -58,6 +64,7 @@ export default abstract class LocalTrack extends Track {
|
|
58
64
|
this.muteLock = new Mutex();
|
59
65
|
this.pauseUpstreamLock = new Mutex();
|
60
66
|
this.processorLock = new Mutex();
|
67
|
+
this.restartLock = new Mutex();
|
61
68
|
this.setMediaStreamTrack(mediaTrack, true);
|
62
69
|
|
63
70
|
// added to satisfy TS compiler, constraints are synced with MediaStreamTrack
|
@@ -128,21 +135,28 @@ export default abstract class LocalTrack extends Track {
|
|
128
135
|
this._constraints = newTrack.getConstraints();
|
129
136
|
}
|
130
137
|
let processedTrack: MediaStreamTrack | undefined;
|
131
|
-
if (this.processor && newTrack
|
132
|
-
this.
|
133
|
-
|
134
|
-
|
135
|
-
|
138
|
+
if (this.processor && newTrack) {
|
139
|
+
const unlock = await this.processorLock.lock();
|
140
|
+
try {
|
141
|
+
this.log.debug('restarting processor', this.logContext);
|
142
|
+
if (this.kind === 'unknown') {
|
143
|
+
throw TypeError('cannot set processor on track of unknown kind');
|
144
|
+
}
|
136
145
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
+
if (this.processorElement) {
|
147
|
+
attachToElement(newTrack, this.processorElement);
|
148
|
+
// ensure the processorElement itself stays muted
|
149
|
+
this.processorElement.muted = true;
|
150
|
+
}
|
151
|
+
await this.processor.restart({
|
152
|
+
track: newTrack,
|
153
|
+
kind: this.kind,
|
154
|
+
element: this.processorElement,
|
155
|
+
});
|
156
|
+
processedTrack = this.processor.processedTrack;
|
157
|
+
} finally {
|
158
|
+
unlock();
|
159
|
+
}
|
146
160
|
}
|
147
161
|
if (this.sender) {
|
148
162
|
await this.sender.replaceTrack(processedTrack ?? newTrack);
|
@@ -200,17 +214,17 @@ export default abstract class LocalTrack extends Track {
|
|
200
214
|
return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId);
|
201
215
|
}
|
202
216
|
|
203
|
-
async mute()
|
217
|
+
async mute() {
|
204
218
|
this.setTrackMuted(true);
|
205
219
|
return this;
|
206
220
|
}
|
207
221
|
|
208
|
-
async unmute()
|
222
|
+
async unmute() {
|
209
223
|
this.setTrackMuted(false);
|
210
224
|
return this;
|
211
225
|
}
|
212
226
|
|
213
|
-
async replaceTrack(track: MediaStreamTrack, userProvidedTrack = true)
|
227
|
+
async replaceTrack(track: MediaStreamTrack, userProvidedTrack = true) {
|
214
228
|
if (!this.sender) {
|
215
229
|
throw new TrackInvalidError('unable to replace an unpublished track');
|
216
230
|
}
|
@@ -227,45 +241,50 @@ export default abstract class LocalTrack extends Track {
|
|
227
241
|
return this;
|
228
242
|
}
|
229
243
|
|
230
|
-
protected async restart(constraints?: MediaTrackConstraints)
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
244
|
+
protected async restart(constraints?: MediaTrackConstraints) {
|
245
|
+
const unlock = await this.restartLock.lock();
|
246
|
+
try {
|
247
|
+
if (!constraints) {
|
248
|
+
constraints = this._constraints;
|
249
|
+
}
|
250
|
+
this.log.debug('restarting track with constraints', { ...this.logContext, constraints });
|
235
251
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
252
|
+
const streamConstraints: MediaStreamConstraints = {
|
253
|
+
audio: false,
|
254
|
+
video: false,
|
255
|
+
};
|
240
256
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
257
|
+
if (this.kind === Track.Kind.Video) {
|
258
|
+
streamConstraints.video = constraints;
|
259
|
+
} else {
|
260
|
+
streamConstraints.audio = constraints;
|
261
|
+
}
|
246
262
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
263
|
+
// these steps are duplicated from setMediaStreamTrack because we must stop
|
264
|
+
// the previous tracks before new tracks can be acquired
|
265
|
+
this.attachedElements.forEach((el) => {
|
266
|
+
detachTrack(this.mediaStreamTrack, el);
|
267
|
+
});
|
268
|
+
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
269
|
+
// on Safari, the old audio track must be stopped before attempting to acquire
|
270
|
+
// the new track, otherwise the new track will stop with
|
271
|
+
// 'A MediaStreamTrack ended due to a capture failure`
|
272
|
+
this._mediaStreamTrack.stop();
|
257
273
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
274
|
+
// create new track and attach
|
275
|
+
const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints);
|
276
|
+
const newTrack = mediaStream.getTracks()[0];
|
277
|
+
newTrack.addEventListener('ended', this.handleEnded);
|
278
|
+
this.log.debug('re-acquired MediaStreamTrack', this.logContext);
|
263
279
|
|
264
|
-
|
265
|
-
|
280
|
+
await this.setMediaStreamTrack(newTrack);
|
281
|
+
this._constraints = constraints;
|
266
282
|
|
267
|
-
|
268
|
-
|
283
|
+
this.emit(TrackEvent.Restarted, this);
|
284
|
+
return this;
|
285
|
+
} finally {
|
286
|
+
unlock();
|
287
|
+
}
|
269
288
|
}
|
270
289
|
|
271
290
|
protected setTrackMuted(muted: boolean) {
|
@@ -408,7 +427,7 @@ export default abstract class LocalTrack extends Track {
|
|
408
427
|
* @param showProcessedStreamLocally
|
409
428
|
* @returns
|
410
429
|
*/
|
411
|
-
async setProcessor(processor: TrackProcessor<
|
430
|
+
async setProcessor(processor: TrackProcessor<TrackKind>, showProcessedStreamLocally = true) {
|
412
431
|
const unlock = await this.processorLock.lock();
|
413
432
|
try {
|
414
433
|
this.log.debug('setting up processor', this.logContext);
|
@@ -418,7 +437,8 @@ export default abstract class LocalTrack extends Track {
|
|
418
437
|
if (this.kind === 'unknown') {
|
419
438
|
throw TypeError('cannot set processor on track of unknown kind');
|
420
439
|
}
|
421
|
-
this.processorElement =
|
440
|
+
this.processorElement =
|
441
|
+
this.processorElement ?? (document.createElement(this.kind) as HTMLMediaElement);
|
422
442
|
|
423
443
|
attachToElement(this._mediaStreamTrack, this.processorElement);
|
424
444
|
this.processorElement.muted = true;
|
@@ -433,6 +453,7 @@ export default abstract class LocalTrack extends Track {
|
|
433
453
|
kind: this.kind,
|
434
454
|
track: this._mediaStreamTrack,
|
435
455
|
element: this.processorElement,
|
456
|
+
audioContext: this.audioContext,
|
436
457
|
};
|
437
458
|
|
438
459
|
await processor.init(processorOptions);
|
@@ -446,6 +467,7 @@ export default abstract class LocalTrack extends Track {
|
|
446
467
|
}
|
447
468
|
await this.sender?.replaceTrack(this.processor.processedTrack);
|
448
469
|
}
|
470
|
+
this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
|
449
471
|
} finally {
|
450
472
|
unlock();
|
451
473
|
}
|
@@ -471,8 +493,8 @@ export default abstract class LocalTrack extends Track {
|
|
471
493
|
this.processor = undefined;
|
472
494
|
this.processorElement?.remove();
|
473
495
|
this.processorElement = undefined;
|
474
|
-
|
475
496
|
await this.restart();
|
497
|
+
this.emit(TrackEvent.TrackProcessorUpdate);
|
476
498
|
}
|
477
499
|
|
478
500
|
protected abstract monitorSender(): void;
|
@@ -30,7 +30,7 @@ export class SimulcastTrackInfo {
|
|
30
30
|
|
31
31
|
const refreshSubscribedCodecAfterNewCodec = 5000;
|
32
32
|
|
33
|
-
export default class LocalVideoTrack extends LocalTrack {
|
33
|
+
export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
34
34
|
/* @internal */
|
35
35
|
signalClient?: SignalClient;
|
36
36
|
|
@@ -115,7 +115,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
115
115
|
}
|
116
116
|
}
|
117
117
|
|
118
|
-
async mute(): Promise<
|
118
|
+
async mute(): Promise<typeof this> {
|
119
119
|
const unlock = await this.muteLock.lock();
|
120
120
|
try {
|
121
121
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
@@ -130,7 +130,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
130
130
|
}
|
131
131
|
}
|
132
132
|
|
133
|
-
async unmute(): Promise<
|
133
|
+
async unmute(): Promise<typeof this> {
|
134
134
|
const unlock = await this.muteLock.lock();
|
135
135
|
try {
|
136
136
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
@@ -7,7 +7,7 @@ import RemoteTrack from './RemoteTrack';
|
|
7
7
|
import { Track } from './Track';
|
8
8
|
import type { AudioOutputOptions } from './options';
|
9
9
|
|
10
|
-
export default class RemoteAudioTrack extends RemoteTrack {
|
10
|
+
export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
11
11
|
private prevStats?: AudioReceiverStats;
|
12
12
|
|
13
13
|
private elementVolume: number | undefined;
|
@@ -3,14 +3,16 @@ import { monitorFrequency } from '../stats';
|
|
3
3
|
import type { LoggerOptions } from '../types';
|
4
4
|
import { Track } from './Track';
|
5
5
|
|
6
|
-
export default abstract class RemoteTrack
|
6
|
+
export default abstract class RemoteTrack<
|
7
|
+
TrackKind extends Track.Kind = Track.Kind,
|
8
|
+
> extends Track<TrackKind> {
|
7
9
|
/** @internal */
|
8
10
|
receiver?: RTCRtpReceiver;
|
9
11
|
|
10
12
|
constructor(
|
11
13
|
mediaTrack: MediaStreamTrack,
|
12
14
|
sid: string,
|
13
|
-
kind:
|
15
|
+
kind: TrackKind,
|
14
16
|
receiver?: RTCRtpReceiver,
|
15
17
|
loggerOptions?: LoggerOptions,
|
16
18
|
) {
|
@@ -12,7 +12,7 @@ import type { AdaptiveStreamSettings } from './types';
|
|
12
12
|
|
13
13
|
const REACTION_DELAY = 100;
|
14
14
|
|
15
|
-
export default class RemoteVideoTrack extends RemoteTrack {
|
15
|
+
export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
|
16
16
|
private prevStats?: VideoReceiverStats;
|
17
17
|
|
18
18
|
private elementInfos: ElementInfo[] = [];
|
package/src/room/track/Track.ts
CHANGED
@@ -11,6 +11,7 @@ import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
|
|
11
11
|
import { TrackEvent } from '../events';
|
12
12
|
import type { LoggerOptions } from '../types';
|
13
13
|
import { isFireFox, isSafari, isWeb } from '../utils';
|
14
|
+
import type { TrackProcessor } from './processor/types';
|
14
15
|
import { getLogContextFromTrack } from './utils';
|
15
16
|
|
16
17
|
const BACKGROUND_REACTION_DELAY = 5000;
|
@@ -24,8 +25,10 @@ export enum VideoQuality {
|
|
24
25
|
MEDIUM = ProtoQuality.MEDIUM,
|
25
26
|
HIGH = ProtoQuality.HIGH,
|
26
27
|
}
|
27
|
-
export abstract class Track
|
28
|
-
|
28
|
+
export abstract class Track<
|
29
|
+
TrackKind extends Track.Kind = Track.Kind,
|
30
|
+
> extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
|
31
|
+
readonly kind: TrackKind;
|
29
32
|
|
30
33
|
attachedElements: HTMLMediaElement[] = [];
|
31
34
|
|
@@ -67,7 +70,7 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
67
70
|
|
68
71
|
protected constructor(
|
69
72
|
mediaTrack: MediaStreamTrack,
|
70
|
-
kind:
|
73
|
+
kind: TrackKind,
|
71
74
|
loggerOptions: LoggerOptions = {},
|
72
75
|
) {
|
73
76
|
super();
|
@@ -500,4 +503,5 @@ export type TrackEventCallbacks = {
|
|
500
503
|
elementDetached: (element: HTMLMediaElement) => void;
|
501
504
|
upstreamPaused: (track: any) => void;
|
502
505
|
upstreamResumed: (track: any) => void;
|
506
|
+
trackProcessorUpdate: (processor?: TrackProcessor<Track.Kind, any>) => void;
|
503
507
|
};
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import type Room from '../../Room';
|
1
2
|
import type { Track } from '../Track';
|
2
3
|
|
3
4
|
/**
|
@@ -7,6 +8,7 @@ export type ProcessorOptions<T extends Track.Kind> = {
|
|
7
8
|
kind: T;
|
8
9
|
track: MediaStreamTrack;
|
9
10
|
element?: HTMLMediaElement;
|
11
|
+
audioContext?: AudioContext;
|
10
12
|
};
|
11
13
|
|
12
14
|
/**
|
@@ -33,4 +35,6 @@ export interface TrackProcessor<
|
|
33
35
|
restart: (opts: U) => Promise<void>;
|
34
36
|
destroy: () => Promise<void>;
|
35
37
|
processedTrack?: MediaStreamTrack;
|
38
|
+
onPublish?: (room: Room) => Promise<void>;
|
39
|
+
onUnpublish?: () => Promise<void>;
|
36
40
|
}
|