livekit-client 2.22.3 → 2.22.4

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 (214) hide show
  1. package/README.md +35 -0
  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 +2 -1
  5. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  6. package/dist/livekit-client.esm.mjs +602 -247
  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 +2 -1
  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 +4 -2
  15. package/dist/src/api/SignalClient.d.ts.map +1 -1
  16. package/dist/src/options.d.ts +14 -0
  17. package/dist/src/options.d.ts.map +1 -1
  18. package/dist/src/room/PCTransport.d.ts +78 -7
  19. package/dist/src/room/PCTransport.d.ts.map +1 -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 +1 -1
  24. package/dist/src/room/Room.d.ts.map +1 -1
  25. package/dist/src/room/defaults.d.ts.map +1 -1
  26. package/dist/src/room/errors.d.ts +18 -0
  27. package/dist/src/room/errors.d.ts.map +1 -1
  28. package/dist/src/room/events.d.ts +3 -2
  29. package/dist/src/room/events.d.ts.map +1 -1
  30. package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
  31. package/dist/src/room/rpc/client/RpcClientManager.d.ts.map +1 -1
  32. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  33. package/dist/src/room/track/LocalVideoTrack.d.ts +2 -0
  34. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  35. package/dist/src/room/track/utils.d.ts +13 -0
  36. package/dist/src/room/track/utils.d.ts.map +1 -1
  37. package/dist/src/room/utils.d.ts +32 -0
  38. package/dist/src/room/utils.d.ts.map +1 -1
  39. package/dist/src/test/compressionStreamStubs.d.ts +12 -0
  40. package/dist/src/test/compressionStreamStubs.d.ts.map +1 -0
  41. package/dist/ts4.2/api/SignalClient.d.ts +187 -185
  42. package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -85
  43. package/dist/ts4.2/api/WebSocketStream.d.ts +33 -33
  44. package/dist/ts4.2/api/utils.d.ts +9 -9
  45. package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +30 -30
  46. package/dist/ts4.2/connectionHelper/checks/Checker.d.ts +62 -62
  47. package/dist/ts4.2/connectionHelper/checks/cloudRegion.d.ts +18 -18
  48. package/dist/ts4.2/connectionHelper/checks/connectionProtocol.d.ts +20 -20
  49. package/dist/ts4.2/connectionHelper/checks/publishAudio.d.ts +6 -6
  50. package/dist/ts4.2/connectionHelper/checks/publishVideo.d.ts +7 -7
  51. package/dist/ts4.2/connectionHelper/checks/reconnect.d.ts +6 -6
  52. package/dist/ts4.2/connectionHelper/checks/turn.d.ts +6 -6
  53. package/dist/ts4.2/connectionHelper/checks/webrtc.d.ts +6 -6
  54. package/dist/ts4.2/connectionHelper/checks/websocket.d.ts +6 -6
  55. package/dist/ts4.2/e2ee/E2eeManager.d.ts +111 -111
  56. package/dist/ts4.2/e2ee/KeyProvider.d.ts +54 -54
  57. package/dist/ts4.2/e2ee/constants.d.ts +21 -21
  58. package/dist/ts4.2/e2ee/errors.d.ts +12 -12
  59. package/dist/ts4.2/e2ee/events.d.ts +39 -39
  60. package/dist/ts4.2/e2ee/index.d.ts +6 -6
  61. package/dist/ts4.2/e2ee/types.d.ts +231 -231
  62. package/dist/ts4.2/e2ee/utils.d.ts +32 -32
  63. package/dist/ts4.2/e2ee/worker/DataCryptor.d.ts +16 -16
  64. package/dist/ts4.2/e2ee/worker/ErrorRateLimiter.d.ts +21 -21
  65. package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +209 -209
  66. package/dist/ts4.2/e2ee/worker/ParticipantKeyHandler.d.ts +81 -84
  67. package/dist/ts4.2/e2ee/worker/e2ee.worker.d.ts +2 -2
  68. package/dist/ts4.2/e2ee/worker/naluUtils.d.ts +28 -28
  69. package/dist/ts4.2/e2ee/worker/sifPayload.d.ts +23 -23
  70. package/dist/ts4.2/frameMetadata/FrameMetadataManager.d.ts +53 -53
  71. package/dist/ts4.2/frameMetadata/frameMetadata.d.ts +33 -33
  72. package/dist/ts4.2/frameMetadata/types.d.ts +62 -62
  73. package/dist/ts4.2/frameMetadata/utils.d.ts +9 -9
  74. package/dist/ts4.2/frameMetadata/worker/frameMetadata.worker.d.ts +2 -2
  75. package/dist/ts4.2/index.d.ts +76 -76
  76. package/dist/ts4.2/logger.d.ts +66 -66
  77. package/dist/ts4.2/options.d.ts +163 -149
  78. package/dist/ts4.2/room/BackOffStrategy.d.ts +27 -27
  79. package/dist/ts4.2/room/DefaultReconnectPolicy.d.ts +8 -8
  80. package/dist/ts4.2/room/DeviceManager.d.ts +12 -12
  81. package/dist/ts4.2/room/PCTransport.d.ts +246 -175
  82. package/dist/ts4.2/room/PCTransportManager.d.ts +77 -77
  83. package/dist/ts4.2/room/RTCEngine.d.ts +269 -262
  84. package/dist/ts4.2/room/ReconnectPolicy.d.ts +24 -24
  85. package/dist/ts4.2/room/RegionUrlProvider.d.ts +36 -36
  86. package/dist/ts4.2/room/Room.d.ts +354 -365
  87. package/dist/ts4.2/room/attribute-typings.d.ts +35 -35
  88. package/dist/ts4.2/room/data-channel/DataChannelManager.d.ts +62 -62
  89. package/dist/ts4.2/room/data-channel/FlowControlledDataChannel.d.ts +94 -95
  90. package/dist/ts4.2/room/data-channel/LossyDataChannel.d.ts +41 -41
  91. package/dist/ts4.2/room/data-channel/ReliableDataChannel.d.ts +57 -57
  92. package/dist/ts4.2/room/data-channel/types.d.ts +12 -12
  93. package/dist/ts4.2/room/data-stream/compression.d.ts +49 -49
  94. package/dist/ts4.2/room/data-stream/constants.d.ts +18 -18
  95. package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +29 -29
  96. package/dist/ts4.2/room/data-stream/incoming/StreamReader.d.ts +80 -80
  97. package/dist/ts4.2/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +73 -73
  98. package/dist/ts4.2/room/data-stream/outgoing/StreamWriter.d.ts +16 -16
  99. package/dist/ts4.2/room/data-stream/outgoing/header-utils.d.ts +18 -18
  100. package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +79 -80
  101. package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +50 -50
  102. package/dist/ts4.2/room/data-track/depacketizer.d.ts +59 -59
  103. package/dist/ts4.2/room/data-track/frame.d.ts +22 -22
  104. package/dist/ts4.2/room/data-track/handle.d.ts +27 -27
  105. package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +124 -124
  106. package/dist/ts4.2/room/data-track/incoming/errors.d.ts +24 -24
  107. package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +41 -41
  108. package/dist/ts4.2/room/data-track/incoming/types.d.ts +20 -20
  109. package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +126 -126
  110. package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +74 -74
  111. package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +23 -23
  112. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +48 -48
  113. package/dist/ts4.2/room/data-track/packet/constants.d.ts +20 -20
  114. package/dist/ts4.2/room/data-track/packet/errors.d.ts +40 -40
  115. package/dist/ts4.2/room/data-track/packet/extensions.d.ts +69 -69
  116. package/dist/ts4.2/room/data-track/packet/index.d.ts +98 -98
  117. package/dist/ts4.2/room/data-track/packet/serializable.d.ts +13 -13
  118. package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -43
  119. package/dist/ts4.2/room/data-track/track-interfaces.d.ts +23 -23
  120. package/dist/ts4.2/room/data-track/types.d.ts +22 -22
  121. package/dist/ts4.2/room/data-track/utils.d.ts +60 -60
  122. package/dist/ts4.2/room/debounce.d.ts +11 -11
  123. package/dist/ts4.2/room/defaults.d.ts +9 -9
  124. package/dist/ts4.2/room/errors.d.ts +180 -162
  125. package/dist/ts4.2/room/events.d.ts +638 -637
  126. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +287 -287
  127. package/dist/ts4.2/room/participant/Participant.d.ts +142 -144
  128. package/dist/ts4.2/room/participant/ParticipantTrackPermission.d.ts +26 -26
  129. package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +85 -86
  130. package/dist/ts4.2/room/participant/publishUtils.d.ts +53 -53
  131. package/dist/ts4.2/room/rpc/client/RpcClientManager.d.ts +43 -43
  132. package/dist/ts4.2/room/rpc/client/events.d.ts +8 -8
  133. package/dist/ts4.2/room/rpc/index.d.ts +7 -7
  134. package/dist/ts4.2/room/rpc/server/RpcServerManager.d.ts +44 -44
  135. package/dist/ts4.2/room/rpc/server/events.d.ts +8 -8
  136. package/dist/ts4.2/room/rpc/utils.d.ts +131 -131
  137. package/dist/ts4.2/room/stats.d.ts +71 -71
  138. package/dist/ts4.2/room/statsSummary.d.ts +13 -13
  139. package/dist/ts4.2/room/timers.d.ts +12 -12
  140. package/dist/ts4.2/room/token-source/TokenSource.d.ts +82 -82
  141. package/dist/ts4.2/room/token-source/types.d.ts +70 -70
  142. package/dist/ts4.2/room/token-source/utils.d.ts +8 -8
  143. package/dist/ts4.2/room/track/FrameMetadataExtractor.d.ts +19 -19
  144. package/dist/ts4.2/room/track/LocalAudioTrack.d.ts +39 -42
  145. package/dist/ts4.2/room/track/LocalTrack.d.ts +125 -125
  146. package/dist/ts4.2/room/track/LocalTrackPublication.d.ts +42 -42
  147. package/dist/ts4.2/room/track/LocalVideoTrack.d.ts +102 -100
  148. package/dist/ts4.2/room/track/RemoteAudioTrack.d.ts +55 -55
  149. package/dist/ts4.2/room/track/RemoteTrack.d.ts +38 -38
  150. package/dist/ts4.2/room/track/RemoteTrackPublication.d.ts +72 -75
  151. package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +73 -76
  152. package/dist/ts4.2/room/track/Track.d.ts +156 -166
  153. package/dist/ts4.2/room/track/TrackPublication.d.ts +75 -81
  154. package/dist/ts4.2/room/track/create.d.ts +25 -25
  155. package/dist/ts4.2/room/track/facingMode.d.ts +41 -41
  156. package/dist/ts4.2/room/track/options.d.ts +403 -403
  157. package/dist/ts4.2/room/track/processor/types.d.ts +31 -31
  158. package/dist/ts4.2/room/track/record.d.ts +13 -13
  159. package/dist/ts4.2/room/track/types.d.ts +28 -28
  160. package/dist/ts4.2/room/track/utils.d.ts +60 -47
  161. package/dist/ts4.2/room/types.d.ts +127 -127
  162. package/dist/ts4.2/room/utils.d.ts +246 -214
  163. package/dist/ts4.2/test/MockMediaStreamTrack.d.ts +26 -26
  164. package/dist/ts4.2/test/compressionStreamStubs.d.ts +12 -0
  165. package/dist/ts4.2/test/mocks.d.ts +12 -12
  166. package/dist/ts4.2/test/promiseState.d.ts +12 -12
  167. package/dist/ts4.2/test/signalToken.d.ts +26 -26
  168. package/dist/ts4.2/type-polyfills/non-shared-typed-arrays.d.ts +2 -2
  169. package/dist/ts4.2/utils/AsyncQueue.d.ts +23 -23
  170. package/dist/ts4.2/utils/TypedPromise.d.ts +17 -17
  171. package/dist/ts4.2/utils/abort-signal-polyfill.d.ts +13 -13
  172. package/dist/ts4.2/utils/browserParser.d.ts +13 -13
  173. package/dist/ts4.2/utils/camelToSnakeCase.d.ts +8 -8
  174. package/dist/ts4.2/utils/cloneDeep.d.ts +2 -2
  175. package/dist/ts4.2/utils/dataPacketBuffer.d.ts +34 -34
  176. package/dist/ts4.2/utils/deferrable-map.d.ts +32 -32
  177. package/dist/ts4.2/utils/machineInspector.d.ts +54 -54
  178. package/dist/ts4.2/utils/serializer.d.ts +48 -48
  179. package/dist/ts4.2/utils/subscribeToEvents.d.ts +15 -15
  180. package/dist/ts4.2/utils/ttlmap.d.ts +20 -20
  181. package/dist/ts4.2/version.d.ts +15 -15
  182. package/package.json +5 -4
  183. package/src/api/SignalClient.e2e.test.ts +1 -3
  184. package/src/api/SignalClient.test.ts +160 -10
  185. package/src/api/SignalClient.ts +75 -54
  186. package/src/options.ts +16 -0
  187. package/src/room/PCTransport.test.ts +183 -7
  188. package/src/room/PCTransport.ts +197 -36
  189. package/src/room/PCTransportManager.ts +3 -1
  190. package/src/room/RTCEngine.test.ts +84 -0
  191. package/src/room/RTCEngine.ts +24 -5
  192. package/src/room/Room.test.ts +32 -6
  193. package/src/room/Room.ts +26 -6
  194. package/src/room/data-stream/incoming/IncomingDataStreamManager.test.ts +16 -20
  195. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +5 -5
  196. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.test.ts +60 -39
  197. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +4 -4
  198. package/src/room/defaults.ts +1 -0
  199. package/src/room/errors.test.ts +36 -0
  200. package/src/room/errors.ts +27 -0
  201. package/src/room/events.ts +2 -1
  202. package/src/room/participant/publishUtils.ts +0 -19
  203. package/src/room/rpc/client/RpcClientManager.test.ts +51 -0
  204. package/src/room/rpc/client/RpcClientManager.ts +32 -15
  205. package/src/room/track/LocalTrack.ts +18 -7
  206. package/src/room/track/LocalVideoTrack.ts +10 -3
  207. package/src/room/track/RemoteAudioTrack.ts +3 -3
  208. package/src/room/track/RemoteVideoTrack.test.ts +210 -0
  209. package/src/room/track/RemoteVideoTrack.ts +29 -3
  210. package/src/room/track/utils.test.ts +201 -2
  211. package/src/room/track/utils.ts +88 -0
  212. package/src/room/utils.test.ts +124 -0
  213. package/src/room/utils.ts +70 -0
  214. package/src/test/compressionStreamStubs.ts +53 -0
@@ -5473,6 +5473,9 @@ const ClientInfo_SDK = /* @__PURE__ */proto3.makeEnum("livekit.ClientInfo.SDK",
5473
5473
  }, {
5474
5474
  no: 14,
5475
5475
  name: "ESP32"
5476
+ }, {
5477
+ no: 15,
5478
+ name: "DOTNET"
5476
5479
  }]);
5477
5480
  const ClientInfo_Capability = /* @__PURE__ */proto3.makeEnum("livekit.ClientInfo.Capability", [{
5478
5481
  no: 0,
@@ -5841,6 +5844,9 @@ const EncodingOptionsPreset = /* @__PURE__ */proto3.makeEnum("livekit.EncodingOp
5841
5844
  }, {
5842
5845
  no: 7,
5843
5846
  name: "PORTRAIT_H264_1080P_60"
5847
+ }, {
5848
+ no: 8,
5849
+ name: "PASSTHROUGH"
5844
5850
  }]);
5845
5851
  const EncodedFileType = /* @__PURE__ */proto3.makeEnum("livekit.EncodedFileType", [{
5846
5852
  no: 0,
@@ -7825,6 +7831,11 @@ const SyncState = /* @__PURE__ */proto3.makeMessageType("livekit.SyncState", ()
7825
7831
  kind: "message",
7826
7832
  T: PublishDataTrackResponse,
7827
7833
  repeated: true
7834
+ }, {
7835
+ no: 9,
7836
+ name: "data_subscription",
7837
+ kind: "message",
7838
+ T: UpdateDataSubscription
7828
7839
  }]);
7829
7840
  const DataChannelReceiveState = /* @__PURE__ */proto3.makeMessageType("livekit.DataChannelReceiveState", () => [{
7830
7841
  no: 1,
@@ -12279,7 +12290,7 @@ function getMatch(exp, ua) {
12279
12290
  }
12280
12291
  function getOSVersion(ua) {
12281
12292
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
12282
- }var version$1 = "2.22.3";const version = version$1;
12293
+ }var version$1 = "2.22.4";const version = version$1;
12283
12294
  const protocolVersion = 17;
12284
12295
  /** Initial client protocol. */
12285
12296
  const CLIENT_PROTOCOL_DEFAULT = 0;
@@ -12360,6 +12371,32 @@ class ConnectionError extends LivekitReasonedError {
12360
12371
  return new ConnectionError(message, ConnectionErrorReason.ServiceNotFound, undefined, serviceName);
12361
12372
  }
12362
12373
  }
12374
+ /**
12375
+ * Whether a failed connection attempt may be retried against a different LiveKit Cloud region.
12376
+ *
12377
+ * LiveKit Cloud signals project-level region pinning by returning 403 on the RTC paths when the
12378
+ * project is not allowed in the region the client geo-routed to. `/settings/regions` is
12379
+ * deliberately left reachable so the client can discover its allowed regions and connect there, so
12380
+ * a 403 must not be treated as terminal.
12381
+ *
12382
+ * A 401 stays terminal: no other region will accept a token this one rejected. So does the 404
12383
+ * "requested room does not exist" case, which is also reported as `NotAllowed`.
12384
+ *
12385
+ * We key on the status rather than the server's error message because that message is an
12386
+ * unversioned human-readable string; matching it would let a copy edit break already-shipped
12387
+ * clients. If a 403 really was a permissions failure rather than region pinning, every region
12388
+ * attempt fails the same way and the original error still surfaces — at the cost of one extra
12389
+ * region lookup.
12390
+ */
12391
+ function canFailOverToAnotherRegion(error) {
12392
+ if (error.reason === ConnectionErrorReason.Cancelled) {
12393
+ return false;
12394
+ }
12395
+ if (error.reason === ConnectionErrorReason.NotAllowed) {
12396
+ return error.status === 403;
12397
+ }
12398
+ return true;
12399
+ }
12363
12400
  class DeviceUnsupportedError extends LivekitError {
12364
12401
  constructor(message) {
12365
12402
  super(21, message !== null && message !== void 0 ? message : 'device is unsupported');
@@ -12693,7 +12730,7 @@ var RoomEvent;
12693
12730
  * Data packets provides the ability to use LiveKit to send/receive arbitrary payloads.
12694
12731
  * All participants in the room will receive the messages sent to the room.
12695
12732
  *
12696
- * args: (payload: NonSharedUint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]], topic?: string)
12733
+ * args: (payload: NonSharedUint8Array, participant: [[Participant]] | undefined, kind: [[DataPacket_Kind]], topic?: string, encryptionType?: Encryption_Type, participantIdentity?: string)
12697
12734
  */
12698
12735
  RoomEvent["DataReceived"] = "dataReceived";
12699
12736
  /**
@@ -13051,6 +13088,7 @@ var EngineEvent;
13051
13088
  EngineEvent["Joined"] = "joined";
13052
13089
  EngineEvent["TokenRefreshed"] = "tokenRefreshed";
13053
13090
  EngineEvent["ServerRegionsReported"] = "serverRegionsReported";
13091
+ EngineEvent["RequestSubscribedCodecRefresh"] = "requestSubscribedCodecRefresh";
13054
13092
  })(EngineEvent || (EngineEvent = {}));
13055
13093
  var TrackEvent;
13056
13094
  (function (TrackEvent) {
@@ -13745,6 +13783,85 @@ function areDimensionsSmaller(a, b) {
13745
13783
  function layerDimensionsFor(trackInfo, quality) {
13746
13784
  var _a;
13747
13785
  return (_a = trackInfo.layers) === null || _a === void 0 ? void 0 : _a.find(l => l.quality === quality);
13786
+ }
13787
+ /**
13788
+ * Waits until `track` has actually produced a video frame.
13789
+ *
13790
+ * iOS keeps reporting the camera's sensor frame from `getSettings()` until the camera has
13791
+ * delivered its first picture, so a portrait capture initially reads as landscape. The arrival
13792
+ * of that first frame is the only reliable signal that the reported settings describe reality.
13793
+ *
13794
+ * Best effort, never throws. Resolves `true` when a frame was observed, `false` when no frame
13795
+ * can be observed (the track is already ended, muted or disabled) or `timeoutMs` elapsed first.
13796
+ *
13797
+ * @internal
13798
+ */
13799
+ function waitForFirstVideoFrame(track_1, timeoutMs_1) {
13800
+ return __awaiter(this, arguments, void 0, function (track, timeoutMs) {
13801
+ let candidateElements = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
13802
+ return function* () {
13803
+ var _a;
13804
+ if (typeof document === 'undefined') {
13805
+ return false;
13806
+ }
13807
+ if (track.readyState === 'ended' || track.muted || !track.enabled) {
13808
+ // no frame is ever going to arrive, don't hold the caller up for the full timeout
13809
+ return false;
13810
+ }
13811
+ // requestVideoFrameCallback (Safari 15.4 and up) is a platform capability, so the answer is the
13812
+ // same for every element
13813
+ const supportsFrameCallback = typeof HTMLVideoElement.prototype.requestVideoFrameCallback === 'function';
13814
+ // prefer an element that is already rendering this track (a local preview, typically) over
13815
+ // spinning up a second decode just to observe a frame
13816
+ const existingElement = candidateElements.find(el => el instanceof HTMLVideoElement && el.srcObject instanceof MediaStream && el.srcObject.getVideoTracks().includes(track) && (
13817
+ // without requestVideoFrameCallback we depend on `loadeddata`, which is one-shot: an element
13818
+ // that already decoded a frame (readyState >= HAVE_CURRENT_DATA) never fires it again.
13819
+ // Leave those alone and set up our own element, which starts out empty.
13820
+ supportsFrameCallback || el.readyState < 2));
13821
+ const element = existingElement !== null && existingElement !== void 0 ? existingElement : document.createElement('video');
13822
+ if (!existingElement) {
13823
+ element.playsInline = true;
13824
+ element.muted = true;
13825
+ element.srcObject = new MediaStream([track]);
13826
+ // the element is deliberately never added to the DOM, it only exists to pull frames.
13827
+ // WebKit delivers frames to a paused element too, so a rejected play() (Safari's low power
13828
+ // mode, for instance) is not a reason to stop waiting
13829
+ element.play().catch(error => {
13830
+ livekitLogger.debug('could not play element while waiting for the first video frame', {
13831
+ error
13832
+ });
13833
+ });
13834
+ }
13835
+ let timer;
13836
+ let frameHandle;
13837
+ let onLoadedData;
13838
+ try {
13839
+ return yield new Promise(resolve => {
13840
+ timer = setTimeout(() => resolve(false), timeoutMs);
13841
+ if (supportsFrameCallback) {
13842
+ frameHandle = element.requestVideoFrameCallback(() => resolve(true));
13843
+ } else {
13844
+ // Safari below 15.4 has no requestVideoFrameCallback. `loadeddata` fires once the first
13845
+ // frame has been decoded, which is the same signal a few milliseconds earlier.
13846
+ onLoadedData = () => resolve(true);
13847
+ element.addEventListener('loadeddata', onLoadedData);
13848
+ }
13849
+ });
13850
+ } finally {
13851
+ clearTimeout(timer);
13852
+ if (frameHandle !== undefined) {
13853
+ (_a = element.cancelVideoFrameCallback) === null || _a === void 0 ? void 0 : _a.call(element, frameHandle);
13854
+ }
13855
+ if (onLoadedData) {
13856
+ element.removeEventListener('loadeddata', onLoadedData);
13857
+ }
13858
+ if (!existingElement) {
13859
+ element.pause();
13860
+ element.srcObject = null;
13861
+ }
13862
+ }
13863
+ }();
13864
+ });
13748
13865
  }const BACKGROUND_REACTION_DELAY = 5000;
13749
13866
  // keep old audio elements when detached, we would re-use them since on iOS
13750
13867
  // Safari tracks which audio elements have been "blessed" by the user.
@@ -14384,6 +14501,32 @@ function isSafariBased() {
14384
14501
  const b = getBrowser();
14385
14502
  return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' || (b === null || b === void 0 ? void 0 : b.os) === 'iOS';
14386
14503
  }
14504
+ /**
14505
+ * iPadOS has sent the desktop Macintosh user agent by default since iPadOS 13, so `getBrowser()`
14506
+ * reports `os: 'macOS'` there and every `os === 'iOS'` check misses it. macOS Safari implements no
14507
+ * touch events at all (`TouchEvent` undefined, `maxTouchPoints` 0) regardless of any touchscreen
14508
+ * attached, so touch capability separates the two. Measured on an iPad 6 / iPadOS 17
14509
+ * (`maxTouchPoints` 5) against macOS Safari 26.4 (`maxTouchPoints` 0).
14510
+ *
14511
+ * Deliberately a separate helper rather than a fix in `browserParser`: iPadOS spoofs the Mac
14512
+ * version too, so reporting `os: 'iOS'` there would leave `osVersion` at `10.15.7` and silently
14513
+ * break {@link isSafari17Based} and {@link isSafariSvcApi}, which compare it.
14514
+ */
14515
+ function isIPadOS() {
14516
+ if (!isWeb()) {
14517
+ return false;
14518
+ }
14519
+ const b = getBrowser();
14520
+ return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' && (b === null || b === void 0 ? void 0 : b.os) === 'macOS' && navigator.maxTouchPoints > 1;
14521
+ }
14522
+ /**
14523
+ * iPhone, iPad and iOS-hosted browsers — everything running the Apple camera capture pipeline,
14524
+ * including iPads that present themselves as a Mac.
14525
+ */
14526
+ function isAppleMobile() {
14527
+ var _a;
14528
+ return ((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.os) === 'iOS' || isIPadOS();
14529
+ }
14387
14530
  function isSafari17Based() {
14388
14531
  const b = getBrowser();
14389
14532
  return (b === null || b === void 0 ? void 0 : b.name) === 'Safari' && b.version.startsWith('17.') || (b === null || b === void 0 ? void 0 : b.os) === 'iOS' && !!(b === null || b === void 0 ? void 0 : b.osVersion) && compareVersions(b.osVersion, '17') >= 0;
@@ -14875,6 +15018,35 @@ function extractMaxAgeFromRequestHeaders(headers) {
14875
15018
  function isCompressionStreamSupported() {
14876
15019
  return typeof CompressionStream !== 'undefined';
14877
15020
  }
15021
+ let deflateRawCompressionSupported = null;
15022
+ /**
15023
+ * Whether this runtime can compress AND decompress the `deflate-raw` format, which is a stricter
15024
+ * requirement than {@link isCompressionStreamSupported}: Chromium 80-102 included
15025
+ * `CompressionStream` supporting only `gzip` / `deflate`, and `deflate-raw` was added in Chromium
15026
+ * 103 (Firefox 113, Safari 16.4).
15027
+ */
15028
+ function isDeflateRawCompressionSupported() {
15029
+ if (typeof deflateRawCompressionSupported !== 'boolean') {
15030
+ deflateRawCompressionSupported = probeDeflateRawCompressionSupport();
15031
+ }
15032
+ return deflateRawCompressionSupported;
15033
+ }
15034
+ function probeDeflateRawCompressionSupport() {
15035
+ if (typeof CompressionStream === 'undefined' || typeof DecompressionStream === 'undefined') {
15036
+ return false;
15037
+ }
15038
+ try {
15039
+ // There is no api to query format support, and constructing with an unsupported format throws
15040
+ // synchronously, so constructing one of each is the probe. Both are checked because the
15041
+ // deflate-raw capability advertised to peers is as much about decompressing what they send us
15042
+ // as it is about compressing what we send them.
15043
+ new CompressionStream('deflate-raw');
15044
+ new DecompressionStream('deflate-raw');
15045
+ return true;
15046
+ } catch (_a) {
15047
+ return false;
15048
+ }
15049
+ }
14878
15050
  function isPublisherOfferWithJoinSupported() {
14879
15051
  // we have connectivity issue about publisher offer with join on firefox #1919
14880
15052
  return isCompressionStreamSupported() && !isFireFox();
@@ -15877,11 +16049,38 @@ class HTMLElementInfo {
15877
16049
  }
15878
16050
  }
15879
16051
  function isElementInPiP(el) {
15880
- var _a, _b;
16052
+ var _a;
15881
16053
  // Simple video PiP
15882
16054
  if (document.pictureInPictureElement === el) return true;
15883
- // Document PiP
15884
- if ((_a = window.documentPictureInPicture) === null || _a === void 0 ? void 0 : _a.window) return isElementInViewport(el, (_b = window.documentPictureInPicture) === null || _b === void 0 ? void 0 : _b.window);
16055
+ // Document PiP: the element has to actually live in the PiP window, otherwise an
16056
+ // opener-document element whose coordinates happen to fall inside the PiP window's
16057
+ // bounds is reported as being in PiP.
16058
+ const pipWindow = (_a = window.documentPictureInPicture) === null || _a === void 0 ? void 0 : _a.window;
16059
+ if (pipWindow) {
16060
+ return isDocumentInPiPWindow(el.ownerDocument, pipWindow) && isElementInViewport(el, pipWindow);
16061
+ }
16062
+ return false;
16063
+ }
16064
+ // Whether the document is the Document PiP window's own document, or the document of a frame
16065
+ // nested inside it. The spec allows frames in a PiP window, so an element in one is in PiP:
16066
+ // https://wicg.github.io/document-picture-in-picture/#iframes
16067
+ function isDocumentInPiPWindow(doc, pipWindow) {
16068
+ var _a, _b, _c;
16069
+ // A cross-origin frame anywhere between the element and the PiP window hides frameElement
16070
+ // from the walk below, but top stays readable across origins and identifies the top-level
16071
+ // window the element belongs to. For an opener element that is the opener, not the PiP window.
16072
+ if (((_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.top) === pipWindow) return true;
16073
+ let current = doc;
16074
+ while (current) {
16075
+ if (current === pipWindow.document) return true;
16076
+ try {
16077
+ // Reading frameElement across a cross-origin boundary throws, which means we cannot
16078
+ // establish the ancestry and must not claim the element is in PiP.
16079
+ current = (_c = (_b = current.defaultView) === null || _b === void 0 ? void 0 : _b.frameElement) === null || _c === void 0 ? void 0 : _c.ownerDocument;
16080
+ } catch (_d) {
16081
+ return false;
16082
+ }
16083
+ }
15885
16084
  return false;
15886
16085
  }
15887
16086
  // does not account for occlusion by other elements or opacity property
@@ -18576,7 +18775,7 @@ class SignalClient {
18576
18775
  const rtcUrl = createRtcUrl(url, params, useV0Path).toString();
18577
18776
  const validateUrl = createValidateUrl(rtcUrl).toString();
18578
18777
  return new Promise((resolve, reject) => __awaiter(_this2, void 0, void 0, function* () {
18579
- var _a, _b;
18778
+ var _a, _b, _c, _d, _e;
18580
18779
  try {
18581
18780
  let alreadyAborted = false;
18582
18781
  const abortHandler = eventOrError => __awaiter(this, void 0, void 0, function* () {
@@ -18683,38 +18882,56 @@ class SignalClient {
18683
18882
  const signalReader = connection.readable.getReader();
18684
18883
  this.streamWriter = connection.writable.getWriter();
18685
18884
  // wsTimeout only guarded the upgrade; guard the first-message read with
18686
- // its own timeout so a silent server can't hang join() forever.
18687
- let firstMessage;
18688
- let firstMessageTimeout;
18885
+ // its own deadline so a silent server can't hang join() forever.
18886
+ // During reconnect, drop any stray messages that arrive before the
18887
+ // ReconnectResponse so we do not declare the channel reconnected on the
18888
+ // wrong signal.
18889
+ let firstSignalResponse;
18689
18890
  try {
18690
- firstMessage = yield Promise.race([signalReader.read(), new Promise((_, rejectRead) => {
18691
- firstMessageTimeout = setTimeout(() => {
18692
- rejectRead(ConnectionError.timeout('signal connection timed out while waiting for the first message'));
18693
- }, JOIN_RESPONSE_TIMEOUT);
18694
- })]);
18891
+ const deadline = Date.now() + JOIN_RESPONSE_TIMEOUT;
18892
+ // eslint-disable-next-line no-constant-condition
18893
+ while (true) {
18894
+ const remaining = deadline - Date.now();
18895
+ if (remaining <= 0) {
18896
+ throw ConnectionError.timeout('signal connection timed out while waiting for the first message');
18897
+ }
18898
+ let readTimeout;
18899
+ const readResult = yield Promise.race([signalReader.read(), new Promise((_, rejectRead) => {
18900
+ readTimeout = setTimeout(() => {
18901
+ rejectRead(ConnectionError.timeout('signal connection timed out while waiting for the first message'));
18902
+ }, remaining);
18903
+ })]);
18904
+ clearTimeout(readTimeout);
18905
+ if (!readResult.value) {
18906
+ throw ConnectionError.internal('no message received as first message');
18907
+ }
18908
+ const parsed = parseSignalResponse(readResult.value);
18909
+ if (this.lifecycleState === 'reconnecting' && ((_a = parsed.message) === null || _a === void 0 ? void 0 : _a.case) !== 'reconnect' && ((_b = parsed.message) === null || _b === void 0 ? void 0 : _b.case) !== 'leave') {
18910
+ this.log.warn('dropping signal message while awaiting reconnect response', {
18911
+ messageCase: (_c = parsed.message) === null || _c === void 0 ? void 0 : _c.case
18912
+ });
18913
+ continue;
18914
+ }
18915
+ firstSignalResponse = parsed;
18916
+ break;
18917
+ }
18695
18918
  } catch (e) {
18696
- // No first message in time: release the reader and tear down the ws
18919
+ // No usable first message in time: release the reader and tear down the ws
18697
18920
  // so we surface the timeout instead of leaking an open connection.
18698
18921
  signalReader.releaseLock();
18699
18922
  reject(e);
18700
18923
  this.close();
18701
18924
  return;
18702
- } finally {
18703
- clearTimeout(firstMessageTimeout);
18704
18925
  }
18705
18926
  signalReader.releaseLock();
18706
- if (!firstMessage.value) {
18707
- throw ConnectionError.internal('no message received as first message');
18708
- }
18709
- const firstSignalResponse = parseSignalResponse(firstMessage.value);
18710
18927
  // Validate the first message
18711
- const validation = this.validateFirstMessage(firstSignalResponse, (_a = opts.reconnect) !== null && _a !== void 0 ? _a : false);
18928
+ const validation = this.validateFirstMessage(firstSignalResponse, (_d = opts.reconnect) !== null && _d !== void 0 ? _d : false);
18712
18929
  if (!validation.isValid) {
18713
18930
  reject(validation.error);
18714
18931
  return;
18715
18932
  }
18716
18933
  // Handle join response
18717
- if (((_b = firstSignalResponse.message) === null || _b === void 0 ? void 0 : _b.case) === 'join') {
18934
+ if (((_e = firstSignalResponse.message) === null || _e === void 0 ? void 0 : _e.case) === 'join') {
18718
18935
  // Set up ping configuration
18719
18936
  this.pingTimeoutDuration = firstSignalResponse.message.value.pingTimeout;
18720
18937
  this.pingIntervalDuration = firstSignalResponse.message.value.pingInterval;
@@ -18728,9 +18945,7 @@ class SignalClient {
18728
18945
  this.onJoined(firstSignalResponse.message.value);
18729
18946
  }
18730
18947
  }
18731
- // Handle successful connection
18732
- const firstMessageToProcess = validation.shouldProcessFirstMessage ? firstSignalResponse : undefined;
18733
- this.handleSignalConnected(connection, wsTimeout, attemptId, firstMessageToProcess);
18948
+ this.handleSignalConnected(connection, wsTimeout, attemptId);
18734
18949
  resolve(validation.response);
18735
18950
  } catch (e) {
18736
18951
  reject(e);
@@ -18744,11 +18959,8 @@ class SignalClient {
18744
18959
  }();
18745
18960
  });
18746
18961
  }
18747
- startReadingLoop(signalReader, firstMessage) {
18962
+ startReadingLoop(signalReader) {
18748
18963
  return __awaiter(this, void 0, void 0, function* () {
18749
- if (firstMessage) {
18750
- this.handleSignalResponse(firstMessage);
18751
- }
18752
18964
  const attemptId = this.attemptId;
18753
18965
  while (true) {
18754
18966
  if (this.signalLatency) {
@@ -19184,6 +19396,7 @@ class SignalClient {
19184
19396
  return __awaiter(this, arguments, void 0, function (reason) {
19185
19397
  var _this6 = this;
19186
19398
  let attemptId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.attemptId;
19399
+ let simulateReconnectDelay = arguments.length > 2 ? arguments[2] : undefined;
19187
19400
  return function* () {
19188
19401
  const onCloseCallback = _this6.onClose;
19189
19402
  if (!_this6.sendLifecycleInput({
@@ -19205,6 +19418,10 @@ class SignalClient {
19205
19418
  _this6.log.info("websocket connection closed: ".concat(reason), {
19206
19419
  reason
19207
19420
  });
19421
+ if (simulateReconnectDelay) {
19422
+ _this6.log.info("waiting for ".concat(simulateReconnectDelay, "ms until reconnecting signal"));
19423
+ yield sleep(simulateReconnectDelay);
19424
+ }
19208
19425
  if (onCloseCallback) {
19209
19426
  onCloseCallback(reason);
19210
19427
  }
@@ -19265,7 +19482,7 @@ class SignalClient {
19265
19482
  * @param firstMessage Optional first message to process
19266
19483
  * @internal
19267
19484
  */
19268
- handleSignalConnected(connection, timeoutHandle, attemptId, firstMessage) {
19485
+ handleSignalConnected(connection, timeoutHandle, attemptId) {
19269
19486
  clearTimeout(timeoutHandle);
19270
19487
  const established = this.sendLifecycleInput(this.lifecycleState === 'reconnecting' ? {
19271
19488
  type: 'reconnectComplete',
@@ -19287,7 +19504,7 @@ class SignalClient {
19287
19504
  }
19288
19505
  this.log.info('signal connected');
19289
19506
  this.startPingInterval();
19290
- this.startReadingLoop(connection.readable.getReader(), firstMessage);
19507
+ this.startReadingLoop(connection.readable.getReader());
19291
19508
  }
19292
19509
  /**
19293
19510
  * Validates the first message received from the signal server
@@ -19297,28 +19514,18 @@ class SignalClient {
19297
19514
  * @internal
19298
19515
  */
19299
19516
  validateFirstMessage(firstSignalResponse, isReconnect) {
19300
- var _a, _b, _c, _d, _e;
19517
+ var _a, _b, _c, _d;
19301
19518
  if (((_a = firstSignalResponse.message) === null || _a === void 0 ? void 0 : _a.case) === 'join') {
19302
19519
  return {
19303
19520
  isValid: true,
19304
19521
  response: firstSignalResponse.message.value
19305
19522
  };
19306
- } else if (this.lifecycleState === 'reconnecting' && ((_b = firstSignalResponse.message) === null || _b === void 0 ? void 0 : _b.case) !== 'leave') {
19307
- if (((_c = firstSignalResponse.message) === null || _c === void 0 ? void 0 : _c.case) === 'reconnect') {
19308
- return {
19309
- isValid: true,
19310
- response: firstSignalResponse.message.value
19311
- };
19312
- } else {
19313
- // in reconnecting, any message received means signal reconnected and we still need to process it
19314
- this.log.debug('declaring signal reconnected without reconnect response received');
19315
- return {
19316
- isValid: true,
19317
- response: undefined,
19318
- shouldProcessFirstMessage: true
19319
- };
19320
- }
19321
- } else if (this.isEstablishingConnection && ((_d = firstSignalResponse.message) === null || _d === void 0 ? void 0 : _d.case) === 'leave') {
19523
+ } else if (this.lifecycleState === 'reconnecting' && ((_b = firstSignalResponse.message) === null || _b === void 0 ? void 0 : _b.case) === 'reconnect') {
19524
+ return {
19525
+ isValid: true,
19526
+ response: firstSignalResponse.message.value
19527
+ };
19528
+ } else if (this.isEstablishingConnection && ((_c = firstSignalResponse.message) === null || _c === void 0 ? void 0 : _c.case) === 'leave') {
19322
19529
  return {
19323
19530
  isValid: false,
19324
19531
  error: ConnectionError.leaveRequest('Received leave request while trying to (re)connect', firstSignalResponse.message.value.reason)
@@ -19327,7 +19534,7 @@ class SignalClient {
19327
19534
  // non-reconnect case, should receive join response first
19328
19535
  return {
19329
19536
  isValid: false,
19330
- error: ConnectionError.internal("did not receive join response, got ".concat((_e = firstSignalResponse.message) === null || _e === void 0 ? void 0 : _e.case, " instead"))
19537
+ error: ConnectionError.internal("did not receive join response, got ".concat((_d = firstSignalResponse.message) === null || _d === void 0 ? void 0 : _d.case, " instead"))
19331
19538
  };
19332
19539
  }
19333
19540
  return {
@@ -19432,6 +19639,12 @@ function createConnectionParams(token, info, opts) {
19432
19639
  if (opts.adaptiveStream) {
19433
19640
  params.set('adaptive_stream', '1');
19434
19641
  }
19642
+ if (opts.disableIceLite) {
19643
+ params.set('disable_ice_lite', '1');
19644
+ }
19645
+ if (typeof opts.subscriberAllowPause !== 'undefined') {
19646
+ params.set('subscriber_allow_pause', opts.subscriberAllowPause ? '1' : '0');
19647
+ }
19435
19648
  if (opts.reconnectReason) {
19436
19649
  params.set('reconnect_reason', opts.reconnectReason.toString());
19437
19650
  }
@@ -19450,7 +19663,9 @@ function createJoinRequestConnectionParams(token, info, opts, publisherOffer) {
19450
19663
  clientInfo: info,
19451
19664
  connectionSettings: new ConnectionSettings({
19452
19665
  autoSubscribe: !!opts.autoSubscribe,
19453
- adaptiveStream: !!opts.adaptiveStream
19666
+ adaptiveStream: !!opts.adaptiveStream,
19667
+ disableIceLite: !!opts.disableIceLite,
19668
+ subscriberAllowPause: opts.subscriberAllowPause
19454
19669
  }),
19455
19670
  reconnect: !!opts.reconnect,
19456
19671
  participantSid: opts.sid ? opts.sid : undefined,
@@ -20291,40 +20506,112 @@ function requireLib() {
20291
20506
  const startBitrateMultiplier = 0.9;
20292
20507
  /** Maximum x-google-start-bitrate in kbps. 1 Mbps prevents BWE from starting too aggressively. */
20293
20508
  const maxStartBitrateKbps = 1000;
20509
+ /**
20510
+ * Minimum target bitrate in kbps for the start bitrate hint. Below this, seeding above the
20511
+ * real capacity costs more than the ramp it saves, so libwebrtc's default is left in place.
20512
+ */
20513
+ const minTargetBitrateKbps = 300;
20294
20514
  const debounceInterval = 20;
20295
20515
  /**
20296
- * Applies the configured start bitrate when this media section belongs to `cid`.
20297
- * This SDP munging is used for a bitrate setting that cannot be applied through
20298
- * `RTCRtpEncodingParameters`.
20516
+ * Codec payload for `codec` in this media section, when the section carries `cid`.
20299
20517
  *
20300
- * Returns `undefined` when the section does not belong to the track, `0` when
20301
- * it does but does not offer the requested codec, and the codec payload when the
20302
- * requested codec is present (whether the bitrate was added or already set).
20518
+ * Returns `undefined` when the section does not belong to the track, `0` when it does but
20519
+ * does not offer the requested codec, and the codec payload otherwise.
20303
20520
  *
20304
20521
  * @internal
20305
20522
  */
20306
- function applyVideoStartBitrate(media, cid, codec, maxbr) {
20307
- let isScreenShare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
20523
+ function findTrackCodecPayload(media, cid, codec) {
20308
20524
  var _a, _b, _c;
20309
20525
  if (!((_a = media.msid) === null || _a === void 0 ? void 0 : _a.includes(cid))) {
20310
20526
  return undefined;
20311
20527
  }
20312
- const codecPayload = (_c = (_b = media.rtp.find(rtp => rtp.codec.toUpperCase() === codec.toUpperCase())) === null || _b === void 0 ? void 0 : _b.payload) !== null && _c !== void 0 ? _c : 0;
20313
- if (codecPayload === 0) {
20314
- return 0;
20528
+ return (_c = (_b = media.rtp.find(rtp => rtp.codec.toUpperCase() === codec.toUpperCase())) === null || _b === void 0 ? void 0 : _b.payload) !== null && _c !== void 0 ? _c : 0;
20529
+ }
20530
+ /**
20531
+ * Start bitrate hinted for a single track, or `undefined` when its target is too low to
20532
+ * be worth seeding.
20533
+ *
20534
+ * 90% of the target leaves ~10% headroom for the estimator to settle. The same multiplier
20535
+ * is used for every codec because the target already reflects the codec's efficiency.
20536
+ * Camera is capped at 1 Mbps so the estimator does not open too aggressively on a
20537
+ * high-bitrate track; screen share is exempt, because its content needs the bitrate
20538
+ * immediately to stay legible.
20539
+ *
20540
+ * TODO: adjust dynamically from network conditions (e.g. a previous BWE estimate) rather
20541
+ * than a fixed cap.
20542
+ *
20543
+ * @internal
20544
+ */
20545
+ function computeTrackStartBitrate(trackbr) {
20546
+ if (trackbr.maxbr < minTargetBitrateKbps) {
20547
+ return undefined;
20548
+ }
20549
+ const calculated = Math.round(trackbr.maxbr * startBitrateMultiplier);
20550
+ return trackbr.isScreenShare ? calculated : Math.min(calculated, maxStartBitrateKbps);
20551
+ }
20552
+ /**
20553
+ * The single start bitrate for this peer connection: the largest hint among the video
20554
+ * m-sections of `media` that map to a published track.
20555
+ *
20556
+ * libwebrtc reads `x-google-start-bitrate` per m-section but applies it to the shared
20557
+ * `Call` (`WebRtcVideoSendChannel::ApplyChangedParams` -> `SetSdpBitrateParameters`), where
20558
+ * `RtpBitrateConfigurator` holds one config for the whole connection. Differing per-section
20559
+ * values are therefore last-writer-wins, decided by m-section order, so every video section
20560
+ * gets the same number instead.
20561
+ *
20562
+ * Only sections that can send local media are considered. `trackBitrates` is append-only and an
20563
+ * unpublished section keeps its `a=msid`, so matching on msid alone would still pair a stale
20564
+ * entry with its old section — letting an uncapped screen-share target seed a connection that
20565
+ * now carries only a camera, or consuming the one-shot hint on a section that sends nothing.
20566
+ *
20567
+ * The direction is the discriminator, as an exclusion rather than a match: `recvonly` and
20568
+ * `inactive` are the only directions that cannot carry local media, and they are exactly the
20569
+ * two a dead section lands on — unpublish sets `inactive` (explicitly in
20570
+ * `LocalParticipant.unpublishTrack`, and via `removeTrack`'s sendonly -> inactive transition for
20571
+ * the simulcast senders), `removeTrack` on a `sendrecv` transceiver leaves `recvonly`, and the
20572
+ * pre-populated placeholders are `recvonly`. Everything else sends: `sendonly` from the
20573
+ * `addTransceiver` path, `sendrecv` from the legacy `addTrack` fallback (which reuses a
20574
+ * transceiver rather than creating a sendonly one), and a section with no direction attribute,
20575
+ * which SDP defaults to `sendrecv`.
20576
+ *
20577
+ * @internal
20578
+ */
20579
+ function computeConnectionStartBitrate(media, trackBitrates) {
20580
+ let connectionStartBitrate;
20581
+ for (const m of media) {
20582
+ if (m.type !== 'video' || m.direction === 'recvonly' || m.direction === 'inactive') {
20583
+ continue;
20584
+ }
20585
+ for (const trackbr of trackBitrates) {
20586
+ if (!trackbr.cid) {
20587
+ continue;
20588
+ }
20589
+ const codecPayload = findTrackCodecPayload(m, trackbr.cid, trackbr.codec);
20590
+ if (codecPayload === undefined) {
20591
+ continue;
20592
+ }
20593
+ const startBitrate = codecPayload > 0 ? computeTrackStartBitrate(trackbr) : undefined;
20594
+ if (startBitrate !== undefined && (connectionStartBitrate === undefined || startBitrate > connectionStartBitrate)) {
20595
+ connectionStartBitrate = startBitrate;
20596
+ }
20597
+ break;
20598
+ }
20315
20599
  }
20316
- // Use 90% of target bitrate, capped at 1 Mbps for camera to prevent BWE
20317
- // from starting too aggressively. Screen share is not capped since text/UI
20318
- // clarity requires high bitrate from the start.
20319
- // TODO: dynamically adjust start bitrate based on network conditions (e.g., previous BWE estimate)
20320
- const calculatedStartBitrate = Math.round(maxbr * startBitrateMultiplier);
20321
- const startBitrate = isScreenShare ? calculatedStartBitrate : Math.min(calculatedStartBitrate, maxStartBitrateKbps);
20600
+ return connectionStartBitrate;
20601
+ }
20602
+ /**
20603
+ * Declares `x-google-start-bitrate` on `codecPayload`'s fmtp. This SDP munging is used for
20604
+ * a bitrate setting that cannot be applied through `RTCRtpEncodingParameters`.
20605
+ *
20606
+ * Returns whether the section now carries the hint.
20607
+ *
20608
+ * @internal
20609
+ */
20610
+ function applyVideoStartBitrate(media, codecPayload, startBitrate) {
20322
20611
  const fmtp = media.fmtp.find(entry => entry.payload === codecPayload);
20323
20612
  if (fmtp) {
20324
- // If another track's fmtp already has a start bitrate, it cannot be
20325
- // overridden here because the payload type is shared across the bundle.
20326
- // This forces every track sharing that payload to use the initial track's
20327
- // start bitrate.
20613
+ // A payload type is shared across the bundle, so a value written for one section is
20614
+ // already the connection-level one; leave it rather than rewrite it.
20328
20615
  if (!fmtp.config.includes('x-google-start-bitrate')) {
20329
20616
  fmtp.config += ";x-google-start-bitrate=".concat(startBitrate);
20330
20617
  }
@@ -20335,7 +20622,7 @@ function applyVideoStartBitrate(media, cid, codec, maxbr) {
20335
20622
  config: "x-google-start-bitrate=".concat(startBitrate)
20336
20623
  });
20337
20624
  }
20338
- return codecPayload;
20625
+ return true;
20339
20626
  }
20340
20627
  const PCEvents = {
20341
20628
  NegotiationStarted: 'negotiationStarted',
@@ -20363,11 +20650,20 @@ class PCTransport extends eventsExports.EventEmitter {
20363
20650
  this.iceLog = livekitLogger;
20364
20651
  this.ddExtID = 0;
20365
20652
  this.latestOfferId = 0;
20653
+ this.answeredOfferId = 0;
20366
20654
  this.latestAcknowledgedOfferId = 0;
20367
20655
  this.pendingCandidates = [];
20368
20656
  this.restartingIce = false;
20369
20657
  this.renegotiate = false;
20370
20658
  this.trackBitrates = [];
20659
+ /**
20660
+ * Whether an offer carrying the connection-level `x-google-start-bitrate` has been
20661
+ * accepted locally. The hint is written once per peer connection: libwebrtc retains
20662
+ * `start_bitrate_bps` in `RtpBitrateConfigurator` and re-applies it on network route
20663
+ * changes, so a later rewrite is at best a no-op and at worst restarts a converged
20664
+ * bandwidth estimator. A new peer connection (full reconnect) seeds a new estimator.
20665
+ */
20666
+ this.hasAppliedVideoStartBitrate = false;
20371
20667
  this.remoteStereoMids = [];
20372
20668
  this.remoteNackMids = [];
20373
20669
  // debounced negotiate interface
@@ -20476,7 +20772,7 @@ class PCTransport extends eventsExports.EventEmitter {
20476
20772
  }
20477
20773
  setRemoteDescription(sd, offerId) {
20478
20774
  return __awaiter(this, void 0, void 0, function* () {
20479
- var _a, _b;
20775
+ var _a;
20480
20776
  if (sd.type === 'answer' && this.latestOfferId > 0 && offerId > 0 && offerId !== this.latestOfferId) {
20481
20777
  this.log.warn('ignoring answer for old offer', {
20482
20778
  offerId,
@@ -20484,6 +20780,29 @@ class PCTransport extends eventsExports.EventEmitter {
20484
20780
  });
20485
20781
  return false;
20486
20782
  }
20783
+ if (sd.type === 'answer') {
20784
+ if (isDuplicateAnswer(offerId, this.answerInFlight, this.answeredOfferId, (_a = this._pc) === null || _a === void 0 ? void 0 : _a.signalingState, this.pendingInitialOffer !== undefined)) {
20785
+ // a repeat of an answer already applied or being applied (e.g.
20786
+ // duplicated by a proxy): there is no local offer left to answer
20787
+ this.log.warn('ignoring duplicate answer', {
20788
+ offerId
20789
+ });
20790
+ return false;
20791
+ }
20792
+ // claimed before any await, so a copy arriving mid-apply is caught too;
20793
+ // released however the apply ends, so a genuine retry is still possible
20794
+ this.answerInFlight = offerId;
20795
+ }
20796
+ try {
20797
+ return yield this.applyRemoteDescription(sd, offerId);
20798
+ } finally {
20799
+ if (sd.type === 'answer') this.answerInFlight = undefined;
20800
+ }
20801
+ });
20802
+ }
20803
+ applyRemoteDescription(sd, offerId) {
20804
+ return __awaiter(this, void 0, void 0, function* () {
20805
+ var _a, _b;
20487
20806
  let mungedSDP = undefined;
20488
20807
  if (sd.type === 'offer') {
20489
20808
  let _extractStereoAndNack = extractStereoAndNackAudioFromOffer(sd),
@@ -20557,6 +20876,8 @@ class PCTransport extends eventsExports.EventEmitter {
20557
20876
  mungedSDP = libExports.write(sdpParsed);
20558
20877
  }
20559
20878
  yield this.setMungedSDP(sd, mungedSDP, true);
20879
+ // only a successfully applied answer makes later copies duplicates
20880
+ if (sd.type === 'answer' && offerId > 0) this.answeredOfferId = offerId;
20560
20881
  if (this.pendingCandidates.length > 0) {
20561
20882
  this.iceLog.debug('flushing queued ICE candidates', {
20562
20883
  count: this.pendingCandidates.length
@@ -20664,6 +20985,12 @@ class PCTransport extends eventsExports.EventEmitter {
20664
20985
  sdp: offer.sdp
20665
20986
  });
20666
20987
  const sdpParsed = libExports.parse((_a = offer.sdp) !== null && _a !== void 0 ? _a : '');
20988
+ // One value for every video m-section, written only on the first offer that carries
20989
+ // local video: the hint is connection-level in libwebrtc, so differing per-section
20990
+ // values would be last-writer-wins on m-section order. Offers before any video is
20991
+ // published (data channel or audio only) find no target and leave the latch unset.
20992
+ const connectionStartBitrate = this.hasAppliedVideoStartBitrate ? undefined : computeConnectionStartBitrate(sdpParsed.media, this.trackBitrates);
20993
+ let appliedVideoStartBitrate = false;
20667
20994
  sdpParsed.media.forEach(media => {
20668
20995
  ensureIPAddrMatchVersion(media);
20669
20996
  if (media.type === 'audio') {
@@ -20673,12 +21000,17 @@ class PCTransport extends eventsExports.EventEmitter {
20673
21000
  if (!trackbr.cid) {
20674
21001
  return false;
20675
21002
  }
20676
- const codecPayload = applyVideoStartBitrate(media, trackbr.cid, trackbr.codec, trackbr.maxbr, trackbr.isScreenShare);
21003
+ const codecPayload = findTrackCodecPayload(media, trackbr.cid, trackbr.codec);
20677
21004
  if (codecPayload === undefined) {
20678
21005
  return false;
20679
21006
  }
20680
- if (codecPayload > 0 && isSVCCodec(trackbr.codec) && !isSafari()) {
20681
- this.ddExtID = ensureVideoDDExtension(media, sdpParsed, this.ddExtID);
21007
+ if (codecPayload > 0) {
21008
+ if (connectionStartBitrate !== undefined) {
21009
+ appliedVideoStartBitrate = applyVideoStartBitrate(media, codecPayload, connectionStartBitrate) || appliedVideoStartBitrate;
21010
+ }
21011
+ if (isSVCCodec(trackbr.codec) && !isSafari()) {
21012
+ this.ddExtID = ensureVideoDDExtension(media, sdpParsed, this.ddExtID);
21013
+ }
20682
21014
  }
20683
21015
  return true;
20684
21016
  });
@@ -20700,7 +21032,13 @@ class PCTransport extends eventsExports.EventEmitter {
20700
21032
  });
20701
21033
  return;
20702
21034
  }
20703
- yield this.setMungedSDP(offer, libExports.write(sdpParsed));
21035
+ const mungedSdp = libExports.write(sdpParsed);
21036
+ yield this.setMungedSDP(offer, mungedSdp);
21037
+ // setMungedSDP falls back to the unmunged SDP on rejection. Only consume the
21038
+ // one-shot hint once the SDP carrying it has been accepted locally.
21039
+ if (appliedVideoStartBitrate && offer.sdp === mungedSdp) {
21040
+ this.hasAppliedVideoStartBitrate = true;
21041
+ }
20704
21042
  this.onOffer(offer, this.latestOfferId);
20705
21043
  } finally {
20706
21044
  unlock();
@@ -21096,6 +21434,19 @@ function conformBundledCodecFmtp(media, isPlaceholder) {
21096
21434
  }
21097
21435
  }
21098
21436
  /** @internal */
21437
+ /**
21438
+ * Whether an incoming answer repeats one already applied or being applied.
21439
+ * Any answer for the offer whose answer is in flight is a duplicate, numbered
21440
+ * or not. With an offerId (current servers) an answer is also a duplicate if
21441
+ * that offer's answer was already applied. Without one, fall back to the
21442
+ * signaling state: in `stable` no local offer is pending, unless the initial
21443
+ * offer is still deferred (it is set locally only once its answer arrives).
21444
+ */
21445
+ function isDuplicateAnswer(offerId, answerInFlight, answeredOfferId, signalingState, hasPendingInitialOffer) {
21446
+ if (answerInFlight === offerId) return true;
21447
+ if (offerId > 0) return offerId === answeredOfferId;
21448
+ return signalingState === 'stable' && !hasPendingInitialOffer;
21449
+ }
21099
21450
  function extractStereoAndNackAudioFromOffer(offer) {
21100
21451
  var _a;
21101
21452
  const stereoMids = [];
@@ -21187,6 +21538,7 @@ const roomOptionDefaults = {
21187
21538
  };
21188
21539
  const roomConnectOptionDefaults = {
21189
21540
  autoSubscribe: true,
21541
+ disableIceLite: false,
21190
21542
  maxRetries: 1,
21191
21543
  peerConnectionTimeout: 15000,
21192
21544
  websocketTimeout: 15000
@@ -21400,7 +21752,9 @@ class PCTransportManager {
21400
21752
  try {
21401
21753
  if (this.isPublisherConnectionRequired && this.publisher.getConnectionState() !== 'connected' && this.publisher.getConnectionState() !== 'connecting') {
21402
21754
  this.log.debug('negotiation required, start negotiating');
21403
- this.publisher.negotiate();
21755
+ this.publisher.negotiate().catch(err => {
21756
+ this.log.error(err);
21757
+ });
21404
21758
  }
21405
21759
  yield Promise.all((_a = this.requiredTransports) === null || _a === void 0 ? void 0 : _a.map(transport => this.ensureTransportConnected(transport, abortController, timeout)));
21406
21760
  } finally {
@@ -22438,21 +22792,29 @@ class LocalTrack extends Track {
22438
22792
  var _this = this;
22439
22793
  let timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_DIMENSIONS_TIMEOUT;
22440
22794
  return function* () {
22441
- var _a;
22442
22795
  if (_this.kind === Track.Kind.Audio) {
22443
22796
  throw new Error('cannot get dimensions for audio tracks');
22444
22797
  }
22445
- if (((_a = getBrowser()) === null || _a === void 0 ? void 0 : _a.os) === 'iOS') {
22446
- // browsers report wrong initial resolution on iOS.
22447
- // when slightly delaying the call to .getSettings(), the correct resolution is being reported
22448
- yield sleep(10);
22449
- }
22450
22798
  const started = Date.now();
22451
- while (Date.now() - started < timeout) {
22799
+ if (isAppleMobile()) {
22800
+ // iOS and iPadOS keep reporting the camera's sensor frame from getSettings() until the
22801
+ // camera has delivered its first picture, so a portrait capture initially reads as
22802
+ // landscape. Wait for that first frame instead of guessing at a delay.
22803
+ // Gated to the Apple capture pipeline rather than run everywhere: elsewhere getSettings() is
22804
+ // already right and the first frame can be hundreds of milliseconds out (measured ~500ms on
22805
+ // macOS Safari), which would be pure added publish latency.
22806
+ // https://github.com/livekit/client-sdk-js/issues/2099
22807
+ // https://github.com/livekit/client-sdk-js/issues/2107
22808
+ yield waitForFirstVideoFrame(_this._mediaStreamTrack, timeout, _this.attachedElements);
22809
+ }
22810
+ while (true) {
22452
22811
  const dims = _this.dimensions;
22453
22812
  if (dims) {
22454
22813
  return dims;
22455
22814
  }
22815
+ if (Date.now() - started >= timeout) {
22816
+ break;
22817
+ }
22456
22818
  yield sleep(50);
22457
22819
  }
22458
22820
  throw new TrackInvalidError('unable to get track dimensions after timeout');
@@ -23155,24 +23517,6 @@ const computeDefaultScreenShareSimulcastPresets = fromPreset => {
23155
23517
  return new VideoPreset(Math.floor(fromPreset.width / t.scaleResolutionDownBy), Math.floor(fromPreset.height / t.scaleResolutionDownBy), Math.max(150000, Math.floor(fromPreset.encoding.maxBitrate / (Math.pow(t.scaleResolutionDownBy, 2) * (((_a = fromPreset.encoding.maxFramerate) !== null && _a !== void 0 ? _a : 30) / ((_b = t.fps) !== null && _b !== void 0 ? _b : 30))))), t.fps, fromPreset.encoding.priority);
23156
23518
  });
23157
23519
  };
23158
- // /**
23159
- // *
23160
- // * @internal
23161
- // * @experimental
23162
- // */
23163
- // const computeDefaultMultiCodecSimulcastEncodings = (width: number, height: number) => {
23164
- // // use vp8 as a default
23165
- // const vp8 = determineAppropriateEncoding(false, width, height);
23166
- // const vp9 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.9 };
23167
- // const h264 = { ...vp8, maxBitrate: vp8.maxBitrate * 1.1 };
23168
- // const av1 = { ...vp8, maxBitrate: vp8.maxBitrate * 0.7 };
23169
- // return {
23170
- // vp8,
23171
- // vp9,
23172
- // h264,
23173
- // av1,
23174
- // };
23175
- // };
23176
23520
  const videoRids = ['q', 'h', 'f'];
23177
23521
  /* @internal */
23178
23522
  function computeVideoEncodings(isScreenShare, width, height, options) {
@@ -24027,12 +24371,20 @@ class LocalVideoTrack extends LocalTrack {
24027
24371
  // browser will reenable disabled codec/layers after new codec has been published,
24028
24372
  // so refresh subscribedCodecs after publish a new codec
24029
24373
  setTimeout(() => {
24030
- if (this.subscribedCodecs) {
24031
- this.setPublishingCodecs(this.subscribedCodecs);
24032
- }
24374
+ this.refreshSubscribedCodecs();
24033
24375
  }, refreshSubscribedCodecAfterNewCodec);
24034
24376
  });
24035
24377
  }
24378
+ /** @interal */
24379
+ refreshSubscribedCodecs() {
24380
+ return __awaiter(this, void 0, void 0, function* () {
24381
+ if (this.subscribedCodecs) {
24382
+ return this.setPublishingCodecs(this.subscribedCodecs).catch(e => this.log.warn("failed to refresh codec for track", Object.assign(Object.assign({}, this.logContext), {
24383
+ error: e
24384
+ })));
24385
+ }
24386
+ });
24387
+ }
24036
24388
  /**
24037
24389
  * @internal
24038
24390
  * Sets codecs that should be publishing, returns new codecs that have not yet
@@ -24377,6 +24729,13 @@ class RTCEngine extends eventsExports.EventEmitter {
24377
24729
  this.midToTrackId = {};
24378
24730
  /** used to indicate whether the browser is currently waiting to reconnect */
24379
24731
  this.isWaitingForNetworkReconnect = false;
24732
+ /**
24733
+ * Abort handlers for the in-flight `negotiate()` calls, which a single central
24734
+ * Closing/Restarting listener pair fans out to. Registering a listener pair per call instead
24735
+ * accumulates them on the engine emitter and trips its max-listener warning under
24736
+ * renegotiation bursts.
24737
+ */
24738
+ this.pendingNegotiationAborts = new Set();
24380
24739
  this.handleDataChannel = _a => __awaiter(this, [_a], void 0, function (_ref) {
24381
24740
  var _this = this;
24382
24741
  let channel = _ref.channel;
@@ -24622,6 +24981,14 @@ class RTCEngine extends eventsExports.EventEmitter {
24622
24981
  this.client.onRequestResponse = response => this.emit(EngineEvent.SignalRequestResponse, response);
24623
24982
  this.client.onParticipantUpdate = updates => this.emit(EngineEvent.ParticipantUpdate, updates);
24624
24983
  this.client.onJoined = joinResponse => this.emit(EngineEvent.Joined, joinResponse);
24984
+ const abortPendingNegotiations = () => {
24985
+ // Iterate a copy: each handler removes itself from the set as its negotiation settles.
24986
+ for (const abort of Array.from(this.pendingNegotiationAborts)) {
24987
+ abort();
24988
+ }
24989
+ };
24990
+ this.on(EngineEvent.Closing, abortPendingNegotiations);
24991
+ this.on(EngineEvent.Restarting, abortPendingNegotiations);
24625
24992
  }
24626
24993
  /** @internal */
24627
24994
  get logContext() {
@@ -24944,6 +25311,7 @@ class RTCEngine extends eventsExports.EventEmitter {
24944
25311
  this.midToTrackId = midToTrackId;
24945
25312
  }
24946
25313
  yield this.pcManager.setPublisherAnswer(sd, offerId);
25314
+ this.emit(EngineEvent.RequestSubscribedCodecRefresh);
24947
25315
  });
24948
25316
  // add candidate on trickle
24949
25317
  this.client.onTrickle = (candidate, target) => {
@@ -25010,7 +25378,9 @@ class RTCEngine extends eventsExports.EventEmitter {
25010
25378
  };
25011
25379
  this.client.onMediaSectionsRequirement = requirement => {
25012
25380
  this.addMediaSections(requirement.numAudios, requirement.numVideos);
25013
- this.negotiate();
25381
+ this.negotiate().catch(err => {
25382
+ this.log.error(err);
25383
+ });
25014
25384
  };
25015
25385
  this.client.onPublishDataTrackResponse = event => {
25016
25386
  this.emit(EngineEvent.PublishDataTrackResponse, event);
@@ -25763,8 +26133,7 @@ class RTCEngine extends eventsExports.EventEmitter {
25763
26133
  if (this.isClosed) {
25764
26134
  reject(new NegotiationError('cannot negotiate on closed engine'));
25765
26135
  }
25766
- this.on(EngineEvent.Closing, handleClosed);
25767
- this.on(EngineEvent.Restarting, handleClosed);
26136
+ this.pendingNegotiationAborts.add(handleClosed);
25768
26137
  this.pcManager.publisher.off(PCEvents.RTPVideoPayloadTypes, this.onRtpMapAvailable);
25769
26138
  this.pcManager.publisher.once(PCEvents.RTPVideoPayloadTypes, this.onRtpMapAvailable);
25770
26139
  try {
@@ -25787,8 +26156,7 @@ class RTCEngine extends eventsExports.EventEmitter {
25787
26156
  reject(new Error(String(e)));
25788
26157
  }
25789
26158
  } finally {
25790
- this.off(EngineEvent.Closing, handleClosed);
25791
- this.off(EngineEvent.Restarting, handleClosed);
26159
+ this.pendingNegotiationAborts.delete(handleClosed);
25792
26160
  }
25793
26161
  }));
25794
26162
  });
@@ -26589,10 +26957,10 @@ class TextStreamReader extends BaseStreamReader {
26589
26957
  let compressed;
26590
26958
  switch (streamHeader.compression) {
26591
26959
  case DataStream_CompressionType.DEFLATE_RAW:
26592
- if (!isCompressionStreamSupported()) {
26960
+ if (!isDeflateRawCompressionSupported()) {
26593
26961
  // NOTE: this shouldn't really ever happen, if this warning is logged then the sender
26594
26962
  // isn't properly abiding by the data streams v2 protocol.
26595
- livekitLogger.warn("Data stream ".concat(streamHeader.streamId, " received with deflate-raw compression, but this browser does not have support for DecompressionStream. Dropping..."));
26963
+ livekitLogger.warn("Data stream ".concat(streamHeader.streamId, " received with deflate-raw compression, but this browser does not support deflate-raw decompression. Dropping..."));
26596
26964
  return;
26597
26965
  }
26598
26966
  compressed = true;
@@ -26660,10 +27028,10 @@ class TextStreamReader extends BaseStreamReader {
26660
27028
  let compressed;
26661
27029
  switch (streamHeader.compression) {
26662
27030
  case DataStream_CompressionType.DEFLATE_RAW:
26663
- if (!isCompressionStreamSupported()) {
27031
+ if (!isDeflateRawCompressionSupported()) {
26664
27032
  // NOTE: this shouldn't really ever happen, if this warning is logged then the sender
26665
27033
  // isn't properly abiding by the data streams v2 protocol.
26666
- livekitLogger.warn("Data stream ".concat(streamHeader.streamId, " received with deflate-raw compression, but this browser does not have support for DecompressionStream. Dropping..."));
27034
+ livekitLogger.warn("Data stream ".concat(streamHeader.streamId, " received with deflate-raw compression, but this browser does not support deflate-raw decompression. Dropping..."));
26667
27035
  return;
26668
27036
  }
26669
27037
  compressed = true;
@@ -27028,7 +27396,7 @@ class OutgoingDataStreamManager {
27028
27396
  attributes: options === null || options === void 0 ? void 0 : options.attributes,
27029
27397
  encryptionType: ((_c = this.engine.e2eeManager) === null || _c === void 0 ? void 0 : _c.isDataChannelEncryptionEnabled) ? Encryption_Type.GCM : Encryption_Type.NONE
27030
27398
  };
27031
- const compressEligible = compress && isCompressionStreamSupported() && this.allRecipientsSupportV2(options === null || options === void 0 ? void 0 : options.destinationIdentities) && this.allRecipientsSupportCompression(options === null || options === void 0 ? void 0 : options.destinationIdentities);
27399
+ const compressEligible = compress && isDeflateRawCompressionSupported() && this.allRecipientsSupportV2(options === null || options === void 0 ? void 0 : options.destinationIdentities) && this.allRecipientsSupportCompression(options === null || options === void 0 ? void 0 : options.destinationIdentities);
27032
27400
  let compressedStream = compressEligible ? MaybeCollectedStream.fromStream(readableFromBytes(textInBytes).pipeThrough(deflateRawTransform())) : null;
27033
27401
  // Phase 1: Try to send as a single packet data stream
27034
27402
  const noAttachments = !(options === null || options === void 0 ? void 0 : options.attachments) || options.attachments.length === 0;
@@ -27137,7 +27505,7 @@ class OutgoingDataStreamManager {
27137
27505
  encryptionType: ((_e = this.engine.e2eeManager) === null || _e === void 0 ? void 0 : _e.isDataChannelEncryptionEnabled) ? Encryption_Type.GCM : Encryption_Type.NONE
27138
27506
  };
27139
27507
  const progressMonitorTap = progressReportingStream(bytes.length, options === null || options === void 0 ? void 0 : options.onProgress);
27140
- const compressEligible = compress && isCompressionStreamSupported() && this.allRecipientsSupportV2(destinationIdentities) && this.allRecipientsSupportCompression(destinationIdentities);
27508
+ const compressEligible = compress && isDeflateRawCompressionSupported() && this.allRecipientsSupportV2(destinationIdentities) && this.allRecipientsSupportCompression(destinationIdentities);
27141
27509
  let compressedStream = compressEligible ? MaybeCollectedStream.fromStream(readableFromBytes(bytes).pipeThrough(progressMonitorTap).pipeThrough(deflateRawTransform())) : null;
27142
27510
  // Phase 1: Try to send as a single packet data stream
27143
27511
  if (this.allRecipientsSupportV2(destinationIdentities)) {
@@ -27334,7 +27702,7 @@ class OutgoingDataStreamManager {
27334
27702
  return __awaiter(this, void 0, void 0, function* () {
27335
27703
  var _a, _b, _c, _d, _e;
27336
27704
  const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
27337
- const compress = ((_a = options === null || options === void 0 ? void 0 : options.compress) !== null && _a !== void 0 ? _a : true) && isCompressionStreamSupported() && this.allRecipientsSupportV2(destinationIdentities) && this.allRecipientsSupportCompression(destinationIdentities);
27705
+ const compress = ((_a = options === null || options === void 0 ? void 0 : options.compress) !== null && _a !== void 0 ? _a : true) && isDeflateRawCompressionSupported() && this.allRecipientsSupportV2(destinationIdentities) && this.allRecipientsSupportCompression(destinationIdentities);
27338
27706
  const info = {
27339
27707
  id: streamId,
27340
27708
  name: file.name,
@@ -30005,20 +30373,37 @@ class RpcClientManager extends eventsExports.EventEmitter {
30005
30373
  completionFuture,
30006
30374
  participantIdentity: destinationIdentity
30007
30375
  });
30008
- yield _this.publishRpcRequest(destinationIdentity, id, method, payload, effectiveTimeoutMs, remoteClientProtocol);
30009
- responseTimeoutId = setTimeout(() => {
30010
- var _a;
30011
- _this.pendingResponses.delete(id);
30012
- (_a = completionFuture.reject) === null || _a === void 0 ? void 0 : _a.call(completionFuture, RpcError.builtIn('RESPONSE_TIMEOUT'));
30013
- }, responseTimeoutMs);
30376
+ // Observe the future before publishing: a slow send can outlast the ack timer.
30377
+ // Keep the returned promise rejected for callers, while marking its rejection
30378
+ // handled until performRpc has finished publishing and can return it.
30014
30379
  const completionPromise = completionFuture.promise.finally(() => {
30015
- clearTimeout(responseTimeoutId);
30380
+ if (responseTimeoutId !== null) {
30381
+ clearTimeout(responseTimeoutId);
30382
+ }
30016
30383
  if (_this.pendingAcks.has(id)) {
30017
30384
  _this.log.warn('RPC response received before ack', id);
30018
30385
  _this.pendingAcks.delete(id);
30019
30386
  clearTimeout(ackTimeoutId);
30020
30387
  }
30021
30388
  });
30389
+ completionPromise.catch(() => {});
30390
+ try {
30391
+ yield _this.publishRpcRequest(destinationIdentity, id, method, payload, effectiveTimeoutMs, remoteClientProtocol);
30392
+ } catch (e) {
30393
+ // The caller receives the publish error. Do not leave an ack timer that
30394
+ // later rejects a future the caller never received.
30395
+ clearTimeout(ackTimeoutId);
30396
+ _this.pendingAcks.delete(id);
30397
+ _this.pendingResponses.delete(id);
30398
+ throw e;
30399
+ }
30400
+ if (_this.pendingResponses.has(id)) {
30401
+ responseTimeoutId = setTimeout(() => {
30402
+ var _a;
30403
+ _this.pendingResponses.delete(id);
30404
+ (_a = completionFuture.reject) === null || _a === void 0 ? void 0 : _a.call(completionFuture, RpcError.builtIn('RESPONSE_TIMEOUT'));
30405
+ }, responseTimeoutMs);
30406
+ }
30022
30407
  return [id, completionPromise];
30023
30408
  }();
30024
30409
  });
@@ -30371,7 +30756,7 @@ class RpcServerManager extends eventsExports.EventEmitter {
30371
30756
  * gets the volume of attached audio elements (loudest)
30372
30757
  */
30373
30758
  getVolume() {
30374
- if (this.elementVolume) {
30759
+ if (this.elementVolume !== undefined) {
30375
30760
  return this.elementVolume;
30376
30761
  }
30377
30762
  if (isReactNative()) {
@@ -30420,7 +30805,7 @@ class RpcServerManager extends eventsExports.EventEmitter {
30420
30805
  element.volume = 0;
30421
30806
  element.muted = true;
30422
30807
  }
30423
- if (this.elementVolume) {
30808
+ if (this.elementVolume !== undefined) {
30424
30809
  // make sure volume setting is being applied to the newly attached element
30425
30810
  this.setVolume(this.elementVolume);
30426
30811
  }
@@ -30480,7 +30865,7 @@ class RpcServerManager extends eventsExports.EventEmitter {
30480
30865
  this.gainNode = context.createGain();
30481
30866
  lastNode.connect(this.gainNode);
30482
30867
  this.gainNode.connect(context.destination);
30483
- if (this.elementVolume) {
30868
+ if (this.elementVolume !== undefined) {
30484
30869
  this.gainNode.gain.setTargetAtTime(this.elementVolume, 0, 0.1);
30485
30870
  }
30486
30871
  // try to resume the context if it isn't running already
@@ -33731,7 +34116,7 @@ class Room extends eventsExports.EventEmitter {
33731
34116
  this.abortController = undefined;
33732
34117
  resolve();
33733
34118
  } catch (error) {
33734
- if (this.regionUrlProvider && error instanceof ConnectionError && error.reason !== ConnectionErrorReason.Cancelled && error.reason !== ConnectionErrorReason.NotAllowed) {
34119
+ if (this.regionUrlProvider && error instanceof ConnectionError && canFailOverToAnotherRegion(error)) {
33735
34120
  let nextUrl = null;
33736
34121
  try {
33737
34122
  this.log.debug('Fetching next region');
@@ -33780,6 +34165,8 @@ class Room extends eventsExports.EventEmitter {
33780
34165
  const _yield$engine$join = yield engine.join(url, token, {
33781
34166
  autoSubscribe: connectOptions.autoSubscribe,
33782
34167
  adaptiveStream: typeof roomOptions.adaptiveStream === 'object' ? true : roomOptions.adaptiveStream,
34168
+ disableIceLite: connectOptions.disableIceLite,
34169
+ subscriberAllowPause: connectOptions.subscriberAllowPause,
33783
34170
  clientInfoCapabilities: this.getClientInfoCapabilities(roomOptions),
33784
34171
  maxRetries: connectOptions.maxRetries,
33785
34172
  e2eeEnabled: !!this.e2eeManager,
@@ -34218,7 +34605,7 @@ class Room extends eventsExports.EventEmitter {
34218
34605
  // find the participant
34219
34606
  const participant = this.remoteParticipants.get(packet.participantIdentity);
34220
34607
  if (packet.value.case === 'user') {
34221
- this.handleUserPacket(participant, packet.value.value, packet.kind, encryptionType);
34608
+ this.handleUserPacket(participant, packet.value.value, packet.kind, encryptionType, packet.participantIdentity);
34222
34609
  } else if (packet.value.case === 'transcription') {
34223
34610
  this.handleTranscription(participant, packet.value.value);
34224
34611
  } else if (packet.value.case === 'sipDtmf') {
@@ -34249,8 +34636,8 @@ class Room extends eventsExports.EventEmitter {
34249
34636
  this.rpcClientManager.handleIncomingRpcAck(packet.value.value.requestId);
34250
34637
  }
34251
34638
  };
34252
- this.handleUserPacket = (participant, userPacket, kind, encryptionType) => {
34253
- this.emit(RoomEvent.DataReceived, userPacket.payload, participant, kind, userPacket.topic, encryptionType);
34639
+ this.handleUserPacket = (participant, userPacket, kind, encryptionType, participantIdentity) => {
34640
+ this.emit(RoomEvent.DataReceived, userPacket.payload, participant, kind, userPacket.topic, encryptionType, participantIdentity);
34254
34641
  // also emit on the participant
34255
34642
  participant === null || participant === void 0 ? void 0 : participant.emit(ParticipantEvent.DataReceived, userPacket.payload, kind, encryptionType);
34256
34643
  };
@@ -34825,6 +35212,12 @@ class Room extends eventsExports.EventEmitter {
34825
35212
  updatedAtInMs: Date.now(),
34826
35213
  maxAgeInMs: DEFAULT_MAX_AGE_MS
34827
35214
  });
35215
+ }).on(EngineEvent.RequestSubscribedCodecRefresh, () => {
35216
+ for (const videoPub of this.localParticipant.videoTrackPublications.values()) {
35217
+ if (isLocalVideoTrack(videoPub.track)) {
35218
+ videoPub.track.refreshSubscribedCodecs();
35219
+ }
35220
+ }
34828
35221
  });
34829
35222
  if (this.localParticipant) {
34830
35223
  this.localParticipant.setupEngine(this.engine);
@@ -34921,8 +35314,9 @@ class Room extends eventsExports.EventEmitter {
34921
35314
  let req;
34922
35315
  switch (scenario) {
34923
35316
  case 'signal-reconnect':
35317
+ const reconnectDelay = typeof arg === 'number' ? arg : 0;
34924
35318
  // @ts-expect-error function is private
34925
- yield this.engine.client.handleOnClose('simulate disconnect');
35319
+ yield this.engine.client.handleOnClose('simulate disconnect', undefined, reconnectDelay);
34926
35320
  break;
34927
35321
  case 'fail-on-v1-path':
34928
35322
  this.engine.failNextV1Path();
@@ -35603,7 +35997,7 @@ class Room extends eventsExports.EventEmitter {
35603
35997
  }
35604
35998
  // Advertise deflate-raw decompression support so peers know they can send us compressed data
35605
35999
  // streams (gated separately from clientProtocol — see the data streams v2 spec).
35606
- if (isCompressionStreamSupported()) {
36000
+ if (isDeflateRawCompressionSupported()) {
35607
36001
  capabilities.push(ClientInfo_Capability.CAP_COMPRESSION_DEFLATE_RAW);
35608
36002
  }
35609
36003
  return capabilities;
@@ -36653,225 +37047,186 @@ class TokenSourceFixed {}
36653
37047
  * and {@link TokenSourceCustom}.
36654
37048
  */
36655
37049
  class TokenSourceConfigurable {}new TextEncoder();
36656
- const decoder = new TextDecoder();
36657
- const strictDecoder = new TextDecoder('utf-8', {
36658
- fatal: true
36659
- });class JOSEError extends Error {
37050
+ const decoder = new TextDecoder(),
37051
+ strictDecoder = new TextDecoder("utf-8", {
37052
+ fatal: true
37053
+ });
37054
+ function decodeBase64(encoded) {
37055
+ let url = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
37056
+ if (Uint8Array.fromBase64) return Uint8Array.fromBase64(encoded, {
37057
+ alphabet: url ? "base64url" : "base64"
37058
+ });
37059
+ if (url) {
37060
+ if (encoded.includes("+") || encoded.includes("/")) throw new TypeError("Invalid base64url");
37061
+ encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
37062
+ }
37063
+ const binary = atob(encoded),
37064
+ bytes = new Uint8Array(binary.length);
37065
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
37066
+ return bytes;
37067
+ }class JOSEError extends Error {
36660
37068
  constructor(message, options) {
36661
37069
  var _Error$captureStackTr;
36662
- super(message, options);
36663
- _defineProperty(this, "code", 'ERR_JOSE_GENERIC');
36664
- this.name = this.constructor.name;
36665
- (_Error$captureStackTr = Error.captureStackTrace) === null || _Error$captureStackTr === void 0 || _Error$captureStackTr.call(Error, this, this.constructor);
37070
+ super(message, options), _defineProperty(this, "code", "ERR_JOSE_GENERIC"), this.name = this.constructor.name, (_Error$captureStackTr = Error.captureStackTrace) === null || _Error$captureStackTr === void 0 ? void 0 : _Error$captureStackTr.call(Error, this, this.constructor);
36666
37071
  }
36667
37072
  }
36668
- _defineProperty(JOSEError, "code", 'ERR_JOSE_GENERIC');
37073
+ _defineProperty(JOSEError, "code", "ERR_JOSE_GENERIC");
36669
37074
  class JWTClaimValidationFailed extends JOSEError {
36670
37075
  constructor(message, payload) {
36671
- let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unspecified';
36672
- let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'unspecified';
37076
+ let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unspecified";
37077
+ let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "unspecified";
36673
37078
  super(message, {
36674
37079
  cause: {
36675
37080
  claim,
36676
37081
  reason,
36677
37082
  payload
36678
37083
  }
36679
- });
36680
- _defineProperty(this, "code", 'ERR_JWT_CLAIM_VALIDATION_FAILED');
36681
- _defineProperty(this, "claim", void 0);
36682
- _defineProperty(this, "reason", void 0);
36683
- _defineProperty(this, "payload", void 0);
36684
- this.claim = claim;
36685
- this.reason = reason;
36686
- this.payload = payload;
37084
+ }), _defineProperty(this, "code", "ERR_JWT_CLAIM_VALIDATION_FAILED"), _defineProperty(this, "claim", void 0), _defineProperty(this, "reason", void 0), _defineProperty(this, "payload", void 0), this.claim = claim, this.reason = reason, this.payload = payload;
36687
37085
  }
36688
37086
  }
36689
- _defineProperty(JWTClaimValidationFailed, "code", 'ERR_JWT_CLAIM_VALIDATION_FAILED');
37087
+ _defineProperty(JWTClaimValidationFailed, "code", "ERR_JWT_CLAIM_VALIDATION_FAILED");
36690
37088
  class JWTExpired extends JOSEError {
36691
37089
  constructor(message, payload) {
36692
- let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'unspecified';
36693
- let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'unspecified';
37090
+ let claim = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "unspecified";
37091
+ let reason = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "unspecified";
36694
37092
  super(message, {
36695
37093
  cause: {
36696
37094
  claim,
36697
37095
  reason,
36698
37096
  payload
36699
37097
  }
36700
- });
36701
- _defineProperty(this, "code", 'ERR_JWT_EXPIRED');
36702
- _defineProperty(this, "claim", void 0);
36703
- _defineProperty(this, "reason", void 0);
36704
- _defineProperty(this, "payload", void 0);
36705
- this.claim = claim;
36706
- this.reason = reason;
36707
- this.payload = payload;
37098
+ }), _defineProperty(this, "code", "ERR_JWT_EXPIRED"), _defineProperty(this, "claim", void 0), _defineProperty(this, "reason", void 0), _defineProperty(this, "payload", void 0), this.claim = claim, this.reason = reason, this.payload = payload;
36708
37099
  }
36709
37100
  }
36710
- _defineProperty(JWTExpired, "code", 'ERR_JWT_EXPIRED');
37101
+ _defineProperty(JWTExpired, "code", "ERR_JWT_EXPIRED");
36711
37102
  class JOSEAlgNotAllowed extends JOSEError {
36712
37103
  constructor() {
36713
37104
  super(...arguments);
36714
- _defineProperty(this, "code", 'ERR_JOSE_ALG_NOT_ALLOWED');
37105
+ _defineProperty(this, "code", "ERR_JOSE_ALG_NOT_ALLOWED");
36715
37106
  }
36716
37107
  }
36717
- _defineProperty(JOSEAlgNotAllowed, "code", 'ERR_JOSE_ALG_NOT_ALLOWED');
37108
+ _defineProperty(JOSEAlgNotAllowed, "code", "ERR_JOSE_ALG_NOT_ALLOWED");
36718
37109
  class JOSENotSupported extends JOSEError {
36719
37110
  constructor() {
36720
37111
  super(...arguments);
36721
- _defineProperty(this, "code", 'ERR_JOSE_NOT_SUPPORTED');
37112
+ _defineProperty(this, "code", "ERR_JOSE_NOT_SUPPORTED");
36722
37113
  }
36723
37114
  }
36724
- _defineProperty(JOSENotSupported, "code", 'ERR_JOSE_NOT_SUPPORTED');
37115
+ _defineProperty(JOSENotSupported, "code", "ERR_JOSE_NOT_SUPPORTED");
36725
37116
  class JWEDecryptionFailed extends JOSEError {
36726
37117
  constructor() {
36727
- let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'decryption operation failed';
37118
+ let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "decryption operation failed";
36728
37119
  let options = arguments.length > 1 ? arguments[1] : undefined;
36729
37120
  super(message, options);
36730
- _defineProperty(this, "code", 'ERR_JWE_DECRYPTION_FAILED');
37121
+ _defineProperty(this, "code", "ERR_JWE_DECRYPTION_FAILED");
36731
37122
  }
36732
37123
  }
36733
- _defineProperty(JWEDecryptionFailed, "code", 'ERR_JWE_DECRYPTION_FAILED');
37124
+ _defineProperty(JWEDecryptionFailed, "code", "ERR_JWE_DECRYPTION_FAILED");
36734
37125
  class JWEInvalid extends JOSEError {
36735
37126
  constructor() {
36736
37127
  super(...arguments);
36737
- _defineProperty(this, "code", 'ERR_JWE_INVALID');
37128
+ _defineProperty(this, "code", "ERR_JWE_INVALID");
36738
37129
  }
36739
37130
  }
36740
- _defineProperty(JWEInvalid, "code", 'ERR_JWE_INVALID');
37131
+ _defineProperty(JWEInvalid, "code", "ERR_JWE_INVALID");
36741
37132
  class JWSInvalid extends JOSEError {
36742
37133
  constructor() {
36743
37134
  super(...arguments);
36744
- _defineProperty(this, "code", 'ERR_JWS_INVALID');
37135
+ _defineProperty(this, "code", "ERR_JWS_INVALID");
36745
37136
  }
36746
37137
  }
36747
- _defineProperty(JWSInvalid, "code", 'ERR_JWS_INVALID');
37138
+ _defineProperty(JWSInvalid, "code", "ERR_JWS_INVALID");
36748
37139
  class JWTInvalid extends JOSEError {
36749
37140
  constructor() {
36750
37141
  super(...arguments);
36751
- _defineProperty(this, "code", 'ERR_JWT_INVALID');
37142
+ _defineProperty(this, "code", "ERR_JWT_INVALID");
36752
37143
  }
36753
37144
  }
36754
- _defineProperty(JWTInvalid, "code", 'ERR_JWT_INVALID');
37145
+ _defineProperty(JWTInvalid, "code", "ERR_JWT_INVALID");
36755
37146
  class JWKInvalid extends JOSEError {
36756
37147
  constructor() {
36757
37148
  super(...arguments);
36758
- _defineProperty(this, "code", 'ERR_JWK_INVALID');
37149
+ _defineProperty(this, "code", "ERR_JWK_INVALID");
36759
37150
  }
36760
37151
  }
36761
- _defineProperty(JWKInvalid, "code", 'ERR_JWK_INVALID');
37152
+ _defineProperty(JWKInvalid, "code", "ERR_JWK_INVALID");
36762
37153
  class JWKSInvalid extends JOSEError {
36763
37154
  constructor() {
36764
37155
  super(...arguments);
36765
- _defineProperty(this, "code", 'ERR_JWKS_INVALID');
37156
+ _defineProperty(this, "code", "ERR_JWKS_INVALID");
36766
37157
  }
36767
37158
  }
36768
- _defineProperty(JWKSInvalid, "code", 'ERR_JWKS_INVALID');
37159
+ _defineProperty(JWKSInvalid, "code", "ERR_JWKS_INVALID");
36769
37160
  class JWKSNoMatchingKey extends JOSEError {
36770
37161
  constructor() {
36771
- let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'no applicable key found in the JSON Web Key Set';
37162
+ let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "no applicable key found in the JSON Web Key Set";
36772
37163
  let options = arguments.length > 1 ? arguments[1] : undefined;
36773
37164
  super(message, options);
36774
- _defineProperty(this, "code", 'ERR_JWKS_NO_MATCHING_KEY');
37165
+ _defineProperty(this, "code", "ERR_JWKS_NO_MATCHING_KEY");
36775
37166
  }
36776
37167
  }
36777
- _defineProperty(JWKSNoMatchingKey, "code", 'ERR_JWKS_NO_MATCHING_KEY');
37168
+ _defineProperty(JWKSNoMatchingKey, "code", "ERR_JWKS_NO_MATCHING_KEY");
36778
37169
  class JWKSMultipleMatchingKeys extends JOSEError {
36779
37170
  constructor() {
36780
- let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'multiple matching keys found in the JSON Web Key Set';
37171
+ let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "multiple matching keys found in the JSON Web Key Set";
36781
37172
  let options = arguments.length > 1 ? arguments[1] : undefined;
36782
37173
  super(message, options);
36783
37174
  _defineProperty(this, Symbol.asyncIterator, _wrapAsyncGenerator(function* () {}));
36784
- _defineProperty(this, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
37175
+ _defineProperty(this, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
36785
37176
  }
36786
37177
  }
36787
- _defineProperty(JWKSMultipleMatchingKeys, "code", 'ERR_JWKS_MULTIPLE_MATCHING_KEYS');
37178
+ _defineProperty(JWKSMultipleMatchingKeys, "code", "ERR_JWKS_MULTIPLE_MATCHING_KEYS");
36788
37179
  class JWKSTimeout extends JOSEError {
36789
37180
  constructor() {
36790
- let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'request timed out';
37181
+ let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "request timed out";
36791
37182
  let options = arguments.length > 1 ? arguments[1] : undefined;
36792
37183
  super(message, options);
36793
- _defineProperty(this, "code", 'ERR_JWKS_TIMEOUT');
37184
+ _defineProperty(this, "code", "ERR_JWKS_TIMEOUT");
36794
37185
  }
36795
37186
  }
36796
- _defineProperty(JWKSTimeout, "code", 'ERR_JWKS_TIMEOUT');
37187
+ _defineProperty(JWKSTimeout, "code", "ERR_JWKS_TIMEOUT");
36797
37188
  class JWSSignatureVerificationFailed extends JOSEError {
36798
37189
  constructor() {
36799
- let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'signature verification failed';
37190
+ let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "signature verification failed";
36800
37191
  let options = arguments.length > 1 ? arguments[1] : undefined;
36801
37192
  super(message, options);
36802
- _defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
37193
+ _defineProperty(this, "code", "ERR_JWS_SIGNATURE_VERIFICATION_FAILED");
36803
37194
  }
36804
37195
  }
36805
- _defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');function decodeBase64(encoded) {
36806
- if (Uint8Array.fromBase64) {
36807
- return Uint8Array.fromBase64(encoded);
36808
- }
36809
- const binary = atob(encoded);
36810
- const bytes = new Uint8Array(binary.length);
36811
- for (let i = 0; i < binary.length; i++) {
36812
- bytes[i] = binary.charCodeAt(i);
36813
- }
36814
- return bytes;
36815
- }const invalid = 'The input to be decoded is not correctly encoded.';
37196
+ _defineProperty(JWSSignatureVerificationFailed, "code", "ERR_JWS_SIGNATURE_VERIFICATION_FAILED");const invalid = "The input to be decoded is not correctly encoded.";
36816
37197
  function decode(input) {
36817
- if (Uint8Array.fromBase64) {
36818
- try {
36819
- return Uint8Array.fromBase64(typeof input === 'string' ? input : decoder.decode(input), {
36820
- alphabet: 'base64url'
36821
- });
36822
- } catch (cause) {
36823
- throw new TypeError(invalid, {
36824
- cause
36825
- });
36826
- }
36827
- }
36828
- let encoded = input;
36829
- if (encoded instanceof Uint8Array) {
36830
- encoded = decoder.decode(encoded);
36831
- }
36832
- if (encoded.includes('+') || encoded.includes('/')) {
36833
- throw new TypeError(invalid);
36834
- }
36835
- encoded = encoded.replace(/-/g, '+').replace(/_/g, '/');
36836
37198
  try {
36837
- return decodeBase64(encoded);
36838
- } catch (_unused) {
36839
- throw new TypeError(invalid);
37199
+ return decodeBase64(typeof input == "string" ? input : decoder.decode(input), !0);
37200
+ } catch (cause) {
37201
+ throw new TypeError(invalid, {
37202
+ cause
37203
+ });
36840
37204
  }
36841
37205
  }function isObject(input) {
36842
- if (typeof input !== 'object' || input === null || Object.prototype.toString.call(input) !== '[object Object]') {
36843
- return false;
36844
- }
37206
+ if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]") return false;
36845
37207
  const prototype = Object.getPrototypeOf(input);
36846
- if (prototype === null) {
36847
- return true;
36848
- }
36849
- let proto = prototype;
36850
- while (Object.getPrototypeOf(proto) !== null) {
36851
- proto = Object.getPrototypeOf(proto);
36852
- }
36853
- return prototype === proto;
37208
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
36854
37209
  }function decodeJwt(jwt) {
36855
- if (typeof jwt !== 'string') throw new JWTInvalid('JWTs must use Compact JWS serialization, JWT must be a string');
36856
- const _jwt$split = jwt.split('.'),
37210
+ if (typeof jwt != "string") throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
37211
+ const _jwt$split = jwt.split("."),
36857
37212
  payload = _jwt$split[1],
36858
37213
  length = _jwt$split.length;
36859
- if (length === 5) throw new JWTInvalid('Only JWTs using Compact JWS serialization can be decoded');
36860
- if (length !== 3) throw new JWTInvalid('Invalid JWT');
36861
- if (!payload) throw new JWTInvalid('JWTs must contain a payload');
37214
+ if (length === 5) throw new JWTInvalid("Only JWTs using Compact JWS serialization can be decoded");
37215
+ if (length !== 3) throw new JWTInvalid("Invalid JWT");
37216
+ if (!payload) throw new JWTInvalid("JWTs must contain a payload");
36862
37217
  let decoded;
36863
37218
  try {
36864
37219
  decoded = decode(payload);
36865
37220
  } catch (_unused) {
36866
- throw new JWTInvalid('Failed to base64url decode the payload');
37221
+ throw new JWTInvalid("Failed to base64url decode the payload");
36867
37222
  }
36868
37223
  let result;
36869
37224
  try {
36870
37225
  result = JSON.parse(strictDecoder.decode(decoded));
36871
37226
  } catch (_unused2) {
36872
- throw new JWTInvalid('Failed to parse the decoded payload as JSON');
37227
+ throw new JWTInvalid("Failed to parse the decoded payload as JSON");
36873
37228
  }
36874
- if (!isObject(result)) throw new JWTInvalid('Invalid JWT Claims Set');
37229
+ if (!isObject(result)) throw new JWTInvalid("Invalid JWT Claims Set");
36875
37230
  return result;
36876
37231
  }const ONE_SECOND_IN_MILLISECONDS = 1000;
36877
37232
  const ONE_MINUTE_IN_MILLISECONDS = 60 * ONE_SECOND_IN_MILLISECONDS;
@@ -37279,4 +37634,4 @@ const serializers = {
37279
37634
  json,
37280
37635
  raw,
37281
37636
  custom
37282
- };export{AudioPresets,BackupCodecPolicy,BaseKeyProvider,CLIENT_PROTOCOL_DATA_STREAM_RPC,CLIENT_PROTOCOL_DATA_STREAM_V2,CLIENT_PROTOCOL_DEFAULT,CheckStatus,Checker,ConnectionCheck,ConnectionError,ConnectionErrorReason,ConnectionQuality,ConnectionState,CriticalTimers,CryptorError,CryptorErrorReason,CryptorEvent,DataPacket_Kind,DataStreamError,DataStreamErrorReason,DataTrackPacket,DefaultReconnectPolicy,DeviceUnsupportedError,DisconnectReason,EncryptionEvent,Encryption_Type,EngineEvent,ExternalE2EEKeyProvider,FrameMetadataManager,KeyHandlerEvent,KeyProviderEvent,LivekitError,LivekitReasonedError,LocalAudioTrack,LocalDataTrack,LocalParticipant,LocalTrack,LocalTrackPublication,LocalTrackRecorder,LocalVideoTrack,LogLevel,LoggerNames,MediaDeviceFailure,_ as Mutex,NegotiationError,PacketTrailerManager,Participant,ParticipantEvent,ParticipantInfo_Kind as ParticipantKind,PublishDataError,PublishTrackError,RemoteAudioTrack,RemoteDataTrack,RemoteParticipant,RemoteTrack,RemoteTrackPublication,RemoteVideoTrack,Room,RoomEvent,RpcError,ScreenSharePresets,SignalReconnectError,SignalRequestError,SimulatedError,SubscriptionError,TokenSource,TokenSourceConfigurable,TokenSourceFixed,Track,TrackEvent,TrackInvalidError,TrackPublication,TrackType,UnexpectedConnectionState,UnsupportedServer,VideoPreset,VideoPresets,VideoPresets43,VideoQuality,areTokenSourceFetchOptionsEqual,asEncryptablePacket,attachToElement,attributeTypings as attributes,audioCodecs,clientProtocol,compareVersions,createAudioAnalyser,createE2EEKey,createKeyMaterialFromBuffer,createKeyMaterialFromString,createLocalAudioTrack,createLocalScreenTracks,createLocalTracks,createLocalVideoTrack,decodeTokenPayload,deriveKeys,detachTrack,facingModeFromDeviceLabel,facingModeFromLocalTrack,getBrowser,getEmptyAudioStreamTrack,getEmptyVideoStreamTrack,getLogger,importKey,isAudioCodec,isAudioTrack,isBackupCodec,isBackupVideoCodec,isBrowserSupported,isE2EESupported,isInsertableStreamSupported,isLocalParticipant,isLocalTrack,isRemoteParticipant,isRemoteTrack,isSVCCodec,isScriptTransformSupported,isSerializer,isVideoCodec,isVideoFrame,isVideoTrack,needsRbspUnescaping,parseRbsp,protocolVersion,ratchet,serializers,setLogExtension,setLogLevel,supportsAV1,supportsAdaptiveStream,supportsAudioOutputSelection,supportsDynacast,supportsH265,supportsVP9,version,videoCodecs,writeRbsp};//# sourceMappingURL=livekit-client.esm.mjs.map
37637
+ };export{AudioPresets,BackupCodecPolicy,BaseKeyProvider,CLIENT_PROTOCOL_DATA_STREAM_RPC,CLIENT_PROTOCOL_DATA_STREAM_V2,CLIENT_PROTOCOL_DEFAULT,CheckStatus,Checker,ConnectionCheck,ConnectionError,ConnectionErrorReason,ConnectionQuality,ConnectionState,CriticalTimers,CryptorError,CryptorErrorReason,CryptorEvent,DataPacket_Kind,DataStreamError,DataStreamErrorReason,DataTrackPacket,DefaultReconnectPolicy,DeviceUnsupportedError,DisconnectReason,EncryptionEvent,Encryption_Type,EngineEvent,ExternalE2EEKeyProvider,FrameMetadataManager,KeyHandlerEvent,KeyProviderEvent,LivekitError,LivekitReasonedError,LocalAudioTrack,LocalDataTrack,LocalParticipant,LocalTrack,LocalTrackPublication,LocalTrackRecorder,LocalVideoTrack,LogLevel,LoggerNames,MediaDeviceFailure,_ as Mutex,NegotiationError,PacketTrailerManager,Participant,ParticipantEvent,ParticipantInfo_Kind as ParticipantKind,PublishDataError,PublishTrackError,RemoteAudioTrack,RemoteDataTrack,RemoteParticipant,RemoteTrack,RemoteTrackPublication,RemoteVideoTrack,Room,RoomEvent,RpcError,ScreenSharePresets,SignalReconnectError,SignalRequestError,SimulatedError,SubscriptionError,TokenSource,TokenSourceConfigurable,TokenSourceFixed,Track,TrackEvent,TrackInvalidError,TrackPublication,TrackType,UnexpectedConnectionState,UnsupportedServer,VideoPreset,VideoPresets,VideoPresets43,VideoQuality,areTokenSourceFetchOptionsEqual,asEncryptablePacket,attachToElement,attributeTypings as attributes,audioCodecs,canFailOverToAnotherRegion,clientProtocol,compareVersions,createAudioAnalyser,createE2EEKey,createKeyMaterialFromBuffer,createKeyMaterialFromString,createLocalAudioTrack,createLocalScreenTracks,createLocalTracks,createLocalVideoTrack,decodeTokenPayload,deriveKeys,detachTrack,facingModeFromDeviceLabel,facingModeFromLocalTrack,getBrowser,getEmptyAudioStreamTrack,getEmptyVideoStreamTrack,getLogger,importKey,isAudioCodec,isAudioTrack,isBackupCodec,isBackupVideoCodec,isBrowserSupported,isE2EESupported,isInsertableStreamSupported,isLocalParticipant,isLocalTrack,isRemoteParticipant,isRemoteTrack,isSVCCodec,isScriptTransformSupported,isSerializer,isVideoCodec,isVideoFrame,isVideoTrack,needsRbspUnescaping,parseRbsp,protocolVersion,ratchet,serializers,setLogExtension,setLogLevel,supportsAV1,supportsAdaptiveStream,supportsAudioOutputSelection,supportsDynacast,supportsH265,supportsVP9,version,videoCodecs,writeRbsp};//# sourceMappingURL=livekit-client.esm.mjs.map