livekit-client 2.0.2 → 2.0.4
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 -17
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +158 -65
- 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/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts.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/types.d.ts +2 -0
- package/dist/src/e2ee/types.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/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +2 -0
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/DeviceManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -0
- package/dist/src/room/RTCEngine.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 +7 -2
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +4 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +2 -0
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +10 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/types.d.ts +4 -0
- package/dist/src/room/track/types.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/KeyProvider.d.ts +1 -1
- package/dist/ts4.2/src/e2ee/types.d.ts +2 -0
- 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/index.d.ts +2 -2
- package/dist/ts4.2/src/logger.d.ts +2 -0
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
- package/dist/ts4.2/src/room/Room.d.ts +1 -0
- package/dist/ts4.2/src/room/events.d.ts +7 -2
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +4 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +2 -0
- package/dist/ts4.2/src/room/track/options.d.ts +10 -0
- package/dist/ts4.2/src/room/track/types.d.ts +4 -0
- package/package.json +1 -1
- package/src/api/SignalClient.ts +1 -0
- package/src/e2ee/E2eeManager.ts +2 -1
- package/src/e2ee/KeyProvider.ts +6 -1
- package/src/e2ee/types.ts +2 -0
- package/src/e2ee/worker/FrameCryptor.ts +26 -0
- package/src/e2ee/worker/ParticipantKeyHandler.ts +9 -5
- package/src/e2ee/worker/e2ee.worker.ts +17 -17
- package/src/index.ts +2 -1
- package/src/logger.ts +2 -0
- package/src/room/DeviceManager.ts +10 -1
- package/src/room/RTCEngine.ts +14 -0
- package/src/room/Room.ts +29 -4
- package/src/room/events.ts +5 -0
- package/src/room/participant/LocalParticipant.ts +4 -4
- package/src/room/track/LocalAudioTrack.ts +11 -0
- package/src/room/track/LocalTrack.ts +62 -36
- package/src/room/track/LocalVideoTrack.ts +10 -0
- package/src/room/track/Track.ts +2 -0
- package/src/room/track/options.ts +41 -8
- package/src/room/track/types.ts +5 -0
@@ -8,6 +8,7 @@ import { Mutex, compareVersions, isMobile, sleep } from '../utils';
|
|
8
8
|
import { Track, attachToElement, detachTrack } from './Track';
|
9
9
|
import type { VideoCodec } from './options';
|
10
10
|
import type { TrackProcessor } from './processor/types';
|
11
|
+
import type { ReplaceTrackOptions } from './types';
|
11
12
|
|
12
13
|
const defaultDimensionsTimeout = 1000;
|
13
14
|
|
@@ -42,6 +43,8 @@ export default abstract class LocalTrack<
|
|
42
43
|
|
43
44
|
protected audioContext?: AudioContext;
|
44
45
|
|
46
|
+
private restartLock: Mutex;
|
47
|
+
|
45
48
|
/**
|
46
49
|
*
|
47
50
|
* @param mediaTrack
|
@@ -62,6 +65,7 @@ export default abstract class LocalTrack<
|
|
62
65
|
this.muteLock = new Mutex();
|
63
66
|
this.pauseUpstreamLock = new Mutex();
|
64
67
|
this.processorLock = new Mutex();
|
68
|
+
this.restartLock = new Mutex();
|
65
69
|
this.setMediaStreamTrack(mediaTrack, true);
|
66
70
|
|
67
71
|
// added to satisfy TS compiler, constraints are synced with MediaStreamTrack
|
@@ -221,62 +225,83 @@ export default abstract class LocalTrack<
|
|
221
225
|
return this;
|
222
226
|
}
|
223
227
|
|
224
|
-
async replaceTrack(track: MediaStreamTrack,
|
228
|
+
async replaceTrack(track: MediaStreamTrack, options?: ReplaceTrackOptions): Promise<typeof this>;
|
229
|
+
async replaceTrack(track: MediaStreamTrack, userProvidedTrack?: boolean): Promise<typeof this>;
|
230
|
+
async replaceTrack(
|
231
|
+
track: MediaStreamTrack,
|
232
|
+
userProvidedOrOptions: boolean | ReplaceTrackOptions | undefined,
|
233
|
+
) {
|
225
234
|
if (!this.sender) {
|
226
235
|
throw new TrackInvalidError('unable to replace an unpublished track');
|
227
236
|
}
|
228
237
|
|
238
|
+
let userProvidedTrack: boolean | undefined;
|
239
|
+
let stopProcessor: boolean | undefined;
|
240
|
+
|
241
|
+
if (typeof userProvidedOrOptions === 'boolean') {
|
242
|
+
userProvidedTrack = userProvidedOrOptions;
|
243
|
+
} else if (userProvidedOrOptions !== undefined) {
|
244
|
+
userProvidedTrack = userProvidedOrOptions.userProvidedTrack;
|
245
|
+
stopProcessor = userProvidedOrOptions.stopProcessor;
|
246
|
+
}
|
247
|
+
|
248
|
+
this.providedByUser = userProvidedTrack ?? true;
|
249
|
+
|
229
250
|
this.log.debug('replace MediaStreamTrack', this.logContext);
|
230
251
|
await this.setMediaStreamTrack(track);
|
231
252
|
// this must be synced *after* setting mediaStreamTrack above, since it relies
|
232
253
|
// on the previous state in order to cleanup
|
233
|
-
this.providedByUser = userProvidedTrack;
|
234
254
|
|
235
|
-
if (this.processor) {
|
255
|
+
if (stopProcessor && this.processor) {
|
236
256
|
await this.stopProcessor();
|
237
257
|
}
|
238
258
|
return this;
|
239
259
|
}
|
240
260
|
|
241
261
|
protected async restart(constraints?: MediaTrackConstraints) {
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
262
|
+
const unlock = await this.restartLock.lock();
|
263
|
+
try {
|
264
|
+
if (!constraints) {
|
265
|
+
constraints = this._constraints;
|
266
|
+
}
|
267
|
+
this.log.debug('restarting track with constraints', { ...this.logContext, constraints });
|
246
268
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
269
|
+
const streamConstraints: MediaStreamConstraints = {
|
270
|
+
audio: false,
|
271
|
+
video: false,
|
272
|
+
};
|
251
273
|
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
274
|
+
if (this.kind === Track.Kind.Video) {
|
275
|
+
streamConstraints.video = constraints;
|
276
|
+
} else {
|
277
|
+
streamConstraints.audio = constraints;
|
278
|
+
}
|
257
279
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
280
|
+
// these steps are duplicated from setMediaStreamTrack because we must stop
|
281
|
+
// the previous tracks before new tracks can be acquired
|
282
|
+
this.attachedElements.forEach((el) => {
|
283
|
+
detachTrack(this.mediaStreamTrack, el);
|
284
|
+
});
|
285
|
+
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
286
|
+
// on Safari, the old audio track must be stopped before attempting to acquire
|
287
|
+
// the new track, otherwise the new track will stop with
|
288
|
+
// 'A MediaStreamTrack ended due to a capture failure`
|
289
|
+
this._mediaStreamTrack.stop();
|
268
290
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
291
|
+
// create new track and attach
|
292
|
+
const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints);
|
293
|
+
const newTrack = mediaStream.getTracks()[0];
|
294
|
+
newTrack.addEventListener('ended', this.handleEnded);
|
295
|
+
this.log.debug('re-acquired MediaStreamTrack', this.logContext);
|
274
296
|
|
275
|
-
|
276
|
-
|
297
|
+
await this.setMediaStreamTrack(newTrack);
|
298
|
+
this._constraints = constraints;
|
277
299
|
|
278
|
-
|
279
|
-
|
300
|
+
this.emit(TrackEvent.Restarted, this);
|
301
|
+
return this;
|
302
|
+
} finally {
|
303
|
+
unlock();
|
304
|
+
}
|
280
305
|
}
|
281
306
|
|
282
307
|
protected setTrackMuted(muted: boolean) {
|
@@ -459,6 +484,7 @@ export default abstract class LocalTrack<
|
|
459
484
|
}
|
460
485
|
await this.sender?.replaceTrack(this.processor.processedTrack);
|
461
486
|
}
|
487
|
+
this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
|
462
488
|
} finally {
|
463
489
|
unlock();
|
464
490
|
}
|
@@ -484,8 +510,8 @@ export default abstract class LocalTrack<
|
|
484
510
|
this.processor = undefined;
|
485
511
|
this.processorElement?.remove();
|
486
512
|
this.processorElement = undefined;
|
487
|
-
|
488
513
|
await this.restart();
|
514
|
+
this.emit(TrackEvent.TrackProcessorUpdate);
|
489
515
|
}
|
490
516
|
|
491
517
|
protected abstract monitorSender(): void;
|
@@ -118,6 +118,11 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
118
118
|
async mute(): Promise<typeof this> {
|
119
119
|
const unlock = await this.muteLock.lock();
|
120
120
|
try {
|
121
|
+
if (this.isMuted) {
|
122
|
+
this.log.debug('Track already muted', this.logContext);
|
123
|
+
return this;
|
124
|
+
}
|
125
|
+
|
121
126
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
122
127
|
this.log.debug('stopping camera track', this.logContext);
|
123
128
|
// also stop the track, so that camera indicator is turned off
|
@@ -133,6 +138,11 @@ export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
|
133
138
|
async unmute(): Promise<typeof this> {
|
134
139
|
const unlock = await this.muteLock.lock();
|
135
140
|
try {
|
141
|
+
if (!this.isMuted) {
|
142
|
+
this.log.debug('Track already unmuted', this.logContext);
|
143
|
+
return this;
|
144
|
+
}
|
145
|
+
|
136
146
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
137
147
|
this.log.debug('reacquiring camera track', this.logContext);
|
138
148
|
await this.restartTrack();
|
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;
|
@@ -502,4 +503,5 @@ export type TrackEventCallbacks = {
|
|
502
503
|
elementDetached: (element: HTMLMediaElement) => void;
|
503
504
|
upstreamPaused: (track: any) => void;
|
504
505
|
upstreamResumed: (track: any) => void;
|
506
|
+
trackProcessorUpdate: (processor?: TrackProcessor<Track.Kind, any>) => void;
|
505
507
|
};
|
@@ -257,6 +257,15 @@ export interface VideoEncoding {
|
|
257
257
|
priority?: RTCPriorityType;
|
258
258
|
}
|
259
259
|
|
260
|
+
export interface VideoPresetOptions {
|
261
|
+
width: number;
|
262
|
+
height: number;
|
263
|
+
aspectRatio?: number;
|
264
|
+
maxBitrate: number;
|
265
|
+
maxFramerate?: number;
|
266
|
+
priority?: RTCPriorityType;
|
267
|
+
}
|
268
|
+
|
260
269
|
export class VideoPreset {
|
261
270
|
encoding: VideoEncoding;
|
262
271
|
|
@@ -264,20 +273,44 @@ export class VideoPreset {
|
|
264
273
|
|
265
274
|
height: number;
|
266
275
|
|
276
|
+
aspectRatio?: number;
|
277
|
+
|
278
|
+
constructor(videoPresetOptions: VideoPresetOptions);
|
267
279
|
constructor(
|
268
280
|
width: number,
|
269
281
|
height: number,
|
270
282
|
maxBitrate: number,
|
271
283
|
maxFramerate?: number,
|
272
284
|
priority?: RTCPriorityType,
|
285
|
+
);
|
286
|
+
constructor(
|
287
|
+
widthOrOptions: number | VideoPresetOptions,
|
288
|
+
height?: number,
|
289
|
+
maxBitrate?: number,
|
290
|
+
maxFramerate?: number,
|
291
|
+
priority?: RTCPriorityType,
|
273
292
|
) {
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
293
|
+
if (typeof widthOrOptions === 'object') {
|
294
|
+
this.width = widthOrOptions.width;
|
295
|
+
this.height = widthOrOptions.height;
|
296
|
+
this.aspectRatio = widthOrOptions.aspectRatio;
|
297
|
+
this.encoding = {
|
298
|
+
maxBitrate: widthOrOptions.maxBitrate,
|
299
|
+
maxFramerate: widthOrOptions.maxFramerate,
|
300
|
+
priority: widthOrOptions.priority,
|
301
|
+
};
|
302
|
+
} else if (height !== undefined && maxBitrate !== undefined) {
|
303
|
+
this.width = widthOrOptions;
|
304
|
+
this.height = height;
|
305
|
+
this.aspectRatio = widthOrOptions / height;
|
306
|
+
this.encoding = {
|
307
|
+
maxBitrate,
|
308
|
+
maxFramerate,
|
309
|
+
priority,
|
310
|
+
};
|
311
|
+
} else {
|
312
|
+
throw new TypeError('Unsupported options: provide at least width, height and maxBitrate');
|
313
|
+
}
|
281
314
|
}
|
282
315
|
|
283
316
|
get resolution(): VideoResolution {
|
@@ -285,7 +318,7 @@ export class VideoPreset {
|
|
285
318
|
width: this.width,
|
286
319
|
height: this.height,
|
287
320
|
frameRate: this.encoding.maxFramerate,
|
288
|
-
aspectRatio: this.
|
321
|
+
aspectRatio: this.aspectRatio,
|
289
322
|
};
|
290
323
|
}
|
291
324
|
}
|