livekit-client 2.18.6 → 2.18.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) 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 +2 -2
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +399 -259
  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.map +1 -1
  10. package/dist/src/logger.d.ts +11 -1
  11. package/dist/src/logger.d.ts.map +1 -1
  12. package/dist/src/room/PCTransport.d.ts +13 -3
  13. package/dist/src/room/PCTransport.d.ts.map +1 -1
  14. package/dist/src/room/PCTransportManager.d.ts +3 -1
  15. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  16. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  17. package/dist/src/room/Room.d.ts.map +1 -1
  18. package/dist/src/room/data-track/LocalDataTrack.d.ts +31 -0
  19. package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
  20. package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
  21. package/dist/src/room/data-track/handle.d.ts +1 -0
  22. package/dist/src/room/data-track/handle.d.ts.map +1 -1
  23. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +4 -3
  24. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
  25. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +18 -3
  26. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
  27. package/dist/src/room/data-track/outgoing/types.d.ts +6 -0
  28. package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
  29. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  30. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  31. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  32. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  33. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  34. package/dist/src/room/track/processor/types.d.ts +2 -0
  35. package/dist/src/room/track/processor/types.d.ts.map +1 -1
  36. package/dist/src/utils/subscribeToEvents.d.ts.map +1 -1
  37. package/dist/ts4.2/logger.d.ts +11 -1
  38. package/dist/ts4.2/room/PCTransport.d.ts +13 -3
  39. package/dist/ts4.2/room/PCTransportManager.d.ts +3 -1
  40. package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +31 -0
  41. package/dist/ts4.2/room/data-track/handle.d.ts +1 -0
  42. package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +4 -3
  43. package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +18 -3
  44. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +6 -0
  45. package/dist/ts4.2/room/track/processor/types.d.ts +2 -0
  46. package/package.json +1 -1
  47. package/src/api/SignalClient.ts +19 -31
  48. package/src/logger.test.ts +61 -0
  49. package/src/logger.ts +38 -4
  50. package/src/room/PCTransport.ts +26 -3
  51. package/src/room/PCTransportManager.test.ts +281 -0
  52. package/src/room/PCTransportManager.ts +45 -31
  53. package/src/room/RTCEngine.ts +34 -52
  54. package/src/room/Room.ts +37 -59
  55. package/src/room/data-track/LocalDataTrack.ts +51 -0
  56. package/src/room/data-track/RemoteDataTrack.ts +4 -1
  57. package/src/room/data-track/handle.ts +4 -0
  58. package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +72 -2
  59. package/src/room/data-track/incoming/IncomingDataTrackManager.ts +5 -3
  60. package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +235 -1
  61. package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +45 -3
  62. package/src/room/data-track/outgoing/types.ts +5 -0
  63. package/src/room/participant/LocalParticipant.ts +59 -144
  64. package/src/room/participant/Participant.ts +4 -1
  65. package/src/room/participant/publishUtils.ts +2 -2
  66. package/src/room/track/LocalAudioTrack.ts +1 -0
  67. package/src/room/track/LocalTrack.ts +2 -0
  68. package/src/room/track/processor/types.ts +2 -0
  69. package/src/utils/subscribeToEvents.ts +11 -8
@@ -290,7 +290,7 @@ export default class LocalParticipant extends Participant {
290
290
  if (this.reconnectFuture) {
291
291
  // @throws-transformer ignore - introduced due to adding Throws into Future, investigate this
292
292
  // further
293
- this.reconnectFuture.promise.catch((e) => this.log.warn(e.message, this.logContext));
293
+ this.reconnectFuture.promise.catch((e) => this.log.warn(e.message));
294
294
  this.reconnectFuture?.reject?.(new Error('Got disconnected during reconnection attempt'));
295
295
  this.reconnectFuture = undefined;
296
296
  }
@@ -548,7 +548,7 @@ export default class LocalParticipant extends Participant {
548
548
  options?: VideoCaptureOptions | AudioCaptureOptions | ScreenShareCaptureOptions,
549
549
  publishOptions?: TrackPublishOptions,
550
550
  ) {
551
- this.log.debug('setTrackEnabled', { ...this.logContext, source, enabled });
551
+ this.log.debug('setTrackEnabled', { source, enabled });
552
552
  if (this.republishPromise) {
553
553
  await this.republishPromise;
554
554
  }
@@ -561,10 +561,7 @@ export default class LocalParticipant extends Participant {
561
561
  if (this.pendingPublishing.has(source)) {
562
562
  const pendingTrack = await this.waitForPendingPublicationOfSource(source);
563
563
  if (!pendingTrack) {
564
- this.log.info('waiting for pending publication promise timed out', {
565
- ...this.logContext,
566
- source,
567
- });
564
+ this.log.info('waiting for pending publication promise timed out', { source });
568
565
  }
569
566
  await pendingTrack?.unmute();
570
567
  return pendingTrack;
@@ -612,9 +609,7 @@ export default class LocalParticipant extends Participant {
612
609
  isAudioTrack(localTrack) &&
613
610
  opts.preConnectBuffer
614
611
  ) {
615
- this.log.info('starting preconnect buffer for microphone', {
616
- ...this.logContext,
617
- });
612
+ this.log.info('starting preconnect buffer for microphone');
618
613
  localTrack.startPreConnectBuffer();
619
614
  }
620
615
  }
@@ -622,10 +617,7 @@ export default class LocalParticipant extends Participant {
622
617
  try {
623
618
  const publishPromises: Array<Promise<LocalTrackPublication>> = [];
624
619
  for (const localTrack of localTracks) {
625
- this.log.info('publishing track', {
626
- ...this.logContext,
627
- ...getLogContextFromTrack(localTrack),
628
- });
620
+ this.log.info('publishing track', getLogContextFromTrack(localTrack));
629
621
 
630
622
  publishPromises.push(this.publishTrack(localTrack, publishOptions));
631
623
  }
@@ -648,10 +640,7 @@ export default class LocalParticipant extends Participant {
648
640
  // if there's no track available yet first wait for pending publishing promises of that source to see if it becomes available
649
641
  track = await this.waitForPendingPublicationOfSource(source);
650
642
  if (!track) {
651
- this.log.info('waiting for pending publication promise timed out', {
652
- ...this.logContext,
653
- source,
654
- });
643
+ this.log.info('waiting for pending publication promise timed out', { source });
655
644
  }
656
645
  }
657
646
  if (track && track.track) {
@@ -917,10 +906,10 @@ export default class LocalParticipant extends Participant {
917
906
  });
918
907
 
919
908
  if (existingPublication) {
920
- this.log.warn('track has already been published, skipping', {
921
- ...this.logContext,
922
- ...getLogContextFromTrack(existingPublication),
923
- });
909
+ this.log.warn(
910
+ 'track has already been published, skipping',
911
+ getLogContextFromTrack(existingPublication),
912
+ );
924
913
  return existingPublication;
925
914
  }
926
915
 
@@ -938,16 +927,13 @@ export default class LocalParticipant extends Participant {
938
927
  // disable dtx for stereo track if not enabled explicitly
939
928
  if (isStereo) {
940
929
  if (opts.dtx === undefined) {
941
- this.log.info(
930
+ this.log.debug(
942
931
  `Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work.`,
943
- {
944
- ...this.logContext,
945
- ...getLogContextFromTrack(track),
946
- },
932
+ getLogContextFromTrack(track),
947
933
  );
948
934
  }
949
935
  if (opts.red === undefined) {
950
- this.log.info(
936
+ this.log.debug(
951
937
  `Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work.`,
952
938
  );
953
939
  }
@@ -958,9 +944,6 @@ export default class LocalParticipant extends Participant {
958
944
  if (!isE2EESimulcastSupported() && this.roomOptions.e2ee) {
959
945
  this.log.info(
960
946
  `End-to-end encryption is set up, simulcast publishing will be disabled on Safari versions and iOS browsers running iOS < v17.2`,
961
- {
962
- ...this.logContext,
963
- },
964
947
  );
965
948
  opts.simulcast = false;
966
949
  }
@@ -972,7 +955,6 @@ export default class LocalParticipant extends Participant {
972
955
  try {
973
956
  if (this.engine.client.currentState !== SignalConnectionState.CONNECTED) {
974
957
  this.log.debug('deferring track publication until signal is connected', {
975
- ...this.logContext,
976
958
  track: getLogContextFromTrack(track),
977
959
  });
978
960
 
@@ -1014,7 +996,6 @@ export default class LocalParticipant extends Participant {
1014
996
  } catch (e) {
1015
997
  if (!hasRetriedAfterNegotiationError && e instanceof NegotiationError) {
1016
998
  this.log.warn('negotiation due to track publish failed, retrying after reconnect', {
1017
- ...this.logContext,
1018
999
  error: e,
1019
1000
  });
1020
1001
  this.pendingPublishPromises.delete(track);
@@ -1036,10 +1017,7 @@ export default class LocalParticipant extends Participant {
1036
1017
 
1037
1018
  private hasPermissionsToPublish(track: LocalTrack): boolean {
1038
1019
  if (!this.permissions) {
1039
- this.log.warn('no permissions present for publishing track', {
1040
- ...this.logContext,
1041
- ...getLogContextFromTrack(track),
1042
- });
1020
+ this.log.warn('no permissions present for publishing track', getLogContextFromTrack(track));
1043
1021
  return false;
1044
1022
  }
1045
1023
  const { canPublish, canPublishSources } = this.permissions;
@@ -1050,10 +1028,7 @@ export default class LocalParticipant extends Participant {
1050
1028
  ) {
1051
1029
  return true;
1052
1030
  }
1053
- this.log.warn('insufficient permissions to publish', {
1054
- ...this.logContext,
1055
- ...getLogContextFromTrack(track),
1056
- });
1031
+ this.log.warn('insufficient permissions to publish', getLogContextFromTrack(track));
1057
1032
  return false;
1058
1033
  }
1059
1034
 
@@ -1065,10 +1040,10 @@ export default class LocalParticipant extends Participant {
1065
1040
  (publishedTrack) => isLocalTrack(track) && publishedTrack.source === track.source,
1066
1041
  );
1067
1042
  if (existingTrackOfSource && track.source !== Track.Source.Unknown) {
1068
- this.log.info(`publishing a second track with the same source: ${track.source}`, {
1069
- ...this.logContext,
1070
- ...getLogContextFromTrack(track),
1071
- });
1043
+ this.log.info(
1044
+ `publishing a second track with the same source: ${track.source}`,
1045
+ getLogContextFromTrack(track),
1046
+ );
1072
1047
  }
1073
1048
  if (opts.stopMicTrackOnMute && isAudioTrack(track)) {
1074
1049
  track.stopOnMute = true;
@@ -1172,7 +1147,6 @@ export default class LocalParticipant extends Participant {
1172
1147
  };
1173
1148
  // log failure
1174
1149
  this.log.error('could not determine track dimensions, using defaults', {
1175
- ...this.logContext,
1176
1150
  ...getLogContextFromTrack(track),
1177
1151
  dims,
1178
1152
  });
@@ -1194,10 +1168,10 @@ export default class LocalParticipant extends Participant {
1194
1168
  // that we need
1195
1169
  if ('contentHint' in track.mediaStreamTrack) {
1196
1170
  track.mediaStreamTrack.contentHint = 'motion';
1197
- this.log.info('forcing contentHint to motion for screenshare with SVC codecs', {
1198
- ...this.logContext,
1199
- ...getLogContextFromTrack(track),
1200
- });
1171
+ this.log.debug(
1172
+ 'forcing contentHint to motion for screenshare with SVC codecs',
1173
+ getLogContextFromTrack(track),
1174
+ );
1201
1175
  }
1202
1176
  }
1203
1177
  // set scalabilityMode to 'L3T3_KEY' by default
@@ -1318,13 +1292,12 @@ export default class LocalParticipant extends Participant {
1318
1292
  try {
1319
1293
  this.engine.pcManager.publisher.removeTrack(track.sender);
1320
1294
  } catch (e) {
1321
- this.log.error(e, this.logContext);
1295
+ this.log.error(e);
1322
1296
  }
1323
1297
  await this.engine.negotiate().catch((negotiateErr) => {
1324
1298
  this.log.error(
1325
1299
  'failed to negotiate after removing track due to failed add track request',
1326
1300
  {
1327
- ...this.logContext,
1328
1301
  ...getLogContextFromTrack(track),
1329
1302
  error: negotiateErr,
1330
1303
  },
@@ -1351,7 +1324,6 @@ export default class LocalParticipant extends Participant {
1351
1324
  const updatedCodec = mimeTypeToVideoCodecString(primaryCodecMime);
1352
1325
  if (updatedCodec !== videoCodec) {
1353
1326
  this.log.debug('falling back to server selected codec', {
1354
- ...this.logContext,
1355
1327
  ...getLogContextFromTrack(track),
1356
1328
  codec: updatedCodec,
1357
1329
  });
@@ -1391,11 +1363,7 @@ export default class LocalParticipant extends Participant {
1391
1363
  }
1392
1364
  }
1393
1365
 
1394
- this.log.debug(`publishing ${track.kind} with encodings`, {
1395
- ...this.logContext,
1396
- encodings,
1397
- trackInfo: ti,
1398
- });
1366
+ this.log.debug(`publishing ${track.kind} with encodings`, { encodings, trackInfo: ti });
1399
1367
 
1400
1368
  if (isLocalVideoTrack(track)) {
1401
1369
  track.startMonitor(this.engine.client);
@@ -1417,13 +1385,10 @@ export default class LocalParticipant extends Participant {
1417
1385
  this.on(ParticipantEvent.LocalTrackSubscribed, (pub) => {
1418
1386
  if (pub.trackSid === ti.sid) {
1419
1387
  if (!track.hasPreConnectBuffer) {
1420
- this.log.warn('subscribe event came to late, buffer already closed', this.logContext);
1388
+ this.log.warn('subscribe event came to late, buffer already closed');
1421
1389
  return;
1422
1390
  }
1423
- this.log.debug('finished recording preconnect buffer', {
1424
- ...this.logContext,
1425
- ...getLogContextFromTrack(track),
1426
- });
1391
+ this.log.debug('finished recording preconnect buffer', getLogContextFromTrack(track));
1427
1392
  track.stopPreConnectBuffer();
1428
1393
  }
1429
1394
  });
@@ -1431,19 +1396,13 @@ export default class LocalParticipant extends Participant {
1431
1396
  if (stream) {
1432
1397
  const bufferStreamPromise = new Promise<void>(async (resolve, reject) => {
1433
1398
  try {
1434
- this.log.debug('waiting for agent', {
1435
- ...this.logContext,
1436
- ...getLogContextFromTrack(track),
1437
- });
1399
+ this.log.debug('waiting for agent', getLogContextFromTrack(track));
1438
1400
  const agentActiveTimeout = setTimeout(() => {
1439
1401
  reject(new Error('agent not active within 10 seconds'));
1440
1402
  }, 10_000);
1441
1403
  const agent = await this.waitUntilActiveAgentPresent();
1442
1404
  clearTimeout(agentActiveTimeout);
1443
- this.log.debug('sending preconnect buffer', {
1444
- ...this.logContext,
1445
- ...getLogContextFromTrack(track),
1446
- });
1405
+ this.log.debug('sending preconnect buffer', getLogContextFromTrack(track));
1447
1406
  const writer = await this.streamBytes({
1448
1407
  name: 'preconnect-buffer',
1449
1408
  mimeType,
@@ -1466,14 +1425,10 @@ export default class LocalParticipant extends Participant {
1466
1425
  });
1467
1426
  bufferStreamPromise
1468
1427
  .then(() => {
1469
- this.log.debug('preconnect buffer sent successfully', {
1470
- ...this.logContext,
1471
- ...getLogContextFromTrack(track),
1472
- });
1428
+ this.log.debug('preconnect buffer sent successfully', getLogContextFromTrack(track));
1473
1429
  })
1474
1430
  .catch((e) => {
1475
1431
  this.log.error('error sending preconnect buffer', {
1476
- ...this.logContext,
1477
1432
  ...getLogContextFromTrack(track),
1478
1433
  error: e,
1479
1434
  });
@@ -1527,10 +1482,7 @@ export default class LocalParticipant extends Participant {
1527
1482
  if (!encodings) {
1528
1483
  this.log.info(
1529
1484
  `backup codec has been disabled, ignoring request to add additional codec for track`,
1530
- {
1531
- ...this.logContext,
1532
- ...getLogContextFromTrack(track),
1533
- },
1485
+ getLogContextFromTrack(track),
1534
1486
  );
1535
1487
  return;
1536
1488
  }
@@ -1571,7 +1523,6 @@ export default class LocalParticipant extends Participant {
1571
1523
  const ti = rets[0];
1572
1524
 
1573
1525
  this.log.debug(`published ${videoCodec} for track ${track.sid}`, {
1574
- ...this.logContext,
1575
1526
  encodings,
1576
1527
  trackInfo: ti,
1577
1528
  });
@@ -1584,10 +1535,10 @@ export default class LocalParticipant extends Participant {
1584
1535
  if (isLocalTrack(track)) {
1585
1536
  const publishPromise = this.pendingPublishPromises.get(track);
1586
1537
  if (publishPromise) {
1587
- this.log.info('awaiting publish promise before attempting to unpublish', {
1588
- ...this.logContext,
1589
- ...getLogContextFromTrack(track),
1590
- });
1538
+ this.log.debug(
1539
+ 'awaiting publish promise before attempting to unpublish',
1540
+ getLogContextFromTrack(track),
1541
+ );
1591
1542
  await publishPromise;
1592
1543
  }
1593
1544
  }
@@ -1596,16 +1547,10 @@ export default class LocalParticipant extends Participant {
1596
1547
 
1597
1548
  const pubLogContext = publication ? getLogContextFromTrack(publication) : undefined;
1598
1549
 
1599
- this.log.debug('unpublishing track', {
1600
- ...this.logContext,
1601
- ...pubLogContext,
1602
- });
1550
+ this.log.info('unpublishing track', pubLogContext);
1603
1551
 
1604
1552
  if (!publication || !publication.track) {
1605
- this.log.warn('track was not unpublished because no publication was found', {
1606
- ...this.logContext,
1607
- ...pubLogContext,
1608
- });
1553
+ this.log.warn('track was not unpublished because no publication was found', pubLogContext);
1609
1554
  return undefined;
1610
1555
  }
1611
1556
 
@@ -1648,7 +1593,7 @@ export default class LocalParticipant extends Participant {
1648
1593
  try {
1649
1594
  negotiationNeeded = this.engine.removeTrack(trackSender);
1650
1595
  } catch (e) {
1651
- this.log.warn(e, this.logContext);
1596
+ this.log.warn(e);
1652
1597
  negotiationNeeded = true;
1653
1598
  }
1654
1599
 
@@ -1658,7 +1603,7 @@ export default class LocalParticipant extends Participant {
1658
1603
  try {
1659
1604
  negotiationNeeded = this.engine.removeTrack(trackInfo.sender);
1660
1605
  } catch (e) {
1661
- this.log.warn(e, this.logContext);
1606
+ this.log.warn(e);
1662
1607
  negotiationNeeded = true;
1663
1608
  }
1664
1609
  trackInfo.sender = undefined;
@@ -1667,11 +1612,7 @@ export default class LocalParticipant extends Participant {
1667
1612
  track.simulcastCodecs.clear();
1668
1613
  }
1669
1614
  } catch (e) {
1670
- this.log.warn('failed to unpublish track', {
1671
- ...this.logContext,
1672
- ...pubLogContext,
1673
- error: e,
1674
- });
1615
+ this.log.warn('failed to unpublish track', { ...pubLogContext, error: e });
1675
1616
  }
1676
1617
  }
1677
1618
 
@@ -1734,10 +1675,7 @@ export default class LocalParticipant extends Participant {
1734
1675
  ) {
1735
1676
  // generally we need to restart the track before publishing, often a full reconnect
1736
1677
  // is necessary because computer had gone to sleep.
1737
- this.log.debug('restarting existing track', {
1738
- ...this.logContext,
1739
- track: pub.trackSid,
1740
- });
1678
+ this.log.debug('restarting existing track', { track: pub.trackSid });
1741
1679
  await track.restartTrack();
1742
1680
  }
1743
1681
  await this.publishOrRepublishTrack(track, pub.options, true);
@@ -2107,7 +2045,6 @@ export default class LocalParticipant extends Participant {
2107
2045
  const mutedOnServer = pub.isMuted || (pub.track?.isUpstreamPaused ?? false);
2108
2046
  if (mutedOnServer !== ti.muted) {
2109
2047
  this.log.debug('updating server mute state after reconcile', {
2110
- ...this.logContext,
2111
2048
  ...getLogContextFromTrack(pub),
2112
2049
  mutedOnServer,
2113
2050
  });
@@ -2120,7 +2057,6 @@ export default class LocalParticipant extends Participant {
2120
2057
 
2121
2058
  private updateTrackSubscriptionPermissions = () => {
2122
2059
  this.log.debug('updating track subscription permissions', {
2123
- ...this.logContext,
2124
2060
  allParticipantsAllowed: this.allParticipantsAllowedToSubscribe,
2125
2061
  participantTrackPermissions: this.participantTrackPermissions,
2126
2062
  });
@@ -2167,10 +2103,10 @@ export default class LocalParticipant extends Participant {
2167
2103
  }
2168
2104
 
2169
2105
  if (!track.sid) {
2170
- this.log.error('could not update mute status for unpublished track', {
2171
- ...this.logContext,
2172
- ...getLogContextFromTrack(track),
2173
- });
2106
+ this.log.error(
2107
+ 'could not update mute status for unpublished track',
2108
+ getLogContextFromTrack(track),
2109
+ );
2174
2110
  return;
2175
2111
  }
2176
2112
 
@@ -2178,18 +2114,12 @@ export default class LocalParticipant extends Participant {
2178
2114
  };
2179
2115
 
2180
2116
  private onTrackUpstreamPaused = (track: LocalTrack) => {
2181
- this.log.debug('upstream paused', {
2182
- ...this.logContext,
2183
- ...getLogContextFromTrack(track),
2184
- });
2117
+ this.log.debug('upstream paused', getLogContextFromTrack(track));
2185
2118
  this.onTrackMuted(track, true);
2186
2119
  };
2187
2120
 
2188
2121
  private onTrackUpstreamResumed = (track: LocalTrack) => {
2189
- this.log.debug('upstream resumed', {
2190
- ...this.logContext,
2191
- ...getLogContextFromTrack(track),
2192
- });
2122
+ this.log.debug('upstream resumed', getLogContextFromTrack(track));
2193
2123
  this.onTrackMuted(track, track.isMuted);
2194
2124
  };
2195
2125
 
@@ -2198,7 +2128,6 @@ export default class LocalParticipant extends Participant {
2198
2128
  if (!pub) {
2199
2129
  this.log.warn(
2200
2130
  `Could not update local audio track settings, missing publication for track ${track.sid}`,
2201
- this.logContext,
2202
2131
  );
2203
2132
  return;
2204
2133
  }
@@ -2206,10 +2135,7 @@ export default class LocalParticipant extends Participant {
2206
2135
  };
2207
2136
 
2208
2137
  private onTrackCpuConstrained = (track: LocalVideoTrack, publication: LocalTrackPublication) => {
2209
- this.log.debug('track cpu constrained', {
2210
- ...this.logContext,
2211
- ...getLogContextFromTrack(publication),
2212
- });
2138
+ this.log.debug('track cpu constrained', getLogContextFromTrack(publication));
2213
2139
  this.emit(ParticipantEvent.LocalTrackCpuConstrained, track, publication);
2214
2140
  };
2215
2141
 
@@ -2220,7 +2146,6 @@ export default class LocalParticipant extends Participant {
2220
2146
  const pub = this.videoTrackPublications.get(update.trackSid);
2221
2147
  if (!pub) {
2222
2148
  this.log.warn('received subscribed quality update for unknown track', {
2223
- ...this.logContext,
2224
2149
  trackSid: update.trackSid,
2225
2150
  });
2226
2151
  return;
@@ -2231,10 +2156,7 @@ export default class LocalParticipant extends Participant {
2231
2156
  const newCodecs = await pub.videoTrack.setPublishingCodecs(update.subscribedCodecs);
2232
2157
  for await (const codec of newCodecs) {
2233
2158
  if (isBackupCodec(codec)) {
2234
- this.log.debug(`publish ${codec} for ${pub.videoTrack.sid}`, {
2235
- ...this.logContext,
2236
- ...getLogContextFromTrack(pub),
2237
- });
2159
+ this.log.debug(`publish ${codec} for ${pub.videoTrack.sid}`, getLogContextFromTrack(pub));
2238
2160
  await this.publishAdditionalCodecForTrack(pub.videoTrack, codec, pub.options);
2239
2161
  }
2240
2162
  }
@@ -2244,7 +2166,6 @@ export default class LocalParticipant extends Participant {
2244
2166
  const track = this.trackPublications.get(unpublished.trackSid);
2245
2167
  if (!track) {
2246
2168
  this.log.warn('received unpublished event for unknown track', {
2247
- ...this.logContext,
2248
2169
  trackSid: unpublished.trackSid,
2249
2170
  });
2250
2171
  return;
@@ -2257,10 +2178,7 @@ export default class LocalParticipant extends Participant {
2257
2178
  track.source === Track.Source.ScreenShare ||
2258
2179
  track.source === Track.Source.ScreenShareAudio
2259
2180
  ) {
2260
- this.log.debug('unpublishing local track due to TrackEnded', {
2261
- ...this.logContext,
2262
- ...getLogContextFromTrack(track),
2263
- });
2181
+ this.log.debug('unpublishing local track due to TrackEnded', getLogContextFromTrack(track));
2264
2182
  this.unpublishTrack(track);
2265
2183
  } else if (track.isUserProvided) {
2266
2184
  await track.mute();
@@ -2274,10 +2192,10 @@ export default class LocalParticipant extends Participant {
2274
2192
  name: track.source === Track.Source.Camera ? 'camera' : 'microphone',
2275
2193
  });
2276
2194
  if (currentPermissions && currentPermissions.state === 'denied') {
2277
- this.log.warn(`user has revoked access to ${track.source}`, {
2278
- ...this.logContext,
2279
- ...getLogContextFromTrack(track),
2280
- });
2195
+ this.log.warn(
2196
+ `user has revoked access to ${track.source}`,
2197
+ getLogContextFromTrack(track),
2198
+ );
2281
2199
 
2282
2200
  // detect granted change after permissions were denied to try and resume then
2283
2201
  currentPermissions.onchange = () => {
@@ -2295,10 +2213,10 @@ export default class LocalParticipant extends Participant {
2295
2213
  }
2296
2214
  }
2297
2215
  if (!track.isMuted) {
2298
- this.log.debug('track ended, attempting to use a different device', {
2299
- ...this.logContext,
2300
- ...getLogContextFromTrack(track),
2301
- });
2216
+ this.log.debug(
2217
+ 'track ended, attempting to use a different device',
2218
+ getLogContextFromTrack(track),
2219
+ );
2302
2220
  if (isLocalAudioTrack(track)) {
2303
2221
  // fall back to default device if available
2304
2222
  await track.restartTrack({ deviceId: 'default' });
@@ -2307,10 +2225,7 @@ export default class LocalParticipant extends Participant {
2307
2225
  }
2308
2226
  }
2309
2227
  } catch (e) {
2310
- this.log.warn(`could not restart track, muting instead`, {
2311
- ...this.logContext,
2312
- ...getLogContextFromTrack(track),
2313
- });
2228
+ this.log.warn(`could not restart track, muting instead`, getLogContextFromTrack(track));
2314
2229
  await track.mute();
2315
2230
  }
2316
2231
  }
@@ -140,8 +140,11 @@ export default class Participant extends (EventEmitter as new () => TypedEmitter
140
140
  ) {
141
141
  super();
142
142
 
143
- this.log = getLogger(loggerOptions?.loggerName ?? LoggerNames.Participant);
144
143
  this.loggerOptions = loggerOptions;
144
+ this.log = getLogger(
145
+ loggerOptions?.loggerName ?? LoggerNames.Participant,
146
+ () => this.logContext,
147
+ );
145
148
 
146
149
  this.setMaxListeners(100);
147
150
  this.sid = sid;
@@ -15,7 +15,6 @@ import type { LoggerOptions } from '../types';
15
15
  import {
16
16
  compareVersions,
17
17
  getReactNativeOs,
18
- isFireFox,
19
18
  isReactNative,
20
19
  isSVCCodec,
21
20
  isSafariBased,
@@ -379,7 +378,8 @@ function encodingsFromPresets(
379
378
  if (maxFramerate) {
380
379
  encoding.maxFramerate = maxFramerate;
381
380
  }
382
- const canSetPriority = isFireFox() || idx === 0;
381
+ const browser = getBrowser();
382
+ const canSetPriority = (browser?.name === 'Firefox' && browser.os !== 'iOS') || idx === 0;
383
383
  if (preset.encoding.priority && canSetPriority) {
384
384
  encoding.priority = preset.encoding.priority;
385
385
  encoding.networkPriority = preset.encoding.priority;
@@ -185,6 +185,7 @@ export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {
185
185
  track: this._mediaStreamTrack,
186
186
  // RN won't have or use AudioContext
187
187
  audioContext: this.audioContext as AudioContext,
188
+ localTrack: this,
188
189
  };
189
190
  this.log.debug(`setting up audio processor ${processor.name}`, this.logContext);
190
191
 
@@ -194,6 +194,7 @@ export default abstract class LocalTrack<
194
194
  track: newTrack,
195
195
  kind: this.kind,
196
196
  element: this.processorElement,
197
+ localTrack: this,
197
198
  });
198
199
  processedTrack = this.processor.processedTrack;
199
200
  }
@@ -555,6 +556,7 @@ export default abstract class LocalTrack<
555
556
  track: this._mediaStreamTrack,
556
557
  element: processorElement,
557
558
  audioContext: this.audioContext,
559
+ localTrack: this,
558
560
  };
559
561
  await processor.init(processorOptions);
560
562
  this.log.debug('processor initialized', this.logContext);
@@ -1,4 +1,5 @@
1
1
  import type Room from '../../Room';
2
+ import type LocalTrack from '../LocalTrack';
2
3
  import type { Track } from '../Track';
3
4
 
4
5
  /**
@@ -9,6 +10,7 @@ export type ProcessorOptions<T extends Track.Kind> = {
9
10
  track: MediaStreamTrack;
10
11
  element?: HTMLMediaElement;
11
12
  audioContext?: AudioContext;
13
+ localTrack?: LocalTrack;
12
14
  };
13
15
 
14
16
  export interface AudioProcessorOptions extends ProcessorOptions<Track.Kind.Audio> {
@@ -8,10 +8,13 @@ export function subscribeToEvents<
8
8
  Callbacks extends EventMap,
9
9
  EventNames extends keyof Callbacks = keyof Callbacks,
10
10
  >(eventEmitter: TypedEventEmitter<Callbacks>, eventNames: Array<EventNames>) {
11
- const nextEventListeners = new Map<EventNames, Array<Future<unknown, never>>>(
11
+ // Wrap buffered events in a `{ event }` envelope so that no-payload events (like
12
+ // `reset: () => void`) survive the `if (earliestBufferedEvent)` check in waitFor --
13
+ // an `undefined` payload would otherwise look the same as an empty buffer.
14
+ const nextEventListeners = new Map<EventNames, Array<Future<{ event: unknown }, never>>>(
12
15
  eventNames.map((eventName) => [eventName, []]),
13
16
  );
14
- const buffers = new Map<EventNames, Array<unknown>>(
17
+ const buffers = new Map<EventNames, Array<{ event: unknown }>>(
15
18
  eventNames.map((eventName) => [eventName, []]),
16
19
  );
17
20
 
@@ -20,11 +23,11 @@ export function subscribeToEvents<
20
23
  const listeners = nextEventListeners.get(eventName)!;
21
24
  if (listeners.length > 0) {
22
25
  for (const listener of listeners) {
23
- listener.resolve?.(event);
26
+ listener.resolve?.({ event });
24
27
  }
25
28
  nextEventListeners.set(eventName, []);
26
29
  } else {
27
- buffers.get(eventName)!.push(event);
30
+ buffers.get(eventName)!.push({ event });
28
31
  }
29
32
  }) as Callbacks[keyof Callbacks];
30
33
  return [eventName, onEvent] as [keyof Callbacks, Callbacks[keyof Callbacks]];
@@ -48,14 +51,14 @@ export function subscribeToEvents<
48
51
  }
49
52
  const earliestBufferedEvent = buffer.shift();
50
53
  if (earliestBufferedEvent) {
51
- return earliestBufferedEvent as EventPayload;
54
+ return earliestBufferedEvent.event as EventPayload;
52
55
  }
53
56
 
54
57
  // Otherwise wait for the next event to come in.
55
- const future = new Future<unknown, never>();
58
+ const future = new Future<{ event: unknown }, never>();
56
59
  nextEventListeners.get(eventName)!.push(future);
57
- const nextEvent = await future.promise;
58
- return nextEvent as EventPayload;
60
+ const { event } = await future.promise;
61
+ return event as EventPayload;
59
62
  },
60
63
  /** Are there events of the given name which are waiting to be processed? Use this to assert
61
64
  * that no unexpected events have been emitted. */