livekit-client 2.0.2 → 2.0.4
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 -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
|
}
|