livekit-client 1.15.5 → 1.15.7
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 +14 -1
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +561 -328
- 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 +5 -1
- package/dist/src/api/SignalClient.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 +19 -3
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +1 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +5 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +8 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +2 -0
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +9 -1
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts +2 -1
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +4 -5
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +2 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +2 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
- 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 -1
- package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -1
- package/dist/src/room/track/RemoteTrackPublication.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 +10 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/TrackPublication.d.ts +7 -1
- package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +8 -3
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +1 -0
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +4 -0
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +1 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/api/SignalClient.d.ts +5 -1
- package/dist/ts4.2/src/index.d.ts +2 -2
- package/dist/ts4.2/src/logger.d.ts +19 -3
- package/dist/ts4.2/src/options.d.ts +1 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +5 -1
- package/dist/ts4.2/src/room/PCTransportManager.d.ts +5 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -0
- package/dist/ts4.2/src/room/Room.d.ts +2 -0
- package/dist/ts4.2/src/room/participant/Participant.d.ts +9 -1
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
- package/dist/ts4.2/src/room/timers.d.ts +4 -5
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -1
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +10 -1
- package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -1
- package/dist/ts4.2/src/room/track/options.d.ts +8 -3
- package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
- package/dist/ts4.2/src/room/types.d.ts +4 -0
- package/dist/ts4.2/src/room/utils.d.ts +1 -0
- package/package.json +15 -15
- package/src/api/SignalClient.ts +43 -21
- package/src/index.ts +2 -1
- package/src/logger.ts +32 -8
- package/src/options.ts +2 -0
- package/src/room/PCTransport.ts +29 -8
- package/src/room/PCTransportManager.ts +29 -9
- package/src/room/RTCEngine.ts +71 -34
- package/src/room/Room.ts +94 -30
- package/src/room/participant/LocalParticipant.ts +163 -47
- package/src/room/participant/Participant.ts +26 -3
- package/src/room/participant/RemoteParticipant.ts +23 -15
- package/src/room/participant/publishUtils.test.ts +2 -2
- package/src/room/participant/publishUtils.ts +7 -4
- package/src/room/track/LocalAudioTrack.ts +8 -7
- package/src/room/track/LocalTrack.ts +27 -20
- package/src/room/track/LocalTrackPublication.ts +3 -2
- package/src/room/track/LocalVideoTrack.ts +31 -13
- package/src/room/track/RemoteAudioTrack.ts +4 -3
- package/src/room/track/RemoteTrack.ts +4 -1
- package/src/room/track/RemoteTrackPublication.ts +21 -13
- package/src/room/track/RemoteVideoTrack.ts +5 -4
- package/src/room/track/Track.ts +32 -2
- package/src/room/track/TrackPublication.ts +18 -3
- package/src/room/track/create.ts +4 -3
- package/src/room/track/options.ts +12 -5
- package/src/room/track/utils.ts +23 -1
- package/src/room/types.ts +5 -0
- package/src/room/utils.ts +5 -0
@@ -10,18 +10,20 @@ import type {
|
|
10
10
|
VideoEncoding,
|
11
11
|
} from '../track/options';
|
12
12
|
import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
|
13
|
+
import type { LoggerOptions } from '../types';
|
13
14
|
import { getReactNativeOs, isFireFox, isReactNative, isSVCCodec } from '../utils';
|
14
15
|
|
15
16
|
/** @internal */
|
16
17
|
export function mediaTrackToLocalTrack(
|
17
18
|
mediaStreamTrack: MediaStreamTrack,
|
18
19
|
constraints?: MediaTrackConstraints,
|
20
|
+
loggerOptions?: LoggerOptions,
|
19
21
|
): LocalVideoTrack | LocalAudioTrack {
|
20
22
|
switch (mediaStreamTrack.kind) {
|
21
23
|
case 'audio':
|
22
|
-
return new LocalAudioTrack(mediaStreamTrack, constraints, false);
|
24
|
+
return new LocalAudioTrack(mediaStreamTrack, constraints, false, undefined, loggerOptions);
|
23
25
|
case 'video':
|
24
|
-
return new LocalVideoTrack(mediaStreamTrack, constraints, false);
|
26
|
+
return new LocalVideoTrack(mediaStreamTrack, constraints, false, loggerOptions);
|
25
27
|
default:
|
26
28
|
throw new TrackInvalidError(`unsupported track type: ${mediaStreamTrack.kind}`);
|
27
29
|
}
|
@@ -44,7 +46,7 @@ export const defaultSimulcastPresets43 = [VideoPresets43.h180, VideoPresets43.h3
|
|
44
46
|
|
45
47
|
/* @internal */
|
46
48
|
export const computeDefaultScreenShareSimulcastPresets = (fromPreset: VideoPreset) => {
|
47
|
-
const layers = [{ scaleResolutionDownBy: 2, fps:
|
49
|
+
const layers = [{ scaleResolutionDownBy: 2, fps: fromPreset.encoding.maxFramerate }];
|
48
50
|
return layers.map(
|
49
51
|
(t) =>
|
50
52
|
new VideoPreset(
|
@@ -54,7 +56,8 @@ export const computeDefaultScreenShareSimulcastPresets = (fromPreset: VideoPrese
|
|
54
56
|
150_000,
|
55
57
|
Math.floor(
|
56
58
|
fromPreset.encoding.maxBitrate /
|
57
|
-
(t.scaleResolutionDownBy ** 2 *
|
59
|
+
(t.scaleResolutionDownBy ** 2 *
|
60
|
+
((fromPreset.encoding.maxFramerate ?? 30) / (t.fps ?? 30))),
|
58
61
|
),
|
59
62
|
),
|
60
63
|
t.fps,
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import log from '../../logger';
|
2
1
|
import { TrackEvent } from '../events';
|
3
2
|
import { computeBitrate, monitorFrequency } from '../stats';
|
4
3
|
import type { AudioSenderStats } from '../stats';
|
4
|
+
import type { LoggerOptions } from '../types';
|
5
5
|
import { isWeb, unwrapConstraint } from '../utils';
|
6
6
|
import LocalTrack from './LocalTrack';
|
7
7
|
import { Track } from './Track';
|
@@ -28,8 +28,9 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
28
28
|
constraints?: MediaTrackConstraints,
|
29
29
|
userProvidedTrack = true,
|
30
30
|
audioContext?: AudioContext,
|
31
|
+
loggerOptions?: LoggerOptions,
|
31
32
|
) {
|
32
|
-
super(mediaTrack, Track.Kind.Audio, constraints, userProvidedTrack);
|
33
|
+
super(mediaTrack, Track.Kind.Audio, constraints, userProvidedTrack, loggerOptions);
|
33
34
|
this.audioContext = audioContext;
|
34
35
|
this.checkForSilence();
|
35
36
|
}
|
@@ -52,7 +53,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
52
53
|
try {
|
53
54
|
// disabled special handling as it will cause BT headsets to switch communication modes
|
54
55
|
if (this.source === Track.Source.Microphone && this.stopOnMute && !this.isUserProvided) {
|
55
|
-
log.debug('stopping mic track');
|
56
|
+
this.log.debug('stopping mic track', this.logContext);
|
56
57
|
// also stop the track, so that microphone indicator is turned off
|
57
58
|
this._mediaStreamTrack.stop();
|
58
59
|
}
|
@@ -76,7 +77,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
76
77
|
(this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) &&
|
77
78
|
!this.isUserProvided
|
78
79
|
) {
|
79
|
-
log.debug('reacquiring mic track');
|
80
|
+
this.log.debug('reacquiring mic track', this.logContext);
|
80
81
|
await this.restartTrack();
|
81
82
|
}
|
82
83
|
await super.unmute();
|
@@ -127,7 +128,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
127
128
|
try {
|
128
129
|
stats = await this.getSenderStats();
|
129
130
|
} catch (e) {
|
130
|
-
log.error('could not get audio sender stats', { error: e });
|
131
|
+
this.log.error('could not get audio sender stats', { ...this.logContext, error: e });
|
131
132
|
return;
|
132
133
|
}
|
133
134
|
|
@@ -158,7 +159,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
158
159
|
track: this._mediaStreamTrack,
|
159
160
|
audioContext: this.audioContext,
|
160
161
|
};
|
161
|
-
log.debug(`setting up audio processor ${processor.name}
|
162
|
+
this.log.debug(`setting up audio processor ${processor.name}`, this.logContext);
|
162
163
|
|
163
164
|
await processor.init(processorOptions);
|
164
165
|
this.processor = processor;
|
@@ -207,7 +208,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
207
208
|
const trackIsSilent = await detectSilence(this);
|
208
209
|
if (trackIsSilent) {
|
209
210
|
if (!this.isMuted) {
|
210
|
-
log.warn('silence detected on local audio track');
|
211
|
+
this.log.warn('silence detected on local audio track', this.logContext);
|
211
212
|
}
|
212
213
|
this.emit(TrackEvent.AudioSilenceDetected);
|
213
214
|
}
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { debounce } from 'ts-debounce';
|
2
|
-
import log from '../../logger';
|
3
2
|
import { getBrowser } from '../../utils/browserParser';
|
4
3
|
import DeviceManager from '../DeviceManager';
|
5
4
|
import { DeviceUnsupportedError, TrackInvalidError } from '../errors';
|
6
5
|
import { TrackEvent } from '../events';
|
6
|
+
import type { LoggerOptions } from '../types';
|
7
7
|
import { Mutex, compareVersions, isMobile, sleep } from '../utils';
|
8
8
|
import { Track, attachToElement, detachTrack } from './Track';
|
9
9
|
import type { VideoCodec } from './options';
|
@@ -50,8 +50,9 @@ export default abstract class LocalTrack extends Track {
|
|
50
50
|
kind: Track.Kind,
|
51
51
|
constraints?: MediaTrackConstraints,
|
52
52
|
userProvidedTrack = false,
|
53
|
+
loggerOptions?: LoggerOptions,
|
53
54
|
) {
|
54
|
-
super(mediaTrack, kind);
|
55
|
+
super(mediaTrack, kind, loggerOptions);
|
55
56
|
this.reacquireTrack = false;
|
56
57
|
this.providedByUser = userProvidedTrack;
|
57
58
|
this.muteLock = new Mutex();
|
@@ -112,10 +113,6 @@ export default abstract class LocalTrack extends Track {
|
|
112
113
|
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
113
114
|
this._mediaStreamTrack.removeEventListener('mute', this.handleTrackMuteEvent);
|
114
115
|
this._mediaStreamTrack.removeEventListener('unmute', this.handleTrackUnmuteEvent);
|
115
|
-
|
116
|
-
if (!this.providedByUser && this._mediaStreamTrack !== newTrack) {
|
117
|
-
this._mediaStreamTrack.stop();
|
118
|
-
}
|
119
116
|
}
|
120
117
|
|
121
118
|
this.mediaStream = new MediaStream([newTrack]);
|
@@ -132,12 +129,14 @@ export default abstract class LocalTrack extends Track {
|
|
132
129
|
}
|
133
130
|
let processedTrack: MediaStreamTrack | undefined;
|
134
131
|
if (this.processor && newTrack && this.processorElement) {
|
135
|
-
log.debug('restarting processor');
|
132
|
+
this.log.debug('restarting processor', this.logContext);
|
136
133
|
if (this.kind === 'unknown') {
|
137
134
|
throw TypeError('cannot set processor on track of unknown kind');
|
138
135
|
}
|
139
136
|
|
140
137
|
attachToElement(newTrack, this.processorElement);
|
138
|
+
// ensure the processorElement itself stays muted
|
139
|
+
this.processorElement.muted = true;
|
141
140
|
await this.processor.restart({
|
142
141
|
track: newTrack,
|
143
142
|
kind: this.kind,
|
@@ -148,6 +147,11 @@ export default abstract class LocalTrack extends Track {
|
|
148
147
|
if (this.sender) {
|
149
148
|
await this.sender.replaceTrack(processedTrack ?? newTrack);
|
150
149
|
}
|
150
|
+
// if `newTrack` is different from the existing track, stop the
|
151
|
+
// older track just before replacing it
|
152
|
+
if (!this.providedByUser && this._mediaStreamTrack !== newTrack) {
|
153
|
+
this._mediaStreamTrack.stop();
|
154
|
+
}
|
151
155
|
this._mediaStreamTrack = newTrack;
|
152
156
|
if (newTrack) {
|
153
157
|
// sync muted state with the enabled state of the newly provided track
|
@@ -211,7 +215,7 @@ export default abstract class LocalTrack extends Track {
|
|
211
215
|
throw new TrackInvalidError('unable to replace an unpublished track');
|
212
216
|
}
|
213
217
|
|
214
|
-
log.debug('replace MediaStreamTrack');
|
218
|
+
this.log.debug('replace MediaStreamTrack', this.logContext);
|
215
219
|
await this.setMediaStreamTrack(track);
|
216
220
|
// this must be synced *after* setting mediaStreamTrack above, since it relies
|
217
221
|
// on the previous state in order to cleanup
|
@@ -227,7 +231,7 @@ export default abstract class LocalTrack extends Track {
|
|
227
231
|
if (!constraints) {
|
228
232
|
constraints = this._constraints;
|
229
233
|
}
|
230
|
-
log.debug('restarting track with constraints', constraints);
|
234
|
+
this.log.debug('restarting track with constraints', { ...this.logContext, constraints });
|
231
235
|
|
232
236
|
const streamConstraints: MediaStreamConstraints = {
|
233
237
|
audio: false,
|
@@ -255,7 +259,7 @@ export default abstract class LocalTrack extends Track {
|
|
255
259
|
const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints);
|
256
260
|
const newTrack = mediaStream.getTracks()[0];
|
257
261
|
newTrack.addEventListener('ended', this.handleEnded);
|
258
|
-
log.debug('re-acquired MediaStreamTrack');
|
262
|
+
this.log.debug('re-acquired MediaStreamTrack', this.logContext);
|
259
263
|
|
260
264
|
await this.setMediaStreamTrack(newTrack);
|
261
265
|
this._constraints = constraints;
|
@@ -265,7 +269,7 @@ export default abstract class LocalTrack extends Track {
|
|
265
269
|
}
|
266
270
|
|
267
271
|
protected setTrackMuted(muted: boolean) {
|
268
|
-
log.debug(`setting ${this.kind} track ${muted ? 'muted' : 'unmuted'}
|
272
|
+
this.log.debug(`setting ${this.kind} track ${muted ? 'muted' : 'unmuted'}`, this.logContext);
|
269
273
|
|
270
274
|
if (this.isMuted === muted && this._mediaStreamTrack.enabled !== muted) {
|
271
275
|
return;
|
@@ -288,10 +292,10 @@ export default abstract class LocalTrack extends Track {
|
|
288
292
|
protected async handleAppVisibilityChanged() {
|
289
293
|
await super.handleAppVisibilityChanged();
|
290
294
|
if (!isMobile()) return;
|
291
|
-
log.debug(`visibility changed, is in Background: ${this.isInBackground}
|
295
|
+
this.log.debug(`visibility changed, is in Background: ${this.isInBackground}`, this.logContext);
|
292
296
|
|
293
297
|
if (!this.isInBackground && this.needsReAcquisition && !this.isUserProvided && !this.isMuted) {
|
294
|
-
log.debug(`track needs to be reacquired, restarting ${this.source}
|
298
|
+
this.log.debug(`track needs to be reacquired, restarting ${this.source}`, this.logContext);
|
295
299
|
await this.restart();
|
296
300
|
this.reacquireTrack = false;
|
297
301
|
}
|
@@ -299,7 +303,7 @@ export default abstract class LocalTrack extends Track {
|
|
299
303
|
|
300
304
|
private handleTrackMuteEvent = () =>
|
301
305
|
this.debouncedTrackMuteHandler().catch(() =>
|
302
|
-
log.debug('track mute bounce got cancelled by an unmute event'),
|
306
|
+
this.log.debug('track mute bounce got cancelled by an unmute event', this.logContext),
|
303
307
|
);
|
304
308
|
|
305
309
|
private debouncedTrackMuteHandler = debounce(async () => {
|
@@ -343,7 +347,7 @@ export default abstract class LocalTrack extends Track {
|
|
343
347
|
return;
|
344
348
|
}
|
345
349
|
if (!this.sender) {
|
346
|
-
log.warn('unable to pause upstream for an unpublished track');
|
350
|
+
this.log.warn('unable to pause upstream for an unpublished track', this.logContext);
|
347
351
|
return;
|
348
352
|
}
|
349
353
|
|
@@ -367,7 +371,7 @@ export default abstract class LocalTrack extends Track {
|
|
367
371
|
return;
|
368
372
|
}
|
369
373
|
if (!this.sender) {
|
370
|
-
log.warn('unable to resume upstream for an unpublished track');
|
374
|
+
this.log.warn('unable to resume upstream for an unpublished track', this.logContext);
|
371
375
|
return;
|
372
376
|
}
|
373
377
|
this._isUpstreamPaused = false;
|
@@ -407,7 +411,7 @@ export default abstract class LocalTrack extends Track {
|
|
407
411
|
async setProcessor(processor: TrackProcessor<this['kind']>, showProcessedStreamLocally = true) {
|
408
412
|
const unlock = await this.processorLock.lock();
|
409
413
|
try {
|
410
|
-
log.debug('setting up processor');
|
414
|
+
this.log.debug('setting up processor', this.logContext);
|
411
415
|
if (this.processor) {
|
412
416
|
await this.stopProcessor();
|
413
417
|
}
|
@@ -415,12 +419,15 @@ export default abstract class LocalTrack extends Track {
|
|
415
419
|
throw TypeError('cannot set processor on track of unknown kind');
|
416
420
|
}
|
417
421
|
this.processorElement = this.processorElement ?? document.createElement(this.kind);
|
418
|
-
this.processorElement.muted = true;
|
419
422
|
|
420
423
|
attachToElement(this._mediaStreamTrack, this.processorElement);
|
424
|
+
this.processorElement.muted = true;
|
425
|
+
|
421
426
|
this.processorElement
|
422
427
|
.play()
|
423
|
-
.catch((error) =>
|
428
|
+
.catch((error) =>
|
429
|
+
this.log.error('failed to play processor element', { ...this.logContext, error }),
|
430
|
+
);
|
424
431
|
|
425
432
|
const processorOptions = {
|
426
433
|
kind: this.kind,
|
@@ -458,7 +465,7 @@ export default abstract class LocalTrack extends Track {
|
|
458
465
|
async stopProcessor() {
|
459
466
|
if (!this.processor) return;
|
460
467
|
|
461
|
-
log.debug('stopping processor');
|
468
|
+
this.log.debug('stopping processor', this.logContext);
|
462
469
|
this.processor.processedTrack?.stop();
|
463
470
|
await this.processor.destroy();
|
464
471
|
this.processor = undefined;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import type { TrackInfo } from '../../proto/livekit_models_pb';
|
2
2
|
import { TrackEvent } from '../events';
|
3
|
+
import type { LoggerOptions } from '../types';
|
3
4
|
import type LocalAudioTrack from './LocalAudioTrack';
|
4
5
|
import type LocalTrack from './LocalTrack';
|
5
6
|
import type LocalVideoTrack from './LocalVideoTrack';
|
@@ -16,8 +17,8 @@ export default class LocalTrackPublication extends TrackPublication {
|
|
16
17
|
return this.track?.isUpstreamPaused;
|
17
18
|
}
|
18
19
|
|
19
|
-
constructor(kind: Track.Kind, ti: TrackInfo, track?: LocalTrack) {
|
20
|
-
super(kind, ti.sid, ti.name);
|
20
|
+
constructor(kind: Track.Kind, ti: TrackInfo, track?: LocalTrack, loggerOptions?: LoggerOptions) {
|
21
|
+
super(kind, ti.sid, ti.name, loggerOptions);
|
21
22
|
|
22
23
|
this.updateInfo(ti);
|
23
24
|
this.setTrack(track);
|
@@ -1,10 +1,11 @@
|
|
1
1
|
import type { SignalClient } from '../../api/SignalClient';
|
2
|
-
import
|
2
|
+
import type { StructuredLogger } from '../../logger';
|
3
3
|
import { VideoLayer, VideoQuality } from '../../proto/livekit_models_pb';
|
4
4
|
import { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc_pb';
|
5
5
|
import { ScalabilityMode } from '../participant/publishUtils';
|
6
6
|
import type { VideoSenderStats } from '../stats';
|
7
7
|
import { computeBitrate, monitorFrequency } from '../stats';
|
8
|
+
import type { LoggerOptions } from '../types';
|
8
9
|
import { Mutex, isFireFox, isMobile, isWeb, unwrapConstraint } from '../utils';
|
9
10
|
import LocalTrack from './LocalTrack';
|
10
11
|
import { Track } from './Track';
|
@@ -58,8 +59,9 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
58
59
|
mediaTrack: MediaStreamTrack,
|
59
60
|
constraints?: MediaTrackConstraints,
|
60
61
|
userProvidedTrack = true,
|
62
|
+
loggerOptions?: LoggerOptions,
|
61
63
|
) {
|
62
|
-
super(mediaTrack, Track.Kind.Video, constraints, userProvidedTrack);
|
64
|
+
super(mediaTrack, Track.Kind.Video, constraints, userProvidedTrack, loggerOptions);
|
63
65
|
this.senderLock = new Mutex();
|
64
66
|
}
|
65
67
|
|
@@ -117,7 +119,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
117
119
|
const unlock = await this.muteLock.lock();
|
118
120
|
try {
|
119
121
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
120
|
-
log.debug('stopping camera track');
|
122
|
+
this.log.debug('stopping camera track', this.logContext);
|
121
123
|
// also stop the track, so that camera indicator is turned off
|
122
124
|
this._mediaStreamTrack.stop();
|
123
125
|
}
|
@@ -132,7 +134,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
132
134
|
const unlock = await this.muteLock.lock();
|
133
135
|
try {
|
134
136
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
135
|
-
log.debug('reacquiring camera track');
|
137
|
+
this.log.debug('reacquiring camera track', this.logContext);
|
136
138
|
await this.restartTrack();
|
137
139
|
}
|
138
140
|
await super.unmute();
|
@@ -202,7 +204,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
202
204
|
}),
|
203
205
|
);
|
204
206
|
}
|
205
|
-
log.debug(`setting publishing quality. max quality ${maxQuality}
|
207
|
+
this.log.debug(`setting publishing quality. max quality ${maxQuality}`, this.logContext);
|
206
208
|
this.setPublishingLayers(qualities);
|
207
209
|
}
|
208
210
|
|
@@ -288,7 +290,8 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
288
290
|
* been published
|
289
291
|
*/
|
290
292
|
async setPublishingCodecs(codecs: SubscribedCodec[]): Promise<VideoCodec[]> {
|
291
|
-
log.debug('setting publishing codecs', {
|
293
|
+
this.log.debug('setting publishing codecs', {
|
294
|
+
...this.logContext,
|
292
295
|
codecs,
|
293
296
|
currentCodec: this.codec,
|
294
297
|
});
|
@@ -306,7 +309,10 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
306
309
|
await this.setPublishingLayers(codec.qualities);
|
307
310
|
} else {
|
308
311
|
const simulcastCodecInfo = this.simulcastCodecs.get(codec.codec as VideoCodec);
|
309
|
-
log.debug(`try setPublishingCodec for ${codec.codec}`,
|
312
|
+
this.log.debug(`try setPublishingCodec for ${codec.codec}`, {
|
313
|
+
...this.logContext,
|
314
|
+
simulcastCodecInfo,
|
315
|
+
});
|
310
316
|
if (!simulcastCodecInfo || !simulcastCodecInfo.sender) {
|
311
317
|
for (const q of codec.qualities) {
|
312
318
|
if (q.enabled) {
|
@@ -315,12 +321,14 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
315
321
|
}
|
316
322
|
}
|
317
323
|
} else if (simulcastCodecInfo.encodings) {
|
318
|
-
log.debug(`try setPublishingLayersForSender ${codec.codec}
|
324
|
+
this.log.debug(`try setPublishingLayersForSender ${codec.codec}`, this.logContext);
|
319
325
|
await setPublishingLayersForSender(
|
320
326
|
simulcastCodecInfo.sender,
|
321
327
|
simulcastCodecInfo.encodings!,
|
322
328
|
codec.qualities,
|
323
329
|
this.senderLock,
|
330
|
+
this.log,
|
331
|
+
this.logContext,
|
324
332
|
);
|
325
333
|
}
|
326
334
|
}
|
@@ -333,12 +341,19 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
333
341
|
* Sets layers that should be publishing
|
334
342
|
*/
|
335
343
|
async setPublishingLayers(qualities: SubscribedQuality[]) {
|
336
|
-
log.debug('setting publishing layers', qualities);
|
344
|
+
this.log.debug('setting publishing layers', { ...this.logContext, qualities });
|
337
345
|
if (!this.sender || !this.encodings) {
|
338
346
|
return;
|
339
347
|
}
|
340
348
|
|
341
|
-
await setPublishingLayersForSender(
|
349
|
+
await setPublishingLayersForSender(
|
350
|
+
this.sender,
|
351
|
+
this.encodings,
|
352
|
+
qualities,
|
353
|
+
this.senderLock,
|
354
|
+
this.log,
|
355
|
+
this.logContext,
|
356
|
+
);
|
342
357
|
}
|
343
358
|
|
344
359
|
protected monitorSender = async () => {
|
@@ -351,7 +366,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
351
366
|
try {
|
352
367
|
stats = await this.getSenderStats();
|
353
368
|
} catch (e) {
|
354
|
-
log.error('could not get audio sender stats', { error: e });
|
369
|
+
this.log.error('could not get audio sender stats', { ...this.logContext, error: e });
|
355
370
|
return;
|
356
371
|
}
|
357
372
|
const statsMap = new Map<string, VideoSenderStats>(stats.map((s) => [s.rid, s]));
|
@@ -382,9 +397,11 @@ async function setPublishingLayersForSender(
|
|
382
397
|
senderEncodings: RTCRtpEncodingParameters[],
|
383
398
|
qualities: SubscribedQuality[],
|
384
399
|
senderLock: Mutex,
|
400
|
+
log: StructuredLogger,
|
401
|
+
logContext: Record<string, unknown>,
|
385
402
|
) {
|
386
403
|
const unlock = await senderLock.lock();
|
387
|
-
log.debug('setPublishingLayersForSender', { sender, qualities, senderEncodings });
|
404
|
+
log.debug('setPublishingLayersForSender', { ...logContext, sender, qualities, senderEncodings });
|
388
405
|
try {
|
389
406
|
const params = sender.getParameters();
|
390
407
|
const { encodings } = params;
|
@@ -458,6 +475,7 @@ async function setPublishingLayersForSender(
|
|
458
475
|
`setting layer ${subscribedQuality.quality} to ${
|
459
476
|
encoding.active ? 'enabled' : 'disabled'
|
460
477
|
}`,
|
478
|
+
logContext,
|
461
479
|
);
|
462
480
|
|
463
481
|
// FireFox does not support setting encoding.active to false, so we
|
@@ -481,7 +499,7 @@ async function setPublishingLayersForSender(
|
|
481
499
|
|
482
500
|
if (hasChanged) {
|
483
501
|
params.encodings = encodings;
|
484
|
-
log.debug(`setting encodings`, params.encodings);
|
502
|
+
log.debug(`setting encodings`, { ...logContext, encodings: params.encodings });
|
485
503
|
await sender.setParameters(params);
|
486
504
|
}
|
487
505
|
} finally {
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import log from '../../logger';
|
2
1
|
import { TrackEvent } from '../events';
|
3
2
|
import { computeBitrate } from '../stats';
|
4
3
|
import type { AudioReceiverStats } from '../stats';
|
4
|
+
import type { LoggerOptions } from '../types';
|
5
5
|
import { isReactNative, supportsSetSinkId } from '../utils';
|
6
6
|
import RemoteTrack from './RemoteTrack';
|
7
7
|
import { Track } from './Track';
|
@@ -28,8 +28,9 @@ export default class RemoteAudioTrack extends RemoteTrack {
|
|
28
28
|
receiver?: RTCRtpReceiver,
|
29
29
|
audioContext?: AudioContext,
|
30
30
|
audioOutput?: AudioOutputOptions,
|
31
|
+
loggerOptions?: LoggerOptions,
|
31
32
|
) {
|
32
|
-
super(mediaTrack, sid, Track.Kind.Audio, receiver);
|
33
|
+
super(mediaTrack, sid, Track.Kind.Audio, receiver, loggerOptions);
|
33
34
|
this.audioContext = audioContext;
|
34
35
|
this.webAudioPluginNodes = [];
|
35
36
|
if (audioOutput) {
|
@@ -107,7 +108,7 @@ export default class RemoteAudioTrack extends RemoteTrack {
|
|
107
108
|
element.setSinkId(this.sinkId);
|
108
109
|
}
|
109
110
|
if (this.audioContext && needsNewWebAudioConnection) {
|
110
|
-
log.debug('using audio context mapping');
|
111
|
+
this.log.debug('using audio context mapping', this.logContext);
|
111
112
|
this.connectWebAudio(this.audioContext, element);
|
112
113
|
element.volume = 0;
|
113
114
|
element.muted = true;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { TrackEvent } from '../events';
|
2
2
|
import { monitorFrequency } from '../stats';
|
3
|
+
import type { LoggerOptions } from '../types';
|
3
4
|
import { Track } from './Track';
|
4
5
|
|
5
6
|
export default abstract class RemoteTrack extends Track {
|
@@ -11,8 +12,10 @@ export default abstract class RemoteTrack extends Track {
|
|
11
12
|
sid: string,
|
12
13
|
kind: Track.Kind,
|
13
14
|
receiver?: RTCRtpReceiver,
|
15
|
+
loggerOptions?: LoggerOptions,
|
14
16
|
) {
|
15
|
-
super(mediaTrack, kind);
|
17
|
+
super(mediaTrack, kind, loggerOptions);
|
18
|
+
|
16
19
|
this.sid = sid;
|
17
20
|
this.receiver = receiver;
|
18
21
|
}
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import log from '../../logger';
|
2
1
|
import {
|
3
2
|
ParticipantTracks,
|
4
3
|
SubscriptionError,
|
@@ -7,6 +6,7 @@ import {
|
|
7
6
|
} from '../../proto/livekit_models_pb';
|
8
7
|
import { UpdateSubscription, UpdateTrackSettings } from '../../proto/livekit_rtc_pb';
|
9
8
|
import { TrackEvent } from '../events';
|
9
|
+
import type { LoggerOptions } from '../types';
|
10
10
|
import type RemoteTrack from './RemoteTrack';
|
11
11
|
import RemoteVideoTrack from './RemoteVideoTrack';
|
12
12
|
import { Track } from './Track';
|
@@ -31,8 +31,13 @@ export default class RemoteTrackPublication extends TrackPublication {
|
|
31
31
|
|
32
32
|
protected subscriptionError?: SubscriptionError;
|
33
33
|
|
34
|
-
constructor(
|
35
|
-
|
34
|
+
constructor(
|
35
|
+
kind: Track.Kind,
|
36
|
+
ti: TrackInfo,
|
37
|
+
autoSubscribe: boolean | undefined,
|
38
|
+
loggerOptions?: LoggerOptions,
|
39
|
+
) {
|
40
|
+
super(kind, ti.sid, ti.name, loggerOptions);
|
36
41
|
this.subscribed = autoSubscribe;
|
37
42
|
this.updateInfo(ti);
|
38
43
|
}
|
@@ -252,13 +257,14 @@ export default class RemoteTrackPublication extends TrackPublication {
|
|
252
257
|
|
253
258
|
private isManualOperationAllowed(): boolean {
|
254
259
|
if (this.kind === Track.Kind.Video && this.isAdaptiveStream) {
|
255
|
-
log.warn(
|
256
|
-
|
257
|
-
|
260
|
+
this.log.warn(
|
261
|
+
'adaptive stream is enabled, cannot change video track settings',
|
262
|
+
this.logContext,
|
263
|
+
);
|
258
264
|
return false;
|
259
265
|
}
|
260
266
|
if (!this.isDesired) {
|
261
|
-
log.warn('cannot update track settings when not subscribed',
|
267
|
+
this.log.warn('cannot update track settings when not subscribed', this.logContext);
|
262
268
|
return false;
|
263
269
|
}
|
264
270
|
return true;
|
@@ -274,17 +280,19 @@ export default class RemoteTrackPublication extends TrackPublication {
|
|
274
280
|
}
|
275
281
|
|
276
282
|
protected handleVisibilityChange = (visible: boolean) => {
|
277
|
-
log.debug(
|
278
|
-
|
279
|
-
|
283
|
+
this.log.debug(
|
284
|
+
`adaptivestream video visibility ${this.trackSid}, visible=${visible}`,
|
285
|
+
this.logContext,
|
286
|
+
);
|
280
287
|
this.disabled = !visible;
|
281
288
|
this.emitTrackUpdate();
|
282
289
|
};
|
283
290
|
|
284
291
|
protected handleVideoDimensionsChange = (dimensions: Track.Dimensions) => {
|
285
|
-
log.debug(
|
286
|
-
|
287
|
-
|
292
|
+
this.log.debug(
|
293
|
+
`adaptivestream video dimensions ${dimensions.width}x${dimensions.height}`,
|
294
|
+
this.logContext,
|
295
|
+
);
|
288
296
|
this.videoDimensions = dimensions;
|
289
297
|
this.emitTrackUpdate();
|
290
298
|
};
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { debounce } from 'ts-debounce';
|
2
|
-
import log from '../../logger';
|
3
2
|
import { TrackEvent } from '../events';
|
4
3
|
import type { VideoReceiverStats } from '../stats';
|
5
4
|
import { computeBitrate } from '../stats';
|
6
5
|
import CriticalTimers from '../timers';
|
6
|
+
import type { LoggerOptions } from '../types';
|
7
7
|
import type { ObservableMediaElement } from '../utils';
|
8
8
|
import { getDevicePixelRatio, getIntersectionObserver, getResizeObserver, isWeb } from '../utils';
|
9
9
|
import RemoteTrack from './RemoteTrack';
|
@@ -28,8 +28,9 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
28
28
|
sid: string,
|
29
29
|
receiver?: RTCRtpReceiver,
|
30
30
|
adaptiveStreamSettings?: AdaptiveStreamSettings,
|
31
|
+
loggerOptions?: LoggerOptions,
|
31
32
|
) {
|
32
|
-
super(mediaTrack, sid, Track.Kind.Video, receiver);
|
33
|
+
super(mediaTrack, sid, Track.Kind.Video, receiver, loggerOptions);
|
33
34
|
this.adaptiveStreamSettings = adaptiveStreamSettings;
|
34
35
|
}
|
35
36
|
|
@@ -103,7 +104,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
103
104
|
this.debouncedHandleResize();
|
104
105
|
this.updateVisibility();
|
105
106
|
} else {
|
106
|
-
log.warn('visibility resize observer not triggered');
|
107
|
+
this.log.warn('visibility resize observer not triggered', this.logContext);
|
107
108
|
}
|
108
109
|
}
|
109
110
|
|
@@ -114,7 +115,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
114
115
|
*/
|
115
116
|
stopObservingElementInfo(elementInfo: ElementInfo) {
|
116
117
|
if (!this.isAdaptiveStream) {
|
117
|
-
log.warn('stopObservingElementInfo ignored');
|
118
|
+
this.log.warn('stopObservingElementInfo ignored', this.logContext);
|
118
119
|
return;
|
119
120
|
}
|
120
121
|
const stopElementInfos = this.elementInfos.filter((info) => info === elementInfo);
|
package/src/room/track/Track.ts
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
2
|
import type TypedEventEmitter from 'typed-emitter';
|
3
3
|
import type { SignalClient } from '../../api/SignalClient';
|
4
|
-
import log from '../../logger';
|
4
|
+
import log, { LoggerNames, StructuredLogger, getLogger } from '../../logger';
|
5
5
|
import { TrackSource, TrackType } from '../../proto/livekit_models_pb';
|
6
6
|
import { StreamState as ProtoStreamState } from '../../proto/livekit_rtc_pb';
|
7
7
|
import { TrackEvent } from '../events';
|
8
|
+
import type { LoggerOptions } from '../types';
|
8
9
|
import { isFireFox, isSafari, isWeb } from '../utils';
|
10
|
+
import { getLogContextFromTrack } from './utils';
|
9
11
|
|
10
12
|
const BACKGROUND_REACTION_DELAY = 5000;
|
11
13
|
|
@@ -46,12 +48,23 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
46
48
|
|
47
49
|
private backgroundTimeout: ReturnType<typeof setTimeout> | undefined;
|
48
50
|
|
51
|
+
private loggerContextCb: LoggerOptions['loggerContextCb'];
|
52
|
+
|
49
53
|
protected _currentBitrate: number = 0;
|
50
54
|
|
51
55
|
protected monitorInterval?: ReturnType<typeof setInterval>;
|
52
56
|
|
53
|
-
protected
|
57
|
+
protected log: StructuredLogger = log;
|
58
|
+
|
59
|
+
protected constructor(
|
60
|
+
mediaTrack: MediaStreamTrack,
|
61
|
+
kind: Track.Kind,
|
62
|
+
loggerOptions: LoggerOptions = {},
|
63
|
+
) {
|
54
64
|
super();
|
65
|
+
this.log = getLogger(loggerOptions.loggerName ?? LoggerNames.Track);
|
66
|
+
this.loggerContextCb = loggerOptions.loggerContextCb;
|
67
|
+
|
55
68
|
this.setMaxListeners(100);
|
56
69
|
this.kind = kind;
|
57
70
|
this._mediaStreamTrack = mediaTrack;
|
@@ -59,6 +72,13 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
59
72
|
this.source = Track.Source.Unknown;
|
60
73
|
}
|
61
74
|
|
75
|
+
protected get logContext() {
|
76
|
+
return {
|
77
|
+
...this.loggerContextCb?.(),
|
78
|
+
...getLogContextFromTrack(this),
|
79
|
+
};
|
80
|
+
}
|
81
|
+
|
62
82
|
/** current receive bits per second */
|
63
83
|
get currentBitrate(): number {
|
64
84
|
return this._currentBitrate;
|
@@ -224,6 +244,16 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
224
244
|
}
|
225
245
|
}
|
226
246
|
|
247
|
+
/** @internal */
|
248
|
+
updateLoggerOptions(loggerOptions: LoggerOptions) {
|
249
|
+
if (loggerOptions.loggerName) {
|
250
|
+
this.log = getLogger(loggerOptions.loggerName);
|
251
|
+
}
|
252
|
+
if (loggerOptions.loggerContextCb) {
|
253
|
+
this.loggerContextCb = loggerOptions.loggerContextCb;
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
227
257
|
private recycleElement(element: HTMLMediaElement) {
|
228
258
|
if (element instanceof HTMLAudioElement) {
|
229
259
|
// we only need to re-use a single element
|