livekit-client 2.21.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 (116) hide show
  1. package/README.md +10 -10
  2. package/dist/livekit-client.e2ee.worker.js +1 -1
  3. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  4. package/dist/livekit-client.e2ee.worker.mjs +189 -2
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +2243 -270
  7. package/dist/livekit-client.esm.mjs.map +1 -1
  8. package/dist/livekit-client.fm.worker.js +1 -1
  9. package/dist/livekit-client.fm.worker.js.map +1 -1
  10. package/dist/livekit-client.fm.worker.mjs +189 -2
  11. package/dist/livekit-client.fm.worker.mjs.map +1 -1
  12. package/dist/livekit-client.umd.js +1 -1
  13. package/dist/livekit-client.umd.js.map +1 -1
  14. package/dist/src/api/SignalClient.d.ts +25 -1
  15. package/dist/src/api/SignalClient.d.ts.map +1 -1
  16. package/dist/src/api/SignalClientStateMachine.d.ts +85 -0
  17. package/dist/src/api/SignalClientStateMachine.d.ts.map +1 -0
  18. package/dist/src/api/WebSocketStream.d.ts.map +1 -1
  19. package/dist/src/api/utils.d.ts.map +1 -1
  20. package/dist/src/index.d.ts +3 -2
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/logger.d.ts +2 -1
  23. package/dist/src/logger.d.ts.map +1 -1
  24. package/dist/src/options.d.ts +22 -0
  25. package/dist/src/options.d.ts.map +1 -1
  26. package/dist/src/room/PCTransport.d.ts +51 -3
  27. package/dist/src/room/PCTransport.d.ts.map +1 -1
  28. package/dist/src/room/RTCEngine.d.ts +27 -3
  29. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  30. package/dist/src/room/Room.d.ts +10 -1
  31. package/dist/src/room/Room.d.ts.map +1 -1
  32. package/dist/src/room/errors.d.ts.map +1 -1
  33. package/dist/src/room/events.d.ts +1 -1
  34. package/dist/src/room/participant/LocalParticipant.d.ts +1 -1
  35. package/dist/src/room/statsSummary.d.ts +13 -0
  36. package/dist/src/room/statsSummary.d.ts.map +1 -0
  37. package/dist/src/room/token-source/TokenSource.d.ts +19 -10
  38. package/dist/src/room/token-source/TokenSource.d.ts.map +1 -1
  39. package/dist/src/room/token-source/utils.d.ts.map +1 -1
  40. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  41. package/dist/src/room/track/LocalVideoTrack.d.ts +12 -1
  42. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  43. package/dist/src/room/track/RemoteTrack.d.ts +3 -0
  44. package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
  45. package/dist/src/room/track/Track.d.ts +10 -0
  46. package/dist/src/room/track/Track.d.ts.map +1 -1
  47. package/dist/src/room/utils.d.ts +15 -0
  48. package/dist/src/room/utils.d.ts.map +1 -1
  49. package/dist/src/test/promiseState.d.ts +12 -0
  50. package/dist/src/test/promiseState.d.ts.map +1 -0
  51. package/dist/src/test/signalToken.d.ts.map +1 -1
  52. package/dist/src/utils/AsyncQueue.d.ts +3 -3
  53. package/dist/src/utils/AsyncQueue.d.ts.map +1 -1
  54. package/dist/src/utils/machineInspector.d.ts +54 -0
  55. package/dist/src/utils/machineInspector.d.ts.map +1 -0
  56. package/dist/ts4.2/api/SignalClient.d.ts +25 -1
  57. package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -0
  58. package/dist/ts4.2/index.d.ts +3 -2
  59. package/dist/ts4.2/logger.d.ts +2 -1
  60. package/dist/ts4.2/options.d.ts +22 -0
  61. package/dist/ts4.2/room/PCTransport.d.ts +51 -3
  62. package/dist/ts4.2/room/RTCEngine.d.ts +27 -3
  63. package/dist/ts4.2/room/Room.d.ts +10 -1
  64. package/dist/ts4.2/room/events.d.ts +1 -1
  65. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +1 -1
  66. package/dist/ts4.2/room/statsSummary.d.ts +13 -0
  67. package/dist/ts4.2/room/token-source/TokenSource.d.ts +17 -8
  68. package/dist/ts4.2/room/track/LocalVideoTrack.d.ts +12 -1
  69. package/dist/ts4.2/room/track/RemoteTrack.d.ts +3 -0
  70. package/dist/ts4.2/room/track/Track.d.ts +10 -0
  71. package/dist/ts4.2/room/utils.d.ts +15 -0
  72. package/dist/ts4.2/test/promiseState.d.ts +12 -0
  73. package/dist/ts4.2/utils/AsyncQueue.d.ts +3 -3
  74. package/dist/ts4.2/utils/machineInspector.d.ts +54 -0
  75. package/package.json +19 -12
  76. package/src/api/SignalClient.e2e.test.ts +16 -9
  77. package/src/api/SignalClient.test.ts +320 -8
  78. package/src/api/SignalClient.ts +260 -82
  79. package/src/api/SignalClientStateMachine.test.ts +472 -0
  80. package/src/api/SignalClientStateMachine.ts +180 -0
  81. package/src/api/WebSocketStream.ts +19 -3
  82. package/src/api/utils.test.ts +20 -1
  83. package/src/api/utils.ts +5 -0
  84. package/src/e2ee/utils.ts +1 -1
  85. package/src/index.ts +5 -0
  86. package/src/logger.ts +1 -0
  87. package/src/options.ts +24 -0
  88. package/src/room/PCTransport.test.ts +243 -1
  89. package/src/room/PCTransport.ts +183 -81
  90. package/src/room/RTCEngine.test.ts +339 -2
  91. package/src/room/RTCEngine.ts +168 -18
  92. package/src/room/Room.test.ts +134 -3
  93. package/src/room/Room.ts +122 -22
  94. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +1 -1
  95. package/src/room/data-stream/incoming/StreamReader.ts +1 -1
  96. package/src/room/errors.ts +1 -2
  97. package/src/room/events.ts +1 -1
  98. package/src/room/statsSummary.ts +187 -0
  99. package/src/room/token-source/TokenSource.ts +25 -12
  100. package/src/room/token-source/test-tokens.ts +20 -0
  101. package/src/room/token-source/utils.test.ts +27 -0
  102. package/src/room/token-source/utils.ts +12 -5
  103. package/src/room/track/LocalAudioTrack.ts +9 -3
  104. package/src/room/track/LocalVideoTrack.test.ts +105 -2
  105. package/src/room/track/LocalVideoTrack.ts +36 -10
  106. package/src/room/track/RemoteTrack.test.ts +144 -0
  107. package/src/room/track/RemoteTrack.ts +39 -12
  108. package/src/room/track/Track.ts +29 -1
  109. package/src/room/utils.test.ts +94 -2
  110. package/src/room/utils.ts +53 -1
  111. package/src/test/promiseState.ts +23 -0
  112. package/src/test/signalServerSetup.ts +2 -1
  113. package/src/test/signalToken.ts +17 -13
  114. package/src/type-polyfills/header-extensions.d.ts +13 -0
  115. package/src/utils/AsyncQueue.ts +3 -3
  116. package/src/utils/machineInspector.ts +90 -0
@@ -4383,6 +4383,7 @@ var LoggerNames;
4383
4383
  LoggerNames["DataTracks"] = "livekit-data-tracks";
4384
4384
  LoggerNames["Region"] = "livekit-region";
4385
4385
  LoggerNames["ICE"] = "livekit-ice";
4386
+ LoggerNames["Stats"] = "livekit-stats";
4386
4387
  })(LoggerNames || (LoggerNames = {}));
4387
4388
  let livekitLogger = loglevelExports.getLogger(LoggerNames.Default);
4388
4389
  Object.values(LoggerNames).map(name => loglevelExports.getLogger(name));
@@ -4499,7 +4500,7 @@ var RoomEvent;
4499
4500
  * When a [[RemoteParticipant]] leaves *after* the local
4500
4501
  * participant has joined.
4501
4502
  *
4502
- * args: ([[RemoteParticipant]])
4503
+ * args: ([[RemoteParticipant]], [[DisconnectReason]] | undefined)
4503
4504
  */
4504
4505
  RoomEvent["ParticipantDisconnected"] = "participantDisconnected";
4505
4506
  /**
@@ -5069,6 +5070,172 @@ var TrackEvent;
5069
5070
  TrackEvent["PreConnectBufferFlushed"] = "preConnectBufferFlushed";
5070
5071
  })(TrackEvent || (TrackEvent = {}));
5071
5072
 
5073
+ function compact(summary) {
5074
+ const compacted = {};
5075
+ for (const _ref of Object.entries(summary)) {
5076
+ var _ref2 = _slicedToArray(_ref, 2);
5077
+ const key = _ref2[0];
5078
+ const value = _ref2[1];
5079
+ if (value !== undefined) {
5080
+ compacted[key] = value;
5081
+ }
5082
+ }
5083
+ return compacted;
5084
+ }
5085
+ function resolution(width, height) {
5086
+ return width && height ? "".concat(width, "x").concat(height) : undefined;
5087
+ }
5088
+ /** keeps the derived durations readable; reported values are logged as they are */
5089
+ function round(seconds) {
5090
+ return Math.round(seconds * 10000) / 10000;
5091
+ }
5092
+ /**
5093
+ * Average time media spent in the jitter buffer, in s. Both counters are
5094
+ * cumulative, so this is the average over the lifetime of the stream.
5095
+ */
5096
+ function jitterBuffer(stat) {
5097
+ const delay = stat.jitterBufferDelay;
5098
+ const emitted = stat.jitterBufferEmittedCount;
5099
+ return delay !== undefined && emitted ? round(delay / emitted) : undefined;
5100
+ }
5101
+ /**
5102
+ * Playout delay in s. Video receive reports it directly, the audio path keeps it
5103
+ * in the linked `media-playout` stats summed over the samples played out. Pairs
5104
+ * with `RemoteTrack.setPlayoutDelay`.
5105
+ */
5106
+ function playoutDelay(stat, playout) {
5107
+ if (stat.playoutDelay !== undefined) {
5108
+ return round(stat.playoutDelay);
5109
+ }
5110
+ const total = playout === null || playout === void 0 ? void 0 : playout.totalPlayoutDelay;
5111
+ const samples = playout === null || playout === void 0 ? void 0 : playout.totalSamplesCount;
5112
+ return total !== undefined && samples ? round(total / samples) : undefined;
5113
+ }
5114
+ /**
5115
+ * Picks the interesting fields out of a `getStats()` report and groups them by
5116
+ * RTP stream, so a stats dump can be read without unfolding the raw report.
5117
+ */
5118
+ function summarizeStatsReport(report) {
5119
+ var _a, _b;
5120
+ const byId = new Map();
5121
+ const candidatePairs = [];
5122
+ const inbound = [];
5123
+ const outbound = [];
5124
+ let transport;
5125
+ report.forEach(stat => byId.set(stat.id, stat));
5126
+ const codecOf = stat => {
5127
+ var _a;
5128
+ return stat.codecId ? (_a = byId.get(stat.codecId)) === null || _a === void 0 ? void 0 : _a.mimeType : undefined;
5129
+ };
5130
+ const relatedOf = (stat, key) => stat[key] ? byId.get(stat[key]) : undefined;
5131
+ report.forEach(stat => {
5132
+ switch (stat.type) {
5133
+ case 'inbound-rtp':
5134
+ {
5135
+ const playout = relatedOf(stat, 'playoutId');
5136
+ inbound.push(compact({
5137
+ kind: stat.kind,
5138
+ ssrc: stat.ssrc,
5139
+ mid: stat.mid,
5140
+ // matches `streamTrackID` in the track's own log context
5141
+ trackId: stat.trackIdentifier,
5142
+ codec: codecOf(stat),
5143
+ decoder: stat.decoderImplementation,
5144
+ resolution: resolution(stat.frameWidth, stat.frameHeight),
5145
+ fps: stat.framesPerSecond,
5146
+ bytesReceived: stat.bytesReceived,
5147
+ packetsReceived: stat.packetsReceived,
5148
+ packetsLost: stat.packetsLost,
5149
+ packetsDiscarded: stat.packetsDiscarded,
5150
+ // frames received without frames decoded is a decode failure
5151
+ framesReceived: stat.framesReceived,
5152
+ framesDecoded: stat.framesDecoded,
5153
+ framesDropped: stat.framesDropped,
5154
+ keyFramesDecoded: stat.keyFramesDecoded,
5155
+ freezeCount: stat.freezeCount,
5156
+ totalFreezesDuration: stat.totalFreezesDuration,
5157
+ pauseCount: stat.pauseCount,
5158
+ nackCount: stat.nackCount,
5159
+ pliCount: stat.pliCount,
5160
+ firCount: stat.firCount,
5161
+ jitter: stat.jitter,
5162
+ jitterBuffer: jitterBuffer(stat),
5163
+ playoutDelay: playoutDelay(stat, playout),
5164
+ audioLevel: stat.audioLevel,
5165
+ totalSamplesReceived: stat.totalSamplesReceived,
5166
+ concealedSamples: stat.concealedSamples
5167
+ }));
5168
+ break;
5169
+ }
5170
+ case 'outbound-rtp':
5171
+ {
5172
+ const remote = relatedOf(stat, 'remoteId');
5173
+ const source = relatedOf(stat, 'mediaSourceId');
5174
+ outbound.push(compact({
5175
+ kind: stat.kind,
5176
+ ssrc: stat.ssrc,
5177
+ mid: stat.mid,
5178
+ rid: stat.rid,
5179
+ trackId: source === null || source === void 0 ? void 0 : source.trackIdentifier,
5180
+ active: stat.active,
5181
+ codec: codecOf(stat),
5182
+ encoder: stat.encoderImplementation,
5183
+ resolution: resolution(stat.frameWidth, stat.frameHeight),
5184
+ fps: stat.framesPerSecond,
5185
+ // what the source produces, to tell a stalled capture from a stalled encoder
5186
+ captureResolution: resolution(source === null || source === void 0 ? void 0 : source.width, source === null || source === void 0 ? void 0 : source.height),
5187
+ captureFps: source === null || source === void 0 ? void 0 : source.framesPerSecond,
5188
+ audioLevel: source === null || source === void 0 ? void 0 : source.audioLevel,
5189
+ targetBitrate: stat.targetBitrate,
5190
+ bytesSent: stat.bytesSent,
5191
+ packetsSent: stat.packetsSent,
5192
+ retransmittedPacketsSent: stat.retransmittedPacketsSent,
5193
+ framesEncoded: stat.framesEncoded,
5194
+ keyFramesEncoded: stat.keyFramesEncoded,
5195
+ limitedBy: stat.qualityLimitationReason === 'none' ? undefined : stat.qualityLimitationReason,
5196
+ nackCount: stat.nackCount,
5197
+ pliCount: stat.pliCount,
5198
+ firCount: stat.firCount,
5199
+ // loss, jitter and RTT are only known from what the remote reports
5200
+ remotePacketsLost: remote === null || remote === void 0 ? void 0 : remote.packetsLost,
5201
+ remoteFractionLost: remote === null || remote === void 0 ? void 0 : remote.fractionLost,
5202
+ remoteJitter: remote === null || remote === void 0 ? void 0 : remote.jitter,
5203
+ remoteRoundTripTime: remote === null || remote === void 0 ? void 0 : remote.roundTripTime
5204
+ }));
5205
+ break;
5206
+ }
5207
+ case 'transport':
5208
+ transport = stat;
5209
+ break;
5210
+ case 'candidate-pair':
5211
+ candidatePairs.push(stat);
5212
+ break;
5213
+ }
5214
+ });
5215
+ const selectedPairId = transport === null || transport === void 0 ? void 0 : transport.selectedCandidatePairId;
5216
+ 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);
5217
+ const local = (pair === null || pair === void 0 ? void 0 : pair.localCandidateId) ? byId.get(pair.localCandidateId) : undefined;
5218
+ const remote = (pair === null || pair === void 0 ? void 0 : pair.remoteCandidateId) ? byId.get(pair.remoteCandidateId) : undefined;
5219
+ const connection = compact({
5220
+ ice: transport === null || transport === void 0 ? void 0 : transport.iceState,
5221
+ dtls: transport === null || transport === void 0 ? void 0 : transport.dtlsState,
5222
+ route: local && remote ? "".concat(local.candidateType, "/").concat(local.protocol, " -> ").concat(remote.candidateType) : undefined,
5223
+ network: local === null || local === void 0 ? void 0 : local.networkType,
5224
+ currentRoundTripTime: pair === null || pair === void 0 ? void 0 : pair.currentRoundTripTime,
5225
+ // the send bandwidth estimate; no RTP stream reports it
5226
+ availableOutgoingBitrate: pair === null || pair === void 0 ? void 0 : pair.availableOutgoingBitrate,
5227
+ availableIncomingBitrate: pair === null || pair === void 0 ? void 0 : pair.availableIncomingBitrate,
5228
+ bytesSent: pair === null || pair === void 0 ? void 0 : pair.bytesSent,
5229
+ bytesReceived: pair === null || pair === void 0 ? void 0 : pair.bytesReceived,
5230
+ candidatePairChanges: transport === null || transport === void 0 ? void 0 : transport.selectedCandidatePairChanges
5231
+ });
5232
+ return {
5233
+ connection: Object.keys(connection).length > 0 ? connection : undefined,
5234
+ outbound: outbound.length > 0 ? outbound : undefined,
5235
+ inbound: inbound.length > 0 ? inbound : undefined
5236
+ };
5237
+ }
5238
+
5072
5239
  class VideoPreset {
5073
5240
  constructor(widthOrOptions, height, maxBitrate, maxFramerate, priority) {
5074
5241
  if (typeof widthOrOptions === 'object') {
@@ -5233,6 +5400,7 @@ class Track extends eventsExports.EventEmitter {
5233
5400
  this._streamState = Track.StreamState.Active;
5234
5401
  this.isInBackground = false;
5235
5402
  this._currentBitrate = 0;
5403
+ this.finalStatsLogged = false;
5236
5404
  this.log = livekitLogger;
5237
5405
  this.appVisibilityChangedListener = () => {
5238
5406
  if (this.backgroundTimeout) {
@@ -5377,9 +5545,28 @@ class Track extends eventsExports.EventEmitter {
5377
5545
  if (this.monitorInterval) {
5378
5546
  clearInterval(this.monitorInterval);
5379
5547
  }
5380
- if (this.timeSyncHandle) {
5548
+ if (this.timeSyncHandle !== undefined) {
5381
5549
  cancelAnimationFrame(this.timeSyncHandle);
5550
+ this.timeSyncHandle = undefined;
5382
5551
  }
5552
+ this.logFinalStats();
5553
+ }
5554
+ /**
5555
+ * Dumps the raw stats of the track as it ends, once: a track that stops
5556
+ * between two of the room's stats dumps is gone by the time the next one runs.
5557
+ */
5558
+ logFinalStats() {
5559
+ if (this.finalStatsLogged) {
5560
+ return;
5561
+ }
5562
+ this.finalStatsLogged = true;
5563
+ this.getRTCStatsReport().then(report => {
5564
+ if (report) {
5565
+ this.log.info('final track stats', summarizeStatsReport(report));
5566
+ }
5567
+ }).catch(error => this.log.debug('could not collect final track stats', {
5568
+ error
5569
+ }));
5383
5570
  }
5384
5571
  /** @internal */
5385
5572
  updateLoggerOptions(loggerOptions) {