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
@@ -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
|
}
|