livekit-client 1.15.6 → 1.15.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +14 -1
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +556 -348
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/api/SignalClient.d.ts +5 -1
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/index.d.ts +2 -2
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/logger.d.ts +19 -3
  14. package/dist/src/logger.d.ts.map +1 -1
  15. package/dist/src/options.d.ts +1 -0
  16. package/dist/src/options.d.ts.map +1 -1
  17. package/dist/src/room/PCTransport.d.ts +5 -1
  18. package/dist/src/room/PCTransport.d.ts.map +1 -1
  19. package/dist/src/room/PCTransportManager.d.ts +5 -1
  20. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  21. package/dist/src/room/RTCEngine.d.ts +8 -0
  22. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  23. package/dist/src/room/Room.d.ts +2 -0
  24. package/dist/src/room/Room.d.ts.map +1 -1
  25. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  26. package/dist/src/room/participant/Participant.d.ts +9 -1
  27. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  28. package/dist/src/room/participant/RemoteParticipant.d.ts +2 -1
  29. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  30. package/dist/src/room/participant/publishUtils.d.ts +2 -1
  31. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  32. package/dist/src/room/timers.d.ts +5 -4
  33. package/dist/src/room/timers.d.ts.map +1 -1
  34. package/dist/src/room/track/LocalAudioTrack.d.ts +2 -1
  35. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  36. package/dist/src/room/track/LocalTrack.d.ts +2 -1
  37. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  38. package/dist/src/room/track/LocalTrackPublication.d.ts +2 -1
  39. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  40. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
  41. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  42. package/dist/src/room/track/RemoteAudioTrack.d.ts +2 -1
  43. package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
  44. package/dist/src/room/track/RemoteTrack.d.ts +2 -1
  45. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  46. package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -1
  47. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  48. package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
  49. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  50. package/dist/src/room/track/Track.d.ts +10 -1
  51. package/dist/src/room/track/Track.d.ts.map +1 -1
  52. package/dist/src/room/track/TrackPublication.d.ts +7 -1
  53. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  54. package/dist/src/room/track/create.d.ts.map +1 -1
  55. package/dist/src/room/track/options.d.ts +8 -3
  56. package/dist/src/room/track/options.d.ts.map +1 -1
  57. package/dist/src/room/track/utils.d.ts +1 -0
  58. package/dist/src/room/track/utils.d.ts.map +1 -1
  59. package/dist/src/room/types.d.ts +4 -0
  60. package/dist/src/room/types.d.ts.map +1 -1
  61. package/dist/src/room/utils.d.ts +1 -0
  62. package/dist/src/room/utils.d.ts.map +1 -1
  63. package/dist/ts4.2/src/api/SignalClient.d.ts +5 -1
  64. package/dist/ts4.2/src/index.d.ts +2 -2
  65. package/dist/ts4.2/src/logger.d.ts +19 -3
  66. package/dist/ts4.2/src/options.d.ts +1 -0
  67. package/dist/ts4.2/src/room/PCTransport.d.ts +5 -1
  68. package/dist/ts4.2/src/room/PCTransportManager.d.ts +5 -1
  69. package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -0
  70. package/dist/ts4.2/src/room/Room.d.ts +2 -0
  71. package/dist/ts4.2/src/room/participant/Participant.d.ts +9 -1
  72. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
  73. package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
  74. package/dist/ts4.2/src/room/timers.d.ts +5 -4
  75. package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +2 -1
  76. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +2 -1
  77. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -1
  78. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
  79. package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
  80. package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -1
  81. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -1
  82. package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
  83. package/dist/ts4.2/src/room/track/Track.d.ts +10 -1
  84. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -1
  85. package/dist/ts4.2/src/room/track/options.d.ts +8 -3
  86. package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
  87. package/dist/ts4.2/src/room/types.d.ts +4 -0
  88. package/dist/ts4.2/src/room/utils.d.ts +1 -0
  89. package/package.json +2 -2
  90. package/src/api/SignalClient.ts +43 -21
  91. package/src/index.ts +2 -1
  92. package/src/logger.ts +32 -8
  93. package/src/options.ts +2 -0
  94. package/src/room/PCTransport.ts +29 -8
  95. package/src/room/PCTransportManager.ts +29 -9
  96. package/src/room/RTCEngine.ts +71 -34
  97. package/src/room/Room.ts +91 -60
  98. package/src/room/participant/LocalParticipant.ts +165 -47
  99. package/src/room/participant/Participant.ts +26 -3
  100. package/src/room/participant/RemoteParticipant.ts +23 -15
  101. package/src/room/participant/publishUtils.test.ts +2 -2
  102. package/src/room/participant/publishUtils.ts +7 -4
  103. package/src/room/track/LocalAudioTrack.ts +8 -7
  104. package/src/room/track/LocalTrack.ts +23 -19
  105. package/src/room/track/LocalTrackPublication.ts +3 -2
  106. package/src/room/track/LocalVideoTrack.ts +31 -13
  107. package/src/room/track/RemoteAudioTrack.ts +4 -3
  108. package/src/room/track/RemoteTrack.ts +4 -1
  109. package/src/room/track/RemoteTrackPublication.ts +21 -13
  110. package/src/room/track/RemoteVideoTrack.ts +5 -4
  111. package/src/room/track/Track.ts +32 -2
  112. package/src/room/track/TrackPublication.ts +18 -3
  113. package/src/room/track/create.ts +4 -3
  114. package/src/room/track/options.ts +12 -5
  115. package/src/room/track/utils.ts +23 -1
  116. package/src/room/types.ts +5 -0
  117. 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: 3 }];
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 * ((fromPreset.encoding.maxFramerate ?? 30) / t.fps)),
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,7 +129,7 @@ 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
  }
@@ -150,6 +147,11 @@ export default abstract class LocalTrack extends Track {
150
147
  if (this.sender) {
151
148
  await this.sender.replaceTrack(processedTrack ?? newTrack);
152
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
+ }
153
155
  this._mediaStreamTrack = newTrack;
154
156
  if (newTrack) {
155
157
  // sync muted state with the enabled state of the newly provided track
@@ -213,7 +215,7 @@ export default abstract class LocalTrack extends Track {
213
215
  throw new TrackInvalidError('unable to replace an unpublished track');
214
216
  }
215
217
 
216
- log.debug('replace MediaStreamTrack');
218
+ this.log.debug('replace MediaStreamTrack', this.logContext);
217
219
  await this.setMediaStreamTrack(track);
218
220
  // this must be synced *after* setting mediaStreamTrack above, since it relies
219
221
  // on the previous state in order to cleanup
@@ -229,7 +231,7 @@ export default abstract class LocalTrack extends Track {
229
231
  if (!constraints) {
230
232
  constraints = this._constraints;
231
233
  }
232
- log.debug('restarting track with constraints', constraints);
234
+ this.log.debug('restarting track with constraints', { ...this.logContext, constraints });
233
235
 
234
236
  const streamConstraints: MediaStreamConstraints = {
235
237
  audio: false,
@@ -257,7 +259,7 @@ export default abstract class LocalTrack extends Track {
257
259
  const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints);
258
260
  const newTrack = mediaStream.getTracks()[0];
259
261
  newTrack.addEventListener('ended', this.handleEnded);
260
- log.debug('re-acquired MediaStreamTrack');
262
+ this.log.debug('re-acquired MediaStreamTrack', this.logContext);
261
263
 
262
264
  await this.setMediaStreamTrack(newTrack);
263
265
  this._constraints = constraints;
@@ -267,7 +269,7 @@ export default abstract class LocalTrack extends Track {
267
269
  }
268
270
 
269
271
  protected setTrackMuted(muted: boolean) {
270
- log.debug(`setting ${this.kind} track ${muted ? 'muted' : 'unmuted'}`);
272
+ this.log.debug(`setting ${this.kind} track ${muted ? 'muted' : 'unmuted'}`, this.logContext);
271
273
 
272
274
  if (this.isMuted === muted && this._mediaStreamTrack.enabled !== muted) {
273
275
  return;
@@ -290,10 +292,10 @@ export default abstract class LocalTrack extends Track {
290
292
  protected async handleAppVisibilityChanged() {
291
293
  await super.handleAppVisibilityChanged();
292
294
  if (!isMobile()) return;
293
- log.debug(`visibility changed, is in Background: ${this.isInBackground}`);
295
+ this.log.debug(`visibility changed, is in Background: ${this.isInBackground}`, this.logContext);
294
296
 
295
297
  if (!this.isInBackground && this.needsReAcquisition && !this.isUserProvided && !this.isMuted) {
296
- log.debug(`track needs to be reacquired, restarting ${this.source}`);
298
+ this.log.debug(`track needs to be reacquired, restarting ${this.source}`, this.logContext);
297
299
  await this.restart();
298
300
  this.reacquireTrack = false;
299
301
  }
@@ -301,7 +303,7 @@ export default abstract class LocalTrack extends Track {
301
303
 
302
304
  private handleTrackMuteEvent = () =>
303
305
  this.debouncedTrackMuteHandler().catch(() =>
304
- 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),
305
307
  );
306
308
 
307
309
  private debouncedTrackMuteHandler = debounce(async () => {
@@ -345,7 +347,7 @@ export default abstract class LocalTrack extends Track {
345
347
  return;
346
348
  }
347
349
  if (!this.sender) {
348
- log.warn('unable to pause upstream for an unpublished track');
350
+ this.log.warn('unable to pause upstream for an unpublished track', this.logContext);
349
351
  return;
350
352
  }
351
353
 
@@ -369,7 +371,7 @@ export default abstract class LocalTrack extends Track {
369
371
  return;
370
372
  }
371
373
  if (!this.sender) {
372
- log.warn('unable to resume upstream for an unpublished track');
374
+ this.log.warn('unable to resume upstream for an unpublished track', this.logContext);
373
375
  return;
374
376
  }
375
377
  this._isUpstreamPaused = false;
@@ -409,7 +411,7 @@ export default abstract class LocalTrack extends Track {
409
411
  async setProcessor(processor: TrackProcessor<this['kind']>, showProcessedStreamLocally = true) {
410
412
  const unlock = await this.processorLock.lock();
411
413
  try {
412
- log.debug('setting up processor');
414
+ this.log.debug('setting up processor', this.logContext);
413
415
  if (this.processor) {
414
416
  await this.stopProcessor();
415
417
  }
@@ -423,7 +425,9 @@ export default abstract class LocalTrack extends Track {
423
425
 
424
426
  this.processorElement
425
427
  .play()
426
- .catch((error) => log.error('failed to play processor element', { error }));
428
+ .catch((error) =>
429
+ this.log.error('failed to play processor element', { ...this.logContext, error }),
430
+ );
427
431
 
428
432
  const processorOptions = {
429
433
  kind: this.kind,
@@ -461,7 +465,7 @@ export default abstract class LocalTrack extends Track {
461
465
  async stopProcessor() {
462
466
  if (!this.processor) return;
463
467
 
464
- log.debug('stopping processor');
468
+ this.log.debug('stopping processor', this.logContext);
465
469
  this.processor.processedTrack?.stop();
466
470
  await this.processor.destroy();
467
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 log from '../../logger';
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}`, simulcastCodecInfo);
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(this.sender, this.encodings, qualities, this.senderLock);
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(kind: Track.Kind, ti: TrackInfo, autoSubscribe: boolean | undefined) {
35
- super(kind, ti.sid, ti.name);
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('adaptive stream is enabled, cannot change video track settings', {
256
- trackSid: this.trackSid,
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', { trackSid: this.trackSid });
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(`adaptivestream video visibility ${this.trackSid}, visible=${visible}`, {
278
- trackSid: this.trackSid,
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(`adaptivestream video dimensions ${dimensions.width}x${dimensions.height}`, {
286
- trackSid: this.trackSid,
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);
@@ -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 constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind) {
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