livekit-client 2.22.0 → 2.22.1

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 (75) 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 +187 -1
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +1764 -121
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.fm.worker.js +1 -1
  8. package/dist/livekit-client.fm.worker.js.map +1 -1
  9. package/dist/livekit-client.fm.worker.mjs +187 -1
  10. package/dist/livekit-client.fm.worker.mjs.map +1 -1
  11. package/dist/livekit-client.umd.js +1 -1
  12. package/dist/livekit-client.umd.js.map +1 -1
  13. package/dist/src/api/SignalClient.d.ts +25 -1
  14. package/dist/src/api/SignalClient.d.ts.map +1 -1
  15. package/dist/src/api/SignalClientStateMachine.d.ts +85 -0
  16. package/dist/src/api/SignalClientStateMachine.d.ts.map +1 -0
  17. package/dist/src/api/WebSocketStream.d.ts.map +1 -1
  18. package/dist/src/api/utils.d.ts.map +1 -1
  19. package/dist/src/index.d.ts +3 -2
  20. package/dist/src/index.d.ts.map +1 -1
  21. package/dist/src/logger.d.ts +2 -1
  22. package/dist/src/logger.d.ts.map +1 -1
  23. package/dist/src/options.d.ts +22 -0
  24. package/dist/src/options.d.ts.map +1 -1
  25. package/dist/src/room/PCTransport.d.ts +2 -1
  26. package/dist/src/room/PCTransport.d.ts.map +1 -1
  27. package/dist/src/room/RTCEngine.d.ts +7 -2
  28. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  29. package/dist/src/room/Room.d.ts +8 -1
  30. package/dist/src/room/Room.d.ts.map +1 -1
  31. package/dist/src/room/events.d.ts +1 -1
  32. package/dist/src/room/statsSummary.d.ts +13 -0
  33. package/dist/src/room/statsSummary.d.ts.map +1 -0
  34. package/dist/src/room/token-source/utils.d.ts.map +1 -1
  35. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  36. package/dist/src/room/track/Track.d.ts +10 -0
  37. package/dist/src/room/track/Track.d.ts.map +1 -1
  38. package/dist/src/utils/machineInspector.d.ts +54 -0
  39. package/dist/src/utils/machineInspector.d.ts.map +1 -0
  40. package/dist/ts4.2/api/SignalClient.d.ts +25 -1
  41. package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -0
  42. package/dist/ts4.2/index.d.ts +3 -2
  43. package/dist/ts4.2/logger.d.ts +2 -1
  44. package/dist/ts4.2/options.d.ts +22 -0
  45. package/dist/ts4.2/room/PCTransport.d.ts +2 -1
  46. package/dist/ts4.2/room/RTCEngine.d.ts +7 -2
  47. package/dist/ts4.2/room/Room.d.ts +8 -1
  48. package/dist/ts4.2/room/events.d.ts +1 -1
  49. package/dist/ts4.2/room/statsSummary.d.ts +13 -0
  50. package/dist/ts4.2/room/track/Track.d.ts +10 -0
  51. package/dist/ts4.2/utils/machineInspector.d.ts +54 -0
  52. package/package.json +7 -1
  53. package/src/api/SignalClient.test.ts +320 -8
  54. package/src/api/SignalClient.ts +260 -82
  55. package/src/api/SignalClientStateMachine.test.ts +472 -0
  56. package/src/api/SignalClientStateMachine.ts +180 -0
  57. package/src/api/WebSocketStream.ts +19 -3
  58. package/src/api/utils.test.ts +20 -1
  59. package/src/api/utils.ts +5 -0
  60. package/src/index.ts +5 -0
  61. package/src/logger.ts +1 -0
  62. package/src/options.ts +24 -0
  63. package/src/room/PCTransport.ts +2 -1
  64. package/src/room/RTCEngine.ts +16 -7
  65. package/src/room/Room.ts +70 -5
  66. package/src/room/events.ts +1 -1
  67. package/src/room/statsSummary.ts +187 -0
  68. package/src/room/token-source/test-tokens.ts +20 -0
  69. package/src/room/token-source/utils.test.ts +27 -0
  70. package/src/room/token-source/utils.ts +12 -5
  71. package/src/room/track/LocalAudioTrack.ts +9 -3
  72. package/src/room/track/Track.ts +27 -0
  73. package/src/room/utils.test.ts +24 -1
  74. package/src/room/utils.ts +1 -1
  75. package/src/utils/machineInspector.ts +90 -0
@@ -381,6 +381,7 @@ var LoggerNames;
381
381
  LoggerNames["DataTracks"] = "livekit-data-tracks";
382
382
  LoggerNames["Region"] = "livekit-region";
383
383
  LoggerNames["ICE"] = "livekit-ice";
384
+ LoggerNames["Stats"] = "livekit-stats";
384
385
  })(LoggerNames || (LoggerNames = {}));
385
386
  let livekitLogger = loglevelExports.getLogger(LoggerNames.Default);
386
387
  Object.values(LoggerNames).map(name => loglevelExports.getLogger(name));
@@ -4866,7 +4867,7 @@ var RoomEvent;
4866
4867
  * When a [[RemoteParticipant]] leaves *after* the local
4867
4868
  * participant has joined.
4868
4869
  *
4869
- * args: ([[RemoteParticipant]])
4870
+ * args: ([[RemoteParticipant]], [[DisconnectReason]] | undefined)
4870
4871
  */
4871
4872
  RoomEvent["ParticipantDisconnected"] = "participantDisconnected";
4872
4873
  /**
@@ -5436,6 +5437,172 @@ var TrackEvent;
5436
5437
  TrackEvent["PreConnectBufferFlushed"] = "preConnectBufferFlushed";
5437
5438
  })(TrackEvent || (TrackEvent = {}));
5438
5439
 
5440
+ function compact(summary) {
5441
+ const compacted = {};
5442
+ for (const _ref of Object.entries(summary)) {
5443
+ var _ref2 = _slicedToArray(_ref, 2);
5444
+ const key = _ref2[0];
5445
+ const value = _ref2[1];
5446
+ if (value !== undefined) {
5447
+ compacted[key] = value;
5448
+ }
5449
+ }
5450
+ return compacted;
5451
+ }
5452
+ function resolution(width, height) {
5453
+ return width && height ? "".concat(width, "x").concat(height) : undefined;
5454
+ }
5455
+ /** keeps the derived durations readable; reported values are logged as they are */
5456
+ function round(seconds) {
5457
+ return Math.round(seconds * 10000) / 10000;
5458
+ }
5459
+ /**
5460
+ * Average time media spent in the jitter buffer, in s. Both counters are
5461
+ * cumulative, so this is the average over the lifetime of the stream.
5462
+ */
5463
+ function jitterBuffer(stat) {
5464
+ const delay = stat.jitterBufferDelay;
5465
+ const emitted = stat.jitterBufferEmittedCount;
5466
+ return delay !== undefined && emitted ? round(delay / emitted) : undefined;
5467
+ }
5468
+ /**
5469
+ * Playout delay in s. Video receive reports it directly, the audio path keeps it
5470
+ * in the linked `media-playout` stats summed over the samples played out. Pairs
5471
+ * with `RemoteTrack.setPlayoutDelay`.
5472
+ */
5473
+ function playoutDelay(stat, playout) {
5474
+ if (stat.playoutDelay !== undefined) {
5475
+ return round(stat.playoutDelay);
5476
+ }
5477
+ const total = playout === null || playout === void 0 ? void 0 : playout.totalPlayoutDelay;
5478
+ const samples = playout === null || playout === void 0 ? void 0 : playout.totalSamplesCount;
5479
+ return total !== undefined && samples ? round(total / samples) : undefined;
5480
+ }
5481
+ /**
5482
+ * Picks the interesting fields out of a `getStats()` report and groups them by
5483
+ * RTP stream, so a stats dump can be read without unfolding the raw report.
5484
+ */
5485
+ function summarizeStatsReport(report) {
5486
+ var _a, _b;
5487
+ const byId = new Map();
5488
+ const candidatePairs = [];
5489
+ const inbound = [];
5490
+ const outbound = [];
5491
+ let transport;
5492
+ report.forEach(stat => byId.set(stat.id, stat));
5493
+ const codecOf = stat => {
5494
+ var _a;
5495
+ return stat.codecId ? (_a = byId.get(stat.codecId)) === null || _a === void 0 ? void 0 : _a.mimeType : undefined;
5496
+ };
5497
+ const relatedOf = (stat, key) => stat[key] ? byId.get(stat[key]) : undefined;
5498
+ report.forEach(stat => {
5499
+ switch (stat.type) {
5500
+ case 'inbound-rtp':
5501
+ {
5502
+ const playout = relatedOf(stat, 'playoutId');
5503
+ inbound.push(compact({
5504
+ kind: stat.kind,
5505
+ ssrc: stat.ssrc,
5506
+ mid: stat.mid,
5507
+ // matches `streamTrackID` in the track's own log context
5508
+ trackId: stat.trackIdentifier,
5509
+ codec: codecOf(stat),
5510
+ decoder: stat.decoderImplementation,
5511
+ resolution: resolution(stat.frameWidth, stat.frameHeight),
5512
+ fps: stat.framesPerSecond,
5513
+ bytesReceived: stat.bytesReceived,
5514
+ packetsReceived: stat.packetsReceived,
5515
+ packetsLost: stat.packetsLost,
5516
+ packetsDiscarded: stat.packetsDiscarded,
5517
+ // frames received without frames decoded is a decode failure
5518
+ framesReceived: stat.framesReceived,
5519
+ framesDecoded: stat.framesDecoded,
5520
+ framesDropped: stat.framesDropped,
5521
+ keyFramesDecoded: stat.keyFramesDecoded,
5522
+ freezeCount: stat.freezeCount,
5523
+ totalFreezesDuration: stat.totalFreezesDuration,
5524
+ pauseCount: stat.pauseCount,
5525
+ nackCount: stat.nackCount,
5526
+ pliCount: stat.pliCount,
5527
+ firCount: stat.firCount,
5528
+ jitter: stat.jitter,
5529
+ jitterBuffer: jitterBuffer(stat),
5530
+ playoutDelay: playoutDelay(stat, playout),
5531
+ audioLevel: stat.audioLevel,
5532
+ totalSamplesReceived: stat.totalSamplesReceived,
5533
+ concealedSamples: stat.concealedSamples
5534
+ }));
5535
+ break;
5536
+ }
5537
+ case 'outbound-rtp':
5538
+ {
5539
+ const remote = relatedOf(stat, 'remoteId');
5540
+ const source = relatedOf(stat, 'mediaSourceId');
5541
+ outbound.push(compact({
5542
+ kind: stat.kind,
5543
+ ssrc: stat.ssrc,
5544
+ mid: stat.mid,
5545
+ rid: stat.rid,
5546
+ trackId: source === null || source === void 0 ? void 0 : source.trackIdentifier,
5547
+ active: stat.active,
5548
+ codec: codecOf(stat),
5549
+ encoder: stat.encoderImplementation,
5550
+ resolution: resolution(stat.frameWidth, stat.frameHeight),
5551
+ fps: stat.framesPerSecond,
5552
+ // what the source produces, to tell a stalled capture from a stalled encoder
5553
+ captureResolution: resolution(source === null || source === void 0 ? void 0 : source.width, source === null || source === void 0 ? void 0 : source.height),
5554
+ captureFps: source === null || source === void 0 ? void 0 : source.framesPerSecond,
5555
+ audioLevel: source === null || source === void 0 ? void 0 : source.audioLevel,
5556
+ targetBitrate: stat.targetBitrate,
5557
+ bytesSent: stat.bytesSent,
5558
+ packetsSent: stat.packetsSent,
5559
+ retransmittedPacketsSent: stat.retransmittedPacketsSent,
5560
+ framesEncoded: stat.framesEncoded,
5561
+ keyFramesEncoded: stat.keyFramesEncoded,
5562
+ limitedBy: stat.qualityLimitationReason === 'none' ? undefined : stat.qualityLimitationReason,
5563
+ nackCount: stat.nackCount,
5564
+ pliCount: stat.pliCount,
5565
+ firCount: stat.firCount,
5566
+ // loss, jitter and RTT are only known from what the remote reports
5567
+ remotePacketsLost: remote === null || remote === void 0 ? void 0 : remote.packetsLost,
5568
+ remoteFractionLost: remote === null || remote === void 0 ? void 0 : remote.fractionLost,
5569
+ remoteJitter: remote === null || remote === void 0 ? void 0 : remote.jitter,
5570
+ remoteRoundTripTime: remote === null || remote === void 0 ? void 0 : remote.roundTripTime
5571
+ }));
5572
+ break;
5573
+ }
5574
+ case 'transport':
5575
+ transport = stat;
5576
+ break;
5577
+ case 'candidate-pair':
5578
+ candidatePairs.push(stat);
5579
+ break;
5580
+ }
5581
+ });
5582
+ const selectedPairId = transport === null || transport === void 0 ? void 0 : transport.selectedCandidatePairId;
5583
+ const pair = (_b = (_a = selectedPairId ? byId.get(selectedPairId) : undefined) !== null && _a !== void 0 ? _a : candidatePairs.find(candidate => candidate.selected)) !== null && _b !== void 0 ? _b : candidatePairs.find(candidate => candidate.nominated);
5584
+ const local = (pair === null || pair === void 0 ? void 0 : pair.localCandidateId) ? byId.get(pair.localCandidateId) : undefined;
5585
+ const remote = (pair === null || pair === void 0 ? void 0 : pair.remoteCandidateId) ? byId.get(pair.remoteCandidateId) : undefined;
5586
+ const connection = compact({
5587
+ ice: transport === null || transport === void 0 ? void 0 : transport.iceState,
5588
+ dtls: transport === null || transport === void 0 ? void 0 : transport.dtlsState,
5589
+ route: local && remote ? "".concat(local.candidateType, "/").concat(local.protocol, " -> ").concat(remote.candidateType) : undefined,
5590
+ network: local === null || local === void 0 ? void 0 : local.networkType,
5591
+ currentRoundTripTime: pair === null || pair === void 0 ? void 0 : pair.currentRoundTripTime,
5592
+ // the send bandwidth estimate; no RTP stream reports it
5593
+ availableOutgoingBitrate: pair === null || pair === void 0 ? void 0 : pair.availableOutgoingBitrate,
5594
+ availableIncomingBitrate: pair === null || pair === void 0 ? void 0 : pair.availableIncomingBitrate,
5595
+ bytesSent: pair === null || pair === void 0 ? void 0 : pair.bytesSent,
5596
+ bytesReceived: pair === null || pair === void 0 ? void 0 : pair.bytesReceived,
5597
+ candidatePairChanges: transport === null || transport === void 0 ? void 0 : transport.selectedCandidatePairChanges
5598
+ });
5599
+ return {
5600
+ connection: Object.keys(connection).length > 0 ? connection : undefined,
5601
+ outbound: outbound.length > 0 ? outbound : undefined,
5602
+ inbound: inbound.length > 0 ? inbound : undefined
5603
+ };
5604
+ }
5605
+
5439
5606
  class VideoPreset {
5440
5607
  constructor(widthOrOptions, height, maxBitrate, maxFramerate, priority) {
5441
5608
  if (typeof widthOrOptions === 'object') {
@@ -5604,6 +5771,7 @@ class Track extends eventsExports.EventEmitter {
5604
5771
  this._streamState = Track.StreamState.Active;
5605
5772
  this.isInBackground = false;
5606
5773
  this._currentBitrate = 0;
5774
+ this.finalStatsLogged = false;
5607
5775
  this.log = livekitLogger;
5608
5776
  this.appVisibilityChangedListener = () => {
5609
5777
  if (this.backgroundTimeout) {
@@ -5752,6 +5920,24 @@ class Track extends eventsExports.EventEmitter {
5752
5920
  cancelAnimationFrame(this.timeSyncHandle);
5753
5921
  this.timeSyncHandle = undefined;
5754
5922
  }
5923
+ this.logFinalStats();
5924
+ }
5925
+ /**
5926
+ * Dumps the raw stats of the track as it ends, once: a track that stops
5927
+ * between two of the room's stats dumps is gone by the time the next one runs.
5928
+ */
5929
+ logFinalStats() {
5930
+ if (this.finalStatsLogged) {
5931
+ return;
5932
+ }
5933
+ this.finalStatsLogged = true;
5934
+ this.getRTCStatsReport().then(report => {
5935
+ if (report) {
5936
+ this.log.info('final track stats', summarizeStatsReport(report));
5937
+ }
5938
+ }).catch(error => this.log.debug('could not collect final track stats', {
5939
+ error
5940
+ }));
5755
5941
  }
5756
5942
  /** @internal */
5757
5943
  updateLoggerOptions(loggerOptions) {