livekit-client 1.15.6 → 1.15.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) 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 +558 -327
  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/track/LocalAudioTrack.d.ts +2 -1
  33. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  34. package/dist/src/room/track/LocalTrack.d.ts +2 -1
  35. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  36. package/dist/src/room/track/LocalTrackPublication.d.ts +2 -1
  37. package/dist/src/room/track/LocalTrackPublication.d.ts.map +1 -1
  38. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
  39. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  40. package/dist/src/room/track/RemoteAudioTrack.d.ts +2 -1
  41. package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
  42. package/dist/src/room/track/RemoteTrack.d.ts +2 -1
  43. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  44. package/dist/src/room/track/RemoteTrackPublication.d.ts +2 -1
  45. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  46. package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
  47. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  48. package/dist/src/room/track/Track.d.ts +10 -1
  49. package/dist/src/room/track/Track.d.ts.map +1 -1
  50. package/dist/src/room/track/TrackPublication.d.ts +7 -1
  51. package/dist/src/room/track/TrackPublication.d.ts.map +1 -1
  52. package/dist/src/room/track/create.d.ts.map +1 -1
  53. package/dist/src/room/track/options.d.ts +8 -3
  54. package/dist/src/room/track/options.d.ts.map +1 -1
  55. package/dist/src/room/track/utils.d.ts +1 -0
  56. package/dist/src/room/track/utils.d.ts.map +1 -1
  57. package/dist/src/room/types.d.ts +4 -0
  58. package/dist/src/room/types.d.ts.map +1 -1
  59. package/dist/src/room/utils.d.ts +1 -0
  60. package/dist/src/room/utils.d.ts.map +1 -1
  61. package/dist/ts4.2/src/api/SignalClient.d.ts +5 -1
  62. package/dist/ts4.2/src/index.d.ts +2 -2
  63. package/dist/ts4.2/src/logger.d.ts +19 -3
  64. package/dist/ts4.2/src/options.d.ts +1 -0
  65. package/dist/ts4.2/src/room/PCTransport.d.ts +5 -1
  66. package/dist/ts4.2/src/room/PCTransportManager.d.ts +5 -1
  67. package/dist/ts4.2/src/room/RTCEngine.d.ts +8 -0
  68. package/dist/ts4.2/src/room/Room.d.ts +2 -0
  69. package/dist/ts4.2/src/room/participant/Participant.d.ts +9 -1
  70. package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
  71. package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
  72. package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +2 -1
  73. package/dist/ts4.2/src/room/track/LocalTrack.d.ts +2 -1
  74. package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -1
  75. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
  76. package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
  77. package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -1
  78. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +2 -1
  79. package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
  80. package/dist/ts4.2/src/room/track/Track.d.ts +10 -1
  81. package/dist/ts4.2/src/room/track/TrackPublication.d.ts +7 -1
  82. package/dist/ts4.2/src/room/track/options.d.ts +8 -3
  83. package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
  84. package/dist/ts4.2/src/room/types.d.ts +4 -0
  85. package/dist/ts4.2/src/room/utils.d.ts +1 -0
  86. package/package.json +2 -2
  87. package/src/api/SignalClient.ts +43 -21
  88. package/src/index.ts +2 -1
  89. package/src/logger.ts +32 -8
  90. package/src/options.ts +2 -0
  91. package/src/room/PCTransport.ts +29 -8
  92. package/src/room/PCTransportManager.ts +29 -9
  93. package/src/room/RTCEngine.ts +71 -34
  94. package/src/room/Room.ts +94 -30
  95. package/src/room/participant/LocalParticipant.ts +163 -47
  96. package/src/room/participant/Participant.ts +26 -3
  97. package/src/room/participant/RemoteParticipant.ts +23 -15
  98. package/src/room/participant/publishUtils.test.ts +2 -2
  99. package/src/room/participant/publishUtils.ts +7 -4
  100. package/src/room/track/LocalAudioTrack.ts +8 -7
  101. package/src/room/track/LocalTrack.ts +23 -19
  102. package/src/room/track/LocalTrackPublication.ts +3 -2
  103. package/src/room/track/LocalVideoTrack.ts +31 -13
  104. package/src/room/track/RemoteAudioTrack.ts +4 -3
  105. package/src/room/track/RemoteTrack.ts +4 -1
  106. package/src/room/track/RemoteTrackPublication.ts +21 -13
  107. package/src/room/track/RemoteVideoTrack.ts +5 -4
  108. package/src/room/track/Track.ts +32 -2
  109. package/src/room/track/TrackPublication.ts +18 -3
  110. package/src/room/track/create.ts +4 -3
  111. package/src/room/track/options.ts +12 -5
  112. package/src/room/track/utils.ts +23 -1
  113. package/src/room/types.ts +5 -0
  114. package/src/room/utils.ts +5 -0
@@ -7,7 +7,7 @@ import {
7
7
  SignalConnectionState,
8
8
  toProtoSessionDescription,
9
9
  } from '../api/SignalClient';
10
- import log from '../logger';
10
+ import log, { LoggerNames, getLogger } from '../logger';
11
11
  import type { InternalRoomOptions } from '../options';
12
12
  import {
13
13
  ClientConfigSetting,
@@ -61,6 +61,7 @@ import type RemoteTrackPublication from './track/RemoteTrackPublication';
61
61
  import { Track } from './track/Track';
62
62
  import type { TrackPublishOptions, VideoCodec } from './track/options';
63
63
  import { getTrackPublicationInfo } from './track/utils';
64
+ import type { LoggerOptions } from './types';
64
65
  import {
65
66
  Mutex,
66
67
  isVideoCodec,
@@ -162,9 +163,18 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
162
163
 
163
164
  private regionUrlProvider?: RegionUrlProvider;
164
165
 
166
+ private log = log;
167
+
168
+ private loggerOptions: LoggerOptions;
169
+
165
170
  constructor(private options: InternalRoomOptions) {
166
171
  super();
167
- this.client = new SignalClient();
172
+ this.log = getLogger(options.loggerName ?? LoggerNames.Engine);
173
+ this.loggerOptions = {
174
+ loggerName: options.loggerName,
175
+ loggerContextCb: () => this.logContext,
176
+ };
177
+ this.client = new SignalClient(undefined, this.loggerOptions);
168
178
  this.client.signalLatency = this.options.expSignalLatency;
169
179
  this.reconnectPolicy = this.options.reconnectPolicy;
170
180
  this.registerOnLineListener();
@@ -187,6 +197,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
187
197
  this.client.onStreamStateUpdate = (update) => this.emit(EngineEvent.StreamStateChanged, update);
188
198
  }
189
199
 
200
+ /** @internal */
201
+ get logContext() {
202
+ return {
203
+ room: this.latestJoinResponse?.room?.name,
204
+ roomSid: this.latestJoinResponse?.room?.sid,
205
+ identity: this.latestJoinResponse?.participant?.identity,
206
+ };
207
+ }
208
+
190
209
  async join(
191
210
  url: string,
192
211
  token: string,
@@ -220,8 +239,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
220
239
  } catch (e) {
221
240
  if (e instanceof ConnectionError) {
222
241
  if (e.reason === ConnectionErrorReason.ServerUnreachable) {
223
- log.warn(
242
+ this.log.warn(
224
243
  `Couldn't connect to server, attempt ${this.joinAttempts} of ${this.maxJoinAttempts}`,
244
+ this.logContext,
225
245
  );
226
246
  if (this.joinAttempts < this.maxJoinAttempts) {
227
247
  return this.join(url, token, opts, abortSignal);
@@ -324,7 +344,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
324
344
  this.pcManager!.removeTrack(sender);
325
345
  return true;
326
346
  } catch (e: unknown) {
327
- log.warn('failed to remove track', { error: e, method: 'removeTrack' });
347
+ this.log.warn('failed to remove track', { ...this.logContext, error: e });
328
348
  }
329
349
  return false;
330
350
  }
@@ -356,7 +376,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
356
376
 
357
377
  const rtcConfig = this.makeRTCConfiguration(joinResponse);
358
378
 
359
- this.pcManager = new PCTransportManager(rtcConfig, joinResponse.subscriberPrimary);
379
+ this.pcManager = new PCTransportManager(
380
+ rtcConfig,
381
+ joinResponse.subscriberPrimary,
382
+ this.loggerOptions,
383
+ );
360
384
 
361
385
  this.emit(EngineEvent.TransportsCreated, this.pcManager.publisher, this.pcManager.subscriber);
362
386
 
@@ -370,7 +394,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
370
394
 
371
395
  this.pcManager.onDataChannel = this.handleDataChannel;
372
396
  this.pcManager.onStateChange = async (connectionState, publisherState, subscriberState) => {
373
- log.debug(`primary PC state changed ${connectionState}`);
397
+ this.log.debug(`primary PC state changed ${connectionState}`, this.logContext);
374
398
  if (connectionState === PCTransportState.CONNECTED) {
375
399
  const shouldEmit = this.pcState === PCState.New;
376
400
  this.pcState = PCState.Connected;
@@ -404,9 +428,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
404
428
  if (!this.pcManager) {
405
429
  return;
406
430
  }
407
- log.debug('received server answer', {
408
- RTCSdpType: sd.type,
409
- });
431
+ this.log.debug('received server answer', { ...this.logContext, RTCSdpType: sd.type });
410
432
  await this.pcManager.setPublisherAnswer(sd);
411
433
  };
412
434
 
@@ -415,7 +437,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
415
437
  if (!this.pcManager) {
416
438
  return;
417
439
  }
418
- log.trace('got ICE candidate from peer', { candidate, target });
440
+ this.log.trace('got ICE candidate from peer', { ...this.logContext, candidate, target });
419
441
  this.pcManager.addIceCandidate(candidate, target);
420
442
  };
421
443
 
@@ -429,9 +451,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
429
451
  };
430
452
 
431
453
  this.client.onLocalTrackPublished = (res: TrackPublishedResponse) => {
432
- log.debug('received trackPublishedResponse', res);
454
+ this.log.debug('received trackPublishedResponse', {
455
+ ...this.logContext,
456
+ cid: res.cid,
457
+ track: res.track?.sid,
458
+ });
433
459
  if (!this.pendingTrackResolvers[res.cid]) {
434
- log.error(`missing track resolver for ${res.cid}`);
460
+ this.log.error(`missing track resolver for ${res.cid}`, {
461
+ ...this.logContext,
462
+ cid: res.cid,
463
+ });
435
464
  return;
436
465
  }
437
466
  const { resolve } = this.pendingTrackResolvers[res.cid];
@@ -464,7 +493,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
464
493
  this.emit(EngineEvent.Disconnected, leave?.reason);
465
494
  this.close();
466
495
  }
467
- log.trace('leave request', { leave });
496
+ this.log.debug('client leave request', { ...this.logContext, reason: leave?.reason });
468
497
  };
469
498
  }
470
499
 
@@ -472,7 +501,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
472
501
  const rtcConfig = { ...this.rtcConfig };
473
502
 
474
503
  if (this.signalOpts?.e2eeEnabled) {
475
- log.debug('E2EE - setting up transports with insertable streams');
504
+ this.log.debug('E2EE - setting up transports with insertable streams', this.logContext);
476
505
  // this makes sure that no data is sent before the transforms are ready
477
506
  // @ts-ignore
478
507
  rtcConfig.encodedInsertableStreams = true;
@@ -562,7 +591,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
562
591
  } else {
563
592
  return;
564
593
  }
565
- log.debug(`on data channel ${channel.id}, ${channel.label}`);
594
+ this.log.debug(`on data channel ${channel.id}, ${channel.label}`, this.logContext);
566
595
  channel.onmessage = this.handleDataMessage;
567
596
  };
568
597
 
@@ -577,7 +606,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
577
606
  } else if (message.data instanceof Blob) {
578
607
  buffer = await message.data.arrayBuffer();
579
608
  } else {
580
- log.error('unsupported data type', message.data);
609
+ this.log.error('unsupported data type', { ...this.logContext, data: message.data });
581
610
  return;
582
611
  }
583
612
  const dp = DataPacket.fromBinary(new Uint8Array(buffer));
@@ -598,9 +627,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
598
627
 
599
628
  if (event instanceof ErrorEvent && event.error) {
600
629
  const { error } = event.error;
601
- log.error(`DataChannel error on ${channelKind}: ${event.message}`, error);
630
+ this.log.error(`DataChannel error on ${channelKind}: ${event.message}`, {
631
+ ...this.logContext,
632
+ error,
633
+ });
602
634
  } else {
603
- log.error(`Unknown DataChannel error on ${channelKind}`, event);
635
+ this.log.error(`Unknown DataChannel error on ${channelKind}`, { ...this.logContext, event });
604
636
  }
605
637
  };
606
638
 
@@ -622,7 +654,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
622
654
  }
623
655
  const cap = RTCRtpSender.getCapabilities(kind);
624
656
  if (!cap) return;
625
- log.debug('get capabilities', cap);
657
+ this.log.debug('get sender capabilities', { ...this.logContext, cap });
626
658
  const matched: RTCRtpCodecCapability[] = [];
627
659
  const partialMatched: RTCRtpCodecCapability[] = [];
628
660
  const unmatched: RTCRtpCodecCapability[] = [];
@@ -666,7 +698,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
666
698
  return sender;
667
699
  }
668
700
  if (supportsAddTrack()) {
669
- log.warn('using add-track fallback');
701
+ this.log.warn('using add-track fallback', this.logContext);
670
702
  const sender = await this.createRTCRtpSender(track.mediaStreamTrack);
671
703
  return sender;
672
704
  }
@@ -684,7 +716,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
684
716
  return this.createSimulcastTransceiverSender(track, simulcastTrack, opts, encodings);
685
717
  }
686
718
  if (supportsAddTrack()) {
687
- log.debug('using add-track fallback');
719
+ this.log.debug('using add-track fallback', this.logContext);
688
720
  return this.createRTCRtpSender(track.mediaStreamTrack);
689
721
  }
690
722
 
@@ -764,15 +796,16 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
764
796
  return;
765
797
  }
766
798
 
767
- log.warn(`${connection} disconnected`);
799
+ this.log.warn(`${connection} disconnected`, this.logContext);
768
800
  if (this.reconnectAttempts === 0) {
769
801
  // only reset start time on the first try
770
802
  this.reconnectStart = Date.now();
771
803
  }
772
804
 
773
805
  const disconnect = (duration: number) => {
774
- log.warn(
806
+ this.log.warn(
775
807
  `could not recover connection after ${this.reconnectAttempts} attempts, ${duration}ms. giving up`,
808
+ this.logContext,
776
809
  );
777
810
  this.emit(EngineEvent.Disconnected);
778
811
  this.close();
@@ -792,7 +825,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
792
825
  delay = 0;
793
826
  }
794
827
 
795
- log.debug(`reconnecting in ${delay}ms`);
828
+ this.log.debug(`reconnecting in ${delay}ms`, this.logContext);
796
829
 
797
830
  this.clearReconnectTimeout();
798
831
  if (this.token && this.regionUrlProvider) {
@@ -836,7 +869,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
836
869
  this.reconnectAttempts += 1;
837
870
  let recoverable = true;
838
871
  if (e instanceof UnexpectedConnectionState) {
839
- log.debug('received unrecoverable error', { error: e });
872
+ this.log.debug('received unrecoverable error', { ...this.logContext, error: e });
840
873
  // unrecoverable
841
874
  recoverable = false;
842
875
  } else if (!(e instanceof SignalReconnectError)) {
@@ -847,10 +880,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
847
880
  if (recoverable) {
848
881
  this.handleDisconnect('reconnect', ReconnectReason.RR_UNKNOWN);
849
882
  } else {
850
- log.info(
883
+ this.log.info(
851
884
  `could not recover connection after ${this.reconnectAttempts} attempts, ${
852
885
  Date.now() - this.reconnectStart
853
886
  }ms. giving up`,
887
+ this.logContext,
854
888
  );
855
889
  this.emit(EngineEvent.Disconnected);
856
890
  await this.close();
@@ -864,7 +898,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
864
898
  try {
865
899
  return this.reconnectPolicy.nextRetryDelayInMs(context);
866
900
  } catch (e) {
867
- log.warn('encountered error in reconnect policy', { error: e });
901
+ this.log.warn('encountered error in reconnect policy', { ...this.logContext, error: e });
868
902
  }
869
903
 
870
904
  // error in user code with provided reconnect policy, stop reconnecting
@@ -878,7 +912,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
878
912
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
879
913
  }
880
914
 
881
- log.info(`reconnecting, attempt: ${this.reconnectAttempts}`);
915
+ this.log.info(`reconnecting, attempt: ${this.reconnectAttempts}`, this.logContext);
882
916
  this.emit(EngineEvent.Restarting);
883
917
 
884
918
  if (!this.client.isDisconnected) {
@@ -890,7 +924,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
890
924
  let joinResponse: JoinResponse;
891
925
  try {
892
926
  if (!this.signalOpts) {
893
- log.warn('attempted connection restart, without signal options present');
927
+ this.log.warn(
928
+ 'attempted connection restart, without signal options present',
929
+ this.logContext,
930
+ );
894
931
  throw new SignalReconnectError();
895
932
  }
896
933
  // in case a regionUrl is passed, the region URL takes precedence
@@ -937,7 +974,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
937
974
  throw new UnexpectedConnectionState('publisher and subscriber connections unset');
938
975
  }
939
976
 
940
- log.info(`resuming signal connection, attempt ${this.reconnectAttempts}`);
977
+ this.log.info(`resuming signal connection, attempt ${this.reconnectAttempts}`, this.logContext);
941
978
  this.emit(EngineEvent.Resuming);
942
979
 
943
980
  try {
@@ -951,7 +988,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
951
988
  let message = '';
952
989
  if (e instanceof Error) {
953
990
  message = e.message;
954
- log.error(e.message);
991
+ this.log.error(e.message, this.logContext);
955
992
  }
956
993
  if (e instanceof ConnectionError && e.reason === ConnectionErrorReason.NotAllowed) {
957
994
  throw new UnexpectedConnectionState('could not reconnect, token might be expired');
@@ -990,7 +1027,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
990
1027
  private async waitForPCReconnected() {
991
1028
  this.pcState = PCState.Reconnecting;
992
1029
 
993
- log.debug('waiting for peer connection to reconnect');
1030
+ this.log.debug('waiting for peer connection to reconnect', this.logContext);
994
1031
  try {
995
1032
  await sleep(minReconnectWait); // FIXME setTimeout again not ideal for a connection critical path
996
1033
  if (!this.pcManager) {
@@ -1136,7 +1173,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1136
1173
 
1137
1174
  const handleClosed = () => {
1138
1175
  abortController.abort();
1139
- log.debug('engine disconnected while negotiation was ongoing');
1176
+ this.log.debug('engine disconnected while negotiation was ongoing', this.logContext);
1140
1177
  resolve();
1141
1178
  return;
1142
1179
  };
@@ -1196,7 +1233,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1196
1233
  /** @internal */
1197
1234
  sendSyncState(remoteTracks: RemoteTrackPublication[], localTracks: LocalTrackPublication[]) {
1198
1235
  if (!this.pcManager) {
1199
- log.warn('sync state cannot be sent without peer connection setup');
1236
+ this.log.warn('sync state cannot be sent without peer connection setup', this.logContext);
1200
1237
  return;
1201
1238
  }
1202
1239
  const previousAnswer = this.pcManager.subscriber.getLocalDescription();
package/src/room/Room.ts CHANGED
@@ -4,7 +4,7 @@ import type TypedEmitter from 'typed-emitter';
4
4
  import 'webrtc-adapter';
5
5
  import { EncryptionEvent } from '../e2ee';
6
6
  import { E2EEManager } from '../e2ee/E2eeManager';
7
- import log from '../logger';
7
+ import log, { LoggerNames, getLogger } from '../logger';
8
8
  import type {
9
9
  InternalRoomConnectOptions,
10
10
  InternalRoomOptions,
@@ -151,6 +151,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
151
151
 
152
152
  private isVideoPlaybackBlocked: boolean = false;
153
153
 
154
+ private log = log;
155
+
154
156
  /**
155
157
  * Creates a new Room, the primary construct for a LiveKit session.
156
158
  * @param options
@@ -163,6 +165,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
163
165
  this.identityToSid = new Map();
164
166
  this.options = { ...roomOptionDefaults, ...options };
165
167
 
168
+ this.log = getLogger(this.options.loggerName ?? LoggerNames.Room);
169
+
166
170
  this.options.audioCaptureDefaults = {
167
171
  ...audioDefaults,
168
172
  ...options?.audioCaptureDefaults,
@@ -198,7 +202,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
198
202
  this.switchActiveDevice(
199
203
  'audiooutput',
200
204
  unwrapConstraint(this.options.audioOutput.deviceId),
201
- ).catch((e) => log.warn(`Could not set audio output: ${e.message}`));
205
+ ).catch((e) => this.log.warn(`Could not set audio output: ${e.message}`, this.logContext));
202
206
  }
203
207
 
204
208
  if (this.options.e2ee) {
@@ -239,6 +243,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
239
243
  }
240
244
  }
241
245
 
246
+ private get logContext() {
247
+ return {
248
+ room: this.name,
249
+ roomSid: this.sid,
250
+ identity: this.localParticipant.identity,
251
+ };
252
+ }
253
+
242
254
  /**
243
255
  * if the current room has a participant with `recorder: true` in its JWT grant
244
256
  **/
@@ -362,7 +374,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
362
374
  if (this.state !== ConnectionState.Disconnected) {
363
375
  return;
364
376
  }
365
- log.debug(`prepareConnection to ${url}`);
377
+ this.log.debug(`prepareConnection to ${url}`, this.logContext);
366
378
  try {
367
379
  if (isCloud(new URL(url)) && token) {
368
380
  this.regionUrlProvider = new RegionUrlProvider(url, token);
@@ -372,13 +384,13 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
372
384
  if (regionUrl && this.state === ConnectionState.Disconnected) {
373
385
  this.regionUrl = regionUrl;
374
386
  await fetch(toHttpUrl(regionUrl), { method: 'HEAD' });
375
- log.debug(`prepared connection to ${regionUrl}`);
387
+ this.log.debug(`prepared connection to ${regionUrl}`, this.logContext);
376
388
  }
377
389
  } else {
378
390
  await fetch(toHttpUrl(url), { method: 'HEAD' });
379
391
  }
380
392
  } catch (e) {
381
- log.warn('could not prepare connection', { error: e });
393
+ this.log.warn('could not prepare connection', { ...this.logContext, error: e });
382
394
  }
383
395
  }
384
396
 
@@ -388,7 +400,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
388
400
 
389
401
  if (this.state === ConnectionState.Connected) {
390
402
  // when the state is reconnecting or connected, this function returns immediately
391
- log.info(`already connected to room ${this.name}`);
403
+ this.log.info(`already connected to room ${this.name}`, this.logContext);
392
404
  unlockDisconnect();
393
405
  return Promise.resolve();
394
406
  }
@@ -413,7 +425,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
413
425
  // if initial connection fails, this will speed up picking regional url
414
426
  // on subsequent runs
415
427
  this.regionUrlProvider.fetchRegionSettings().catch((e) => {
416
- log.warn('could not fetch region settings', { error: e });
428
+ this.log.warn('could not fetch region settings', { ...this.logContext, error: e });
417
429
  });
418
430
  }
419
431
 
@@ -460,8 +472,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
460
472
  }
461
473
  }
462
474
  if (nextUrl) {
463
- log.info(
475
+ this.log.info(
464
476
  `Initial connection failed with ConnectionError: ${e.message}. Retrying with another region: ${nextUrl}`,
477
+ this.logContext,
465
478
  );
466
479
  await connectFn(resolve, reject, nextUrl);
467
480
  } else {
@@ -517,10 +530,15 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
517
530
  serverInfo = { version: joinResponse.serverVersion, region: joinResponse.serverRegion };
518
531
  }
519
532
 
520
- log.debug(
533
+ this.log.debug(
521
534
  `connected to Livekit Server ${Object.entries(serverInfo)
522
535
  .map(([key, value]) => `${key}: ${value}`)
523
536
  .join(', ')}`,
537
+ {
538
+ room: joinResponse.room?.name,
539
+ roomSid: joinResponse.room?.sid,
540
+ identity: joinResponse.participant?.identity,
541
+ },
524
542
  );
525
543
 
526
544
  if (!joinResponse.serverVersion) {
@@ -528,7 +546,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
528
546
  }
529
547
 
530
548
  if (joinResponse.serverVersion === '0.15.1' && this.options.dynacast) {
531
- log.debug('disabling dynacast due to server version');
549
+ this.log.debug('disabling dynacast due to server version', this.logContext);
532
550
  // dynacast has a bug in 0.15.1, so we cannot use it then
533
551
  roomOptions.dynacast = false;
534
552
  }
@@ -561,7 +579,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
561
579
  abortController: AbortController,
562
580
  ) => {
563
581
  if (this.state === ConnectionState.Reconnecting) {
564
- log.info('Reconnection attempt replaced by new connection attempt');
582
+ this.log.info('Reconnection attempt replaced by new connection attempt', this.logContext);
565
583
  // make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
566
584
  this.recreateEngine();
567
585
  } else {
@@ -608,7 +626,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
608
626
  resultingError.reason = err.reason;
609
627
  resultingError.status = err.status;
610
628
  }
611
- log.debug(`error trying to establish signal connection`, { error: err });
629
+ this.log.debug(`error trying to establish signal connection`, {
630
+ ...this.logContext,
631
+ error: err,
632
+ });
612
633
  throw resultingError;
613
634
  }
614
635
 
@@ -651,16 +672,18 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
651
672
  const unlock = await this.disconnectLock.lock();
652
673
  try {
653
674
  if (this.state === ConnectionState.Disconnected) {
654
- log.debug('already disconnected');
675
+ this.log.debug('already disconnected', this.logContext);
655
676
  return;
656
677
  }
657
- log.info('disconnect from room', { identity: this.localParticipant.identity });
678
+ this.log.info('disconnect from room', {
679
+ ...this.logContext,
680
+ });
658
681
  if (
659
682
  this.state === ConnectionState.Connecting ||
660
683
  this.state === ConnectionState.Reconnecting
661
684
  ) {
662
685
  // try aborting pending connection attempt
663
- log.warn('abort connection attempt');
686
+ this.log.warn('abort connection attempt', this.logContext);
664
687
  this.abortController?.abort();
665
688
  // in case the abort controller didn't manage to cancel the connection attempt, reject the connect promise explicitly
666
689
  this.connectFuture?.reject?.(new ConnectionError('Client initiated disconnect'));
@@ -886,8 +909,9 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
886
909
  if (e.name === 'NotAllowedError') {
887
910
  this.handleVideoPlaybackFailed();
888
911
  } else {
889
- log.warn(
912
+ this.log.warn(
890
913
  'Resuming video playback failed, make sure you call `startVideo` directly in a user gesture handler',
914
+ this.logContext,
891
915
  );
892
916
  }
893
917
  });
@@ -1052,7 +1076,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1052
1076
  return;
1053
1077
  }
1054
1078
  if (this.state === ConnectionState.Disconnected) {
1055
- log.warn('skipping incoming track after Room disconnected');
1079
+ this.log.warn('skipping incoming track after Room disconnected', this.logContext);
1056
1080
  return;
1057
1081
  }
1058
1082
  const parts = unpackStreamId(stream.id);
@@ -1064,15 +1088,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1064
1088
  if (streamId && streamId.startsWith('TR')) trackId = streamId;
1065
1089
 
1066
1090
  if (participantId === this.localParticipant.sid) {
1067
- log.warn('tried to create RemoteParticipant for local participant');
1091
+ this.log.warn('tried to create RemoteParticipant for local participant', this.logContext);
1068
1092
  return;
1069
1093
  }
1070
1094
 
1071
1095
  const participant = this.participants.get(participantId) as RemoteParticipant | undefined;
1072
1096
 
1073
1097
  if (!participant) {
1074
- log.error(
1098
+ this.log.error(
1075
1099
  `Tried to add a track for a participant, that's not present. Sid: ${participantId}`,
1100
+ this.logContext,
1076
1101
  );
1077
1102
  return;
1078
1103
  }
@@ -1107,7 +1132,8 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1107
1132
  };
1108
1133
 
1109
1134
  private handleSignalRestarted = async (joinResponse: JoinResponse) => {
1110
- log.debug(`signal reconnected to server`, {
1135
+ this.log.debug(`signal reconnected to server, region ${joinResponse.serverRegion}`, {
1136
+ ...this.logContext,
1111
1137
  region: joinResponse.serverRegion,
1112
1138
  });
1113
1139
 
@@ -1136,12 +1162,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1136
1162
  ) {
1137
1163
  // we need to restart the track before publishing, often a full reconnect
1138
1164
  // is necessary because computer had gone to sleep.
1139
- log.debug('restarting existing track', {
1165
+ this.log.debug('restarting existing track', {
1166
+ ...this.logContext,
1140
1167
  track: pub.trackSid,
1141
1168
  });
1142
1169
  await track.restartTrack();
1143
1170
  }
1144
- log.debug('publishing new track', {
1171
+ this.log.debug('publishing new track', {
1172
+ ...this.logContext,
1145
1173
  track: pub.trackSid,
1146
1174
  });
1147
1175
  await this.localParticipant.publishTrack(track, pub.options);
@@ -1149,12 +1177,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1149
1177
  }),
1150
1178
  );
1151
1179
  } catch (error) {
1152
- log.error('error trying to re-publish tracks after reconnection', { error });
1180
+ this.log.error('error trying to re-publish tracks after reconnection', {
1181
+ ...this.logContext,
1182
+ error,
1183
+ });
1153
1184
  }
1154
1185
 
1155
1186
  try {
1156
1187
  await this.engine.waitForRestarted();
1157
- log.debug(`fully reconnected to server`, {
1188
+ this.log.debug(`fully reconnected to server`, {
1189
+ ...this.logContext,
1158
1190
  region: joinResponse.serverRegion,
1159
1191
  });
1160
1192
  } catch {
@@ -1411,7 +1443,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1411
1443
  };
1412
1444
 
1413
1445
  private handleAudioPlaybackFailed = (e: any) => {
1414
- log.warn('could not playback audio', e);
1446
+ this.log.warn('could not playback audio', { ...this.logContext, error: e });
1415
1447
  if (!this.canPlaybackAudio) {
1416
1448
  return;
1417
1449
  }
@@ -1480,7 +1512,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1480
1512
  try {
1481
1513
  await this.audioContext.resume();
1482
1514
  } catch (e: any) {
1483
- log.warn(e);
1515
+ this.log.warn('Could not resume audio context', { ...this.logContext, error: e });
1484
1516
  }
1485
1517
  }
1486
1518
 
@@ -1502,7 +1534,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1502
1534
  if (info) {
1503
1535
  participant = RemoteParticipant.fromParticipantInfo(this.engine.client, info);
1504
1536
  } else {
1505
- participant = new RemoteParticipant(this.engine.client, id, '', undefined, undefined);
1537
+ participant = new RemoteParticipant(this.engine.client, id, '', undefined, undefined, {
1538
+ loggerContextCb: () => this.logContext,
1539
+ loggerName: this.options.loggerName,
1540
+ });
1506
1541
  }
1507
1542
  if (this.options.expWebAudioMix) {
1508
1543
  participant.setAudioContext(this.audioContext);
@@ -1510,7 +1545,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1510
1545
  if (this.options.audioOutput?.deviceId) {
1511
1546
  participant
1512
1547
  .setAudioOutput(this.options.audioOutput)
1513
- .catch((e) => log.warn(`Could not set audio output: ${e.message}`));
1548
+ .catch((e) => this.log.warn(`Could not set audio output: ${e.message}`, this.logContext));
1514
1549
  }
1515
1550
  return participant;
1516
1551
  }
@@ -1643,7 +1678,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1643
1678
  !this.engine.verifyTransport()
1644
1679
  ) {
1645
1680
  consecutiveFailures++;
1646
- log.warn('detected connection state mismatch', { numFailures: consecutiveFailures });
1681
+ this.log.warn('detected connection state mismatch', {
1682
+ ...this.logContext,
1683
+ numFailures: consecutiveFailures,
1684
+ });
1647
1685
  if (consecutiveFailures >= 3) {
1648
1686
  this.recreateEngine();
1649
1687
  this.handleDisconnect(
@@ -1799,7 +1837,11 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1799
1837
  true,
1800
1838
  true,
1801
1839
  ),
1840
+ undefined,
1841
+ false,
1842
+ { loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
1802
1843
  ),
1844
+ { loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
1803
1845
  );
1804
1846
  // @ts-ignore
1805
1847
  this.localParticipant.addTrackPublication(camPub);
@@ -1817,7 +1859,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1817
1859
  publishOptions.useRealTracks
1818
1860
  ? (await navigator.mediaDevices.getUserMedia({ audio: true })).getAudioTracks()[0]
1819
1861
  : getEmptyAudioStreamTrack(),
1862
+ undefined,
1863
+ false,
1864
+ this.audioContext,
1865
+ { loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
1820
1866
  ),
1867
+ { loggerName: this.options.loggerName, loggerContextCb: () => this.logContext },
1821
1868
  );
1822
1869
  // @ts-ignore
1823
1870
  this.localParticipant.addTrackPublication(audioPub);
@@ -1870,12 +1917,29 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
1870
1917
  ): boolean {
1871
1918
  // active speaker updates are too spammy
1872
1919
  if (event !== RoomEvent.ActiveSpeakersChanged) {
1873
- log.debug(`room event ${event}`, { event, args });
1920
+ // only extract logContext from arguments in order to avoid logging the whole object tree
1921
+ const minimizedArgs = mapArgs(args).filter((arg: unknown) => arg !== undefined);
1922
+ this.log.debug(`room event ${event}`, { ...this.logContext, event, args: minimizedArgs });
1874
1923
  }
1875
1924
  return super.emit(event, ...args);
1876
1925
  }
1877
1926
  }
1878
1927
 
1928
+ function mapArgs(args: unknown[]): any {
1929
+ return args.map((arg: unknown) => {
1930
+ if (!arg) {
1931
+ return;
1932
+ }
1933
+ if (Array.isArray(arg)) {
1934
+ return mapArgs(arg);
1935
+ }
1936
+ if (typeof arg === 'object') {
1937
+ return 'logContext' in arg && arg.logContext;
1938
+ }
1939
+ return arg;
1940
+ });
1941
+ }
1942
+
1879
1943
  export default Room;
1880
1944
 
1881
1945
  export type RoomEventCallbacks = {