livekit-client 2.18.3 → 2.18.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.
@@ -8704,6 +8704,11 @@ function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {
8704
8704
  if (!window.RTCPeerConnection) {
8705
8705
  return;
8706
8706
  }
8707
+ const addEventListener = Object.getOwnPropertyDescriptor(EventTarget.prototype, 'addEventListener');
8708
+ if (!addEventListener.writable) {
8709
+ log$4('Unable to polyfill events');
8710
+ return;
8711
+ }
8707
8712
  const proto = window.RTCPeerConnection.prototype;
8708
8713
  const nativeAddEventListener = proto.addEventListener;
8709
8714
  proto.addEventListener = function (nativeEventName, cb) {
@@ -8846,7 +8851,7 @@ function detectBrowser(window) {
8846
8851
  // Chrome 74 removed webkitGetUserMedia on http as well so we need the
8847
8852
  // more complicated fallback to webkitRTCPeerConnection.
8848
8853
  result.browser = 'chrome';
8849
- result.version = parseInt(extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2));
8854
+ result.version = parseInt(extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2)) || null;
8850
8855
  } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
8851
8856
  // Safari.
8852
8857
  result.browser = 'safari';
@@ -9120,7 +9125,11 @@ function shimGetUserMedia$2(window, browserDetails) {
9120
9125
  function shimMediaStream(window) {
9121
9126
  window.MediaStream = window.MediaStream || window.webkitMediaStream;
9122
9127
  }
9123
- function shimOnTrack$1(window) {
9128
+ function shimOnTrack$1(window, browserDetails) {
9129
+ if (browserDetails.version > 102) {
9130
+ // Unified plan is supported so no need to do anything.
9131
+ return;
9132
+ }
9124
9133
  if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) {
9125
9134
  Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
9126
9135
  get() {
@@ -9283,7 +9292,10 @@ function shimGetSendersWithDtmf(window) {
9283
9292
  });
9284
9293
  }
9285
9294
  }
9286
- function shimSenderReceiverGetStats(window) {
9295
+ function shimSenderReceiverGetStats(window, browserDetails) {
9296
+ if (browserDetails.version >= 67) {
9297
+ return;
9298
+ }
9287
9299
  if (!(typeof window === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) {
9288
9300
  return;
9289
9301
  }
@@ -9650,6 +9662,10 @@ function shimPeerConnection$1(window, browserDetails) {
9650
9662
 
9651
9663
  // Attempt to fix ONN in plan-b mode.
9652
9664
  function fixNegotiationNeeded(window, browserDetails) {
9665
+ if (browserDetails.version > 102) {
9666
+ // Plan-B is no longer supported.
9667
+ return;
9668
+ }
9653
9669
  wrapPeerConnectionEvent(window, 'negotiationneeded', e => {
9654
9670
  const pc = e.target;
9655
9671
  if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') {
@@ -9785,6 +9801,15 @@ function shimPeerConnection(window, browserDetails) {
9785
9801
  window.RTCPeerConnection.prototype[method] = methodObj[method];
9786
9802
  });
9787
9803
  }
9804
+ }
9805
+ function shimGetStats(window, browserDetails) {
9806
+ if (typeof window !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {
9807
+ return; // probably media.peerconnection.enabled=false in about:config
9808
+ }
9809
+ if (browserDetails.version >= 151) {
9810
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1056433
9811
+ return;
9812
+ }
9788
9813
  const modernStatsTypes = {
9789
9814
  inboundrtp: 'inbound-rtp',
9790
9815
  outboundrtp: 'outbound-rtp',
@@ -9795,6 +9820,10 @@ function shimPeerConnection(window, browserDetails) {
9795
9820
  const nativeGetStats = window.RTCPeerConnection.prototype.getStats;
9796
9821
  window.RTCPeerConnection.prototype.getStats = function getStats() {
9797
9822
  const [selector, onSucc, onErr] = arguments;
9823
+ if (this.signalingState === 'closed') {
9824
+ // No longer required in FF151+
9825
+ return Promise.resolve(new Map());
9826
+ }
9798
9827
  return nativeGetStats.apply(this, [selector || null]).then(stats => {
9799
9828
  if (browserDetails.version < 53 && !onSucc) {
9800
9829
  // Shim only promise getStats with spec-hyphens in type names
@@ -10009,7 +10038,7 @@ function shimCreateAnswer(window) {
10009
10038
  }
10010
10039
  return origCreateAnswer.apply(this, arguments);
10011
10040
  };
10012
- }var firefoxShim=/*#__PURE__*/Object.freeze({__proto__:null,shimAddTransceiver:shimAddTransceiver,shimCreateAnswer:shimCreateAnswer,shimCreateOffer:shimCreateOffer,shimGetDisplayMedia:shimGetDisplayMedia,shimGetParameters:shimGetParameters,shimGetUserMedia:shimGetUserMedia$1,shimOnTrack:shimOnTrack,shimPeerConnection:shimPeerConnection,shimRTCDataChannel:shimRTCDataChannel,shimReceiverGetStats:shimReceiverGetStats,shimRemoveStream:shimRemoveStream,shimSenderGetStats:shimSenderGetStats});/*
10041
+ }var firefoxShim=/*#__PURE__*/Object.freeze({__proto__:null,shimAddTransceiver:shimAddTransceiver,shimCreateAnswer:shimCreateAnswer,shimCreateOffer:shimCreateOffer,shimGetDisplayMedia:shimGetDisplayMedia,shimGetParameters:shimGetParameters,shimGetStats:shimGetStats,shimGetUserMedia:shimGetUserMedia$1,shimOnTrack:shimOnTrack,shimPeerConnection:shimPeerConnection,shimRTCDataChannel:shimRTCDataChannel,shimReceiverGetStats:shimReceiverGetStats,shimRemoveStream:shimRemoveStream,shimSenderGetStats:shimSenderGetStats});/*
10013
10042
  * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
10014
10043
  *
10015
10044
  * Use of this source code is governed by a BSD-style license
@@ -10444,7 +10473,7 @@ function requireSdp() {
10444
10473
  const type = candidate.type;
10445
10474
  sdp.push('typ');
10446
10475
  sdp.push(type);
10447
- if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) {
10476
+ if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort !== undefined) {
10448
10477
  sdp.push('raddr');
10449
10478
  sdp.push(candidate.relatedAddress);
10450
10479
  sdp.push('rport');
@@ -10517,6 +10546,8 @@ function requireSdp() {
10517
10546
  // Parses a fmtp line, returns dictionary. Sample input:
10518
10547
  // a=fmtp:96 vbr=on;cng=on
10519
10548
  // Also deals with vbr=on; cng=on
10549
+ // Non-key-value such as telephone-events `0-15` get parsed as
10550
+ // {`0-15`:undefined}
10520
10551
  SDPUtils.parseFmtp = function (line) {
10521
10552
  const parsed = {};
10522
10553
  let kv;
@@ -11290,15 +11321,21 @@ function shimMaxMessageSize(window, browserDetails) {
11290
11321
  return origSetRemoteDescription.apply(this, arguments);
11291
11322
  };
11292
11323
  }
11293
- function shimSendThrowTypeError(window) {
11324
+ function shimSendThrowTypeError(window, browserDetails) {
11294
11325
  if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) {
11295
11326
  return;
11296
11327
  }
11328
+ if (browserDetails.browser === 'chrome' && browserDetails.version > 149) {
11329
+ // Fixed by https://issues.chromium.org/issues/490588131
11330
+ return;
11331
+ }
11297
11332
 
11298
11333
  // Note: Although Firefox >= 57 has a native implementation, the maximum
11299
11334
  // message size can be reset for all data channels at a later stage.
11300
11335
  // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
11301
-
11336
+ if (browserDetails.browser === 'firefox' && browserDetails.version > 60) {
11337
+ return;
11338
+ }
11302
11339
  function wrapDcSend(dc, pc) {
11303
11340
  const origDataChannelSend = dc.send;
11304
11341
  dc.send = function send() {
@@ -11536,16 +11573,16 @@ function adapterFactory() {
11536
11573
  shimGetUserMedia$2(window, browserDetails);
11537
11574
  shimMediaStream(window);
11538
11575
  shimPeerConnection$1(window, browserDetails);
11539
- shimOnTrack$1(window);
11576
+ shimOnTrack$1(window, browserDetails);
11540
11577
  shimAddTrackRemoveTrack(window, browserDetails);
11541
11578
  shimGetSendersWithDtmf(window);
11542
- shimSenderReceiverGetStats(window);
11579
+ shimSenderReceiverGetStats(window, browserDetails);
11543
11580
  fixNegotiationNeeded(window, browserDetails);
11544
11581
  shimRTCIceCandidate(window);
11545
11582
  shimRTCIceCandidateRelayProtocol(window);
11546
11583
  shimConnectionState(window);
11547
11584
  shimMaxMessageSize(window, browserDetails);
11548
- shimSendThrowTypeError(window);
11585
+ shimSendThrowTypeError(window, browserDetails);
11549
11586
  removeExtmapAllowMixed(window, browserDetails);
11550
11587
  break;
11551
11588
  case 'firefox':
@@ -11562,6 +11599,7 @@ function adapterFactory() {
11562
11599
  shimParameterlessSetLocalDescription(window);
11563
11600
  shimGetUserMedia$1(window, browserDetails);
11564
11601
  shimPeerConnection(window, browserDetails);
11602
+ shimGetStats(window, browserDetails);
11565
11603
  shimOnTrack(window);
11566
11604
  shimRemoveStream(window);
11567
11605
  shimSenderGetStats(window);
@@ -11574,7 +11612,7 @@ function adapterFactory() {
11574
11612
  shimRTCIceCandidate(window);
11575
11613
  shimConnectionState(window);
11576
11614
  shimMaxMessageSize(window, browserDetails);
11577
- shimSendThrowTypeError(window);
11615
+ shimSendThrowTypeError(window, browserDetails);
11578
11616
  break;
11579
11617
  case 'safari':
11580
11618
  if (!safariShim || !options.shimSafari) {
@@ -11599,7 +11637,7 @@ function adapterFactory() {
11599
11637
  shimRTCIceCandidate(window);
11600
11638
  shimRTCIceCandidateRelayProtocol(window);
11601
11639
  shimMaxMessageSize(window, browserDetails);
11602
- shimSendThrowTypeError(window);
11640
+ shimSendThrowTypeError(window, browserDetails);
11603
11641
  removeExtmapAllowMixed(window, browserDetails);
11604
11642
  break;
11605
11643
  default:
@@ -11706,7 +11744,7 @@ function getMatch(exp, ua) {
11706
11744
  }
11707
11745
  function getOSVersion(ua) {
11708
11746
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
11709
- }var version$1 = "2.18.3";const version = version$1;
11747
+ }var version$1 = "2.18.4";const version = version$1;
11710
11748
  const protocolVersion = 16;/** Base error that all LiveKit specific custom errors inherit from. */
11711
11749
  class LivekitError extends Error {
11712
11750
  constructor(code, message, options) {
@@ -17120,6 +17158,7 @@ class PCTransport extends eventsExports.EventEmitter {
17120
17158
  if (!this._pc) {
17121
17159
  return;
17122
17160
  }
17161
+ this.pendingInitialOffer = undefined;
17123
17162
  this._pc.close();
17124
17163
  this._pc.onconnectionstatechange = null;
17125
17164
  this._pc.oniceconnectionstatechange = null;
@@ -17207,7 +17246,7 @@ class PCTransport extends eventsExports.EventEmitter {
17207
17246
  this.remoteStereoMids = stereoMids;
17208
17247
  this.remoteNackMids = nackMids;
17209
17248
  } else if (sd.type === 'answer') {
17210
- if (this.pendingInitialOffer) {
17249
+ if (this.pendingInitialOffer && this._pc) {
17211
17250
  const initialOffer = this.pendingInitialOffer;
17212
17251
  this.pendingInitialOffer = undefined;
17213
17252
  const sdpParsed = libExports.parse((_a = initialOffer.sdp) !== null && _a !== void 0 ? _a : '');
@@ -17529,6 +17568,7 @@ class PCTransport extends eventsExports.EventEmitter {
17529
17568
  }
17530
17569
  setMungedSDP(sd, munged, remote) {
17531
17570
  return __awaiter(this, void 0, void 0, function* () {
17571
+ var _a, _b;
17532
17572
  if (munged) {
17533
17573
  const originalSdp = sd.sdp;
17534
17574
  sd.sdp = munged;
@@ -17550,9 +17590,9 @@ class PCTransport extends eventsExports.EventEmitter {
17550
17590
  }
17551
17591
  try {
17552
17592
  if (remote) {
17553
- yield this.pc.setRemoteDescription(sd);
17593
+ yield (_a = this._pc) === null || _a === void 0 ? void 0 : _a.setRemoteDescription(sd);
17554
17594
  } else {
17555
- yield this.pc.setLocalDescription(sd);
17595
+ yield (_b = this._pc) === null || _b === void 0 ? void 0 : _b.setLocalDescription(sd);
17556
17596
  }
17557
17597
  } catch (e) {
17558
17598
  let msg = 'unknown error';
@@ -20333,6 +20373,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20333
20373
  /** specifies how often an initial join connection is allowed to retry */
20334
20374
  this.maxJoinAttempts = 1;
20335
20375
  this.shouldFailNext = false;
20376
+ this.shouldFailOnV1Path = false;
20336
20377
  this.log = livekitLogger;
20337
20378
  this.reliableDataSequence = 1;
20338
20379
  this.reliableMessageBuffer = new DataPacketBuffer();
@@ -20634,6 +20675,11 @@ class RTCEngine extends eventsExports.EventEmitter {
20634
20675
  if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
20635
20676
  throw ConnectionError.cancelled('Connection aborted');
20636
20677
  }
20678
+ if (!useV0Path && _this2.shouldFailOnV1Path) {
20679
+ _this2.shouldFailOnV1Path = false;
20680
+ throw ConnectionError.serviceNotFound('Simulated v1 path failure', 'v0-rtc');
20681
+ }
20682
+ livekitLogger.warn('joining signal with ', url);
20637
20683
  const joinResponse = yield _this2.client.join(url, token, opts, abortSignal, useV0Path, offerProto);
20638
20684
  _this2._isClosed = false;
20639
20685
  _this2.latestJoinResponse = joinResponse;
@@ -20683,6 +20729,10 @@ class RTCEngine extends eventsExports.EventEmitter {
20683
20729
  }
20684
20730
  } else if (e.reason === ConnectionErrorReason.ServiceNotFound) {
20685
20731
  _this2.log.warn("Initial connection failed: ".concat(e.message, " \u2013 Retrying"));
20732
+ if (_this2.pcManager) {
20733
+ _this2.pcManager.onStateChange = undefined;
20734
+ yield _this2.cleanupPeerConnections();
20735
+ }
20686
20736
  return _this2.join(url, token, opts, abortSignal, true);
20687
20737
  }
20688
20738
  }
@@ -21783,6 +21833,11 @@ class RTCEngine extends eventsExports.EventEmitter {
21783
21833
  // debugging method to fail the next reconnect/resume attempt
21784
21834
  this.shouldFailNext = true;
21785
21835
  }
21836
+ /* @internal */
21837
+ failNextV1Path() {
21838
+ // debugging method to fail the next connection attempt for /rtc/v1 to trigger the fallback version
21839
+ this.shouldFailOnV1Path = true;
21840
+ }
21786
21841
  dataChannelsInfo() {
21787
21842
  const infos = [];
21788
21843
  const getInfo = (dc, target) => {
@@ -23540,55 +23595,82 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23540
23595
  let bufferSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : READABLE_STREAM_DEFAULT_BUFFER_SIZE;
23541
23596
  let streamController = null;
23542
23597
  const sfuSubscriptionComplete = new Future();
23598
+ const detachSignal = () => {
23599
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
23600
+ };
23601
+ const cleanup = () => {
23602
+ detachSignal();
23603
+ if (!streamController) {
23604
+ log$1.warn("ReadableStream subscribed to ".concat(sid, " was not started."));
23605
+ return;
23606
+ }
23607
+ const descriptor = this.descriptors.get(sid);
23608
+ if (!descriptor) {
23609
+ log$1.warn("Unknown track ".concat(sid, ", skipping cancel..."));
23610
+ return;
23611
+ }
23612
+ if (descriptor.subscription.type !== 'active') {
23613
+ log$1.warn("Subscription for track ".concat(sid, " is not active, skipping cancel..."));
23614
+ return;
23615
+ }
23616
+ descriptor.subscription.streamControllers.delete(streamController);
23617
+ // If no active stream controllers are left, also unsubscribe on the SFU end.
23618
+ if (descriptor.subscription.streamControllers.size === 0) {
23619
+ this.unSubscribeRequest(descriptor.info.sid);
23620
+ }
23621
+ };
23622
+ const onAbort = () => {
23623
+ var _a;
23624
+ if (!streamController) {
23625
+ return;
23626
+ }
23627
+ const currentDescriptor = this.descriptors.get(sid);
23628
+ if ((currentDescriptor === null || currentDescriptor === void 0 ? void 0 : currentDescriptor.subscription.type) === 'active') {
23629
+ currentDescriptor.subscription.streamControllers.delete(streamController);
23630
+ }
23631
+ streamController.error(DataTrackSubscribeError.cancelled());
23632
+ (_a = sfuSubscriptionComplete.reject) === null || _a === void 0 ? void 0 : _a.call(sfuSubscriptionComplete, DataTrackSubscribeError.cancelled());
23633
+ cleanup();
23634
+ };
23543
23635
  const stream = new ReadableStream({
23544
23636
  start: controller => {
23545
23637
  streamController = controller;
23546
- const onAbort = () => {
23547
- var _a;
23548
- controller.error(DataTrackSubscribeError.cancelled());
23549
- (_a = sfuSubscriptionComplete.reject) === null || _a === void 0 ? void 0 : _a.call(sfuSubscriptionComplete, DataTrackSubscribeError.cancelled());
23550
- };
23551
23638
  this.subscribeRequest(sid, signal).then(() => __awaiter(this, void 0, void 0, function* () {
23552
- var _a;
23553
- signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort);
23639
+ var _a, _b, _c;
23554
23640
  const descriptor = this.descriptors.get(sid);
23555
23641
  if (!descriptor) {
23556
23642
  log$1.error("Unknown track ".concat(sid));
23643
+ const err = DataTrackSubscribeError.disconnected();
23644
+ controller.error(err);
23645
+ (_a = sfuSubscriptionComplete.reject) === null || _a === void 0 ? void 0 : _a.call(sfuSubscriptionComplete, err);
23557
23646
  return;
23558
23647
  }
23559
23648
  if (descriptor.subscription.type !== 'active') {
23560
23649
  log$1.error("Subscription for track ".concat(sid, " is not active"));
23650
+ const err = DataTrackSubscribeError.disconnected();
23651
+ controller.error(err);
23652
+ (_b = sfuSubscriptionComplete.reject) === null || _b === void 0 ? void 0 : _b.call(sfuSubscriptionComplete, err);
23561
23653
  return;
23562
23654
  }
23563
- descriptor.subscription.streamControllers.add(controller);
23564
- (_a = sfuSubscriptionComplete.resolve) === null || _a === void 0 ? void 0 : _a.call(sfuSubscriptionComplete);
23655
+ // Attach the abort signal, aborting immediately if the abort signal was fired while
23656
+ // subscribeRequest was in flight.
23657
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
23658
+ onAbort();
23659
+ return;
23660
+ }
23661
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort);
23662
+ descriptor.subscription.streamControllers.set(controller, detachSignal);
23663
+ (_c = sfuSubscriptionComplete.resolve) === null || _c === void 0 ? void 0 : _c.call(sfuSubscriptionComplete);
23565
23664
  })).catch(err => {
23566
23665
  var _a;
23666
+ // subscribeRequest rejected (cancelled, timed out, disconnected). The signal
23667
+ // listener was never attached in this path, so nothing to detach.
23567
23668
  controller.error(err);
23568
23669
  (_a = sfuSubscriptionComplete.reject) === null || _a === void 0 ? void 0 : _a.call(sfuSubscriptionComplete, err);
23569
- }).finally(() => {
23570
- signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
23571
23670
  });
23572
23671
  },
23573
23672
  cancel: () => {
23574
- if (!streamController) {
23575
- log$1.warn("ReadableStream subscribed to ".concat(sid, " was not started."));
23576
- return;
23577
- }
23578
- const descriptor = this.descriptors.get(sid);
23579
- if (!descriptor) {
23580
- log$1.warn("Unknown track ".concat(sid, ", skipping cancel..."));
23581
- return;
23582
- }
23583
- if (descriptor.subscription.type !== 'active') {
23584
- log$1.warn("Subscription for track ".concat(sid, " is not active, skipping cancel..."));
23585
- return;
23586
- }
23587
- descriptor.subscription.streamControllers.delete(streamController);
23588
- // If no active stream controllers are left, also unsubscribe on the SFU end.
23589
- if (descriptor.subscription.streamControllers.size === 0) {
23590
- this.unSubscribeRequest(descriptor.info.sid);
23591
- }
23673
+ cleanup();
23592
23674
  }
23593
23675
  }, new CountQueuingStrategy({
23594
23676
  highWaterMark: bufferSize
@@ -23726,9 +23808,7 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23726
23808
  log$1.warn("Unexpected descriptor state in unSubscribeRequest, expected active, found ".concat((_a = descriptor.subscription) === null || _a === void 0 ? void 0 : _a.type));
23727
23809
  return;
23728
23810
  }
23729
- for (const controller of descriptor.subscription.streamControllers) {
23730
- controller.close();
23731
- }
23811
+ this.closeStreamControllers(descriptor.subscription.streamControllers, sid);
23732
23812
  // FIXME: this might be wrong? Shouldn't this only occur if it is the last subscription to
23733
23813
  // terminate?
23734
23814
  const previousDescriptorSubscription = descriptor.subscription;
@@ -23741,6 +23821,23 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23741
23821
  subscribe: false
23742
23822
  });
23743
23823
  }
23824
+ /** Detach abort-signal listeners and close all downstream stream controllers for an active
23825
+ * subscription. Used when the subscription is being torn down by the manager (unsubscribe,
23826
+ * unpublish, or shutdown). */
23827
+ closeStreamControllers(streamControllers, sid) {
23828
+ for (const [controller, detachSignal] of streamControllers) {
23829
+ // Detach before close so we don't leak a listener on the user's AbortSignal.
23830
+ detachSignal();
23831
+ try {
23832
+ controller.close();
23833
+ } catch (err) {
23834
+ // Defensive: if the controller has already been errored (e.g. by a racing abort whose
23835
+ // listener removed itself before we got here), close() throws. There's nothing
23836
+ // meaningful to do other than log — the stream is already terminal.
23837
+ log$1.warn("Failed to close readable stream for track ".concat(sid, ": ").concat(err));
23838
+ }
23839
+ }
23840
+ }
23744
23841
  /** SFU notification that track publications have changed.
23745
23842
  *
23746
23843
  * This event is produced from both {@link JoinResponse} and {@link ParticipantUpdate}
@@ -23822,9 +23919,7 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23822
23919
  }
23823
23920
  this.descriptors.delete(sid);
23824
23921
  if (descriptor.subscription.type === 'active') {
23825
- descriptor.subscription.streamControllers.forEach(controller => {
23826
- controller.close();
23827
- });
23922
+ this.closeStreamControllers(descriptor.subscription.streamControllers, sid);
23828
23923
  this.subscriptionHandles.delete(descriptor.subscription.subcriptionHandle);
23829
23924
  }
23830
23925
  this.emit('trackUnpublished', {
@@ -23874,7 +23969,7 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23874
23969
  type: 'active',
23875
23970
  subcriptionHandle: assignedHandle,
23876
23971
  pipeline,
23877
- streamControllers: new Set()
23972
+ streamControllers: new Map()
23878
23973
  };
23879
23974
  this.subscriptionHandles.set(assignedHandle, sid);
23880
23975
  (_b = (_a = previousDescriptorSubscription.completionFuture).resolve) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -23911,7 +24006,7 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23911
24006
  return;
23912
24007
  }
23913
24008
  // Broadcast to all downstream subscribers
23914
- for (const controller of descriptor.subscription.streamControllers) {
24009
+ for (const controller of descriptor.subscription.streamControllers.keys()) {
23915
24010
  if (controller.desiredSize !== null && controller.desiredSize <= 0) {
23916
24011
  log$1.warn("Cannot send frame to subscribers: readable stream is full (desiredSize is ".concat(controller.desiredSize, "). To increase this threshold, set a higher 'options.highWaterMark' when calling .subscribe()."));
23917
24012
  continue;
@@ -23969,7 +24064,7 @@ class IncomingDataTrackManager extends eventsExports.EventEmitter {
23969
24064
  (_b = (_a = descriptor.subscription.completionFuture).reject) === null || _b === void 0 ? void 0 : _b.call(_a, DataTrackSubscribeError.disconnected());
23970
24065
  }
23971
24066
  if (descriptor.subscription.type === 'active') {
23972
- descriptor.subscription.streamControllers.forEach(controller => controller.close());
24067
+ this.closeStreamControllers(descriptor.subscription.streamControllers, descriptor.info.sid);
23973
24068
  }
23974
24069
  }
23975
24070
  this.descriptors.clear();
@@ -27718,14 +27813,14 @@ class DeferrableMap extends Map {
27718
27813
  this.pending = new Map();
27719
27814
  }
27720
27815
  set(key, value) {
27721
- var _a;
27816
+ var _a, _b;
27722
27817
  super.set(key, value);
27723
27818
  // Resolve any futures waiting on this key.
27724
- const futures = this.pending.get(key);
27819
+ const futures = (_a = this.pending) === null || _a === void 0 ? void 0 : _a.get(key);
27725
27820
  if (futures) {
27726
27821
  for (const future of futures) {
27727
27822
  if (!future.isResolved) {
27728
- (_a = future.resolve) === null || _a === void 0 ? void 0 : _a.call(future, value);
27823
+ (_b = future.resolve) === null || _b === void 0 ? void 0 : _b.call(future, value);
27729
27824
  }
27730
27825
  }
27731
27826
  this.pending.delete(key);
@@ -27733,7 +27828,7 @@ class DeferrableMap extends Map {
27733
27828
  return this;
27734
27829
  }
27735
27830
  get [Symbol.toStringTag]() {
27736
- return 'WaitableMap';
27831
+ return 'DeferrableMap';
27737
27832
  }
27738
27833
  getDeferred(key, signal) {
27739
27834
  return __awaiter(this, void 0, void 0, function* () {
@@ -28056,8 +28151,13 @@ class DeferrableMap extends Map {
28056
28151
  }
28057
28152
  }class RemoteParticipant extends Participant {
28058
28153
  /** @internal */
28059
- static fromParticipantInfo(signalClient, pi, loggerOptions) {
28060
- return new RemoteParticipant(signalClient, pi.sid, pi.identity, pi.name, pi.metadata, pi.attributes, loggerOptions, pi.kind);
28154
+ static fromParticipantInfo(signalClient, pi, loggerOptions, manager) {
28155
+ return new RemoteParticipant(signalClient, pi.sid, pi.identity, pi.name, pi.metadata, pi.attributes, loggerOptions, pi.kind, pi.dataTracks.map(dti => {
28156
+ const info = DataTrackInfo.from(dti);
28157
+ return new RemoteDataTrack(info, manager, {
28158
+ publisherIdentity: pi.identity
28159
+ });
28160
+ }));
28061
28161
  }
28062
28162
  get logContext() {
28063
28163
  return Object.assign(Object.assign({}, super.logContext), {
@@ -28068,12 +28168,15 @@ class DeferrableMap extends Map {
28068
28168
  /** @internal */
28069
28169
  constructor(signalClient, sid, identity, name, metadata, attributes, loggerOptions) {
28070
28170
  let kind = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : ParticipantInfo_Kind.STANDARD;
28171
+ let remoteDataTracks = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : [];
28071
28172
  super(sid, identity || '', name, metadata, attributes, loggerOptions, kind);
28072
28173
  this.signalClient = signalClient;
28073
28174
  this.trackPublications = new Map();
28074
28175
  this.audioTrackPublications = new Map();
28075
28176
  this.videoTrackPublications = new Map();
28076
- this.dataTracks = new DeferrableMap();
28177
+ this.dataTracks = new DeferrableMap(remoteDataTracks.map(remoteDataTrack => {
28178
+ return [remoteDataTrack.info.name, remoteDataTrack];
28179
+ }));
28077
28180
  this.volumeMap = new Map();
28078
28181
  }
28079
28182
  addTrackPublication(publication) {
@@ -29367,18 +29470,7 @@ class Room extends eventsExports.EventEmitter {
29367
29470
  }).on(EngineEvent.DCBufferStatusChanged, (status, kind) => {
29368
29471
  this.emit(RoomEvent.DCBufferStatusChanged, status, kind);
29369
29472
  }).on(EngineEvent.LocalTrackSubscribed, subscribedSid => {
29370
- const trackPublication = this.localParticipant.getTrackPublications().find(_ref2 => {
29371
- let {
29372
- trackSid
29373
- } = _ref2;
29374
- return trackSid === subscribedSid;
29375
- });
29376
- if (!trackPublication) {
29377
- this.log.warn('could not find local track subscription for subscribed event', this.logContext);
29378
- return;
29379
- }
29380
- this.localParticipant.emit(ParticipantEvent.LocalTrackSubscribed, trackPublication);
29381
- this.emitWhenConnected(RoomEvent.LocalTrackSubscribed, trackPublication, this.localParticipant);
29473
+ this.handleLocalTrackSubscribed(subscribedSid);
29382
29474
  }).on(EngineEvent.RoomMoved, roomMoved => {
29383
29475
  this.log.debug('room moved', roomMoved);
29384
29476
  if (roomMoved.room) {
@@ -29414,8 +29506,8 @@ class Room extends eventsExports.EventEmitter {
29414
29506
  }
29415
29507
  this.outgoingDataTrackManager.receivedSfuUnpublishResponse(event.info.pubHandle);
29416
29508
  }).on(EngineEvent.DataTrackSubscriberHandles, event => {
29417
- const handleToSidMapping = new Map(Object.entries(event.subHandles).map(_ref3 => {
29418
- let [key, value] = _ref3;
29509
+ const handleToSidMapping = new Map(Object.entries(event.subHandles).map(_ref2 => {
29510
+ let [key, value] = _ref2;
29419
29511
  return [parseInt(key, 10), value.trackSid];
29420
29512
  }));
29421
29513
  this.incomingDataTrackManager.receivedSfuSubscriberHandles(handleToSidMapping);
@@ -29521,6 +29613,9 @@ class Room extends eventsExports.EventEmitter {
29521
29613
  // @ts-expect-error function is private
29522
29614
  yield this.engine.client.handleOnClose('simulate disconnect');
29523
29615
  break;
29616
+ case 'fail-on-v1-path':
29617
+ this.engine.failNextV1Path();
29618
+ break;
29524
29619
  case 'speaker':
29525
29620
  req = new SimulateScenario({
29526
29621
  scenario: {
@@ -29844,6 +29939,56 @@ class Room extends eventsExports.EventEmitter {
29844
29939
  this.emit(RoomEvent.EncryptionError, new Error("Encrypted ".concat(publication.source, " track received from participant ").concat(participant.sid, ", but room does not have encryption enabled!")));
29845
29940
  }
29846
29941
  }
29942
+ handleLocalTrackSubscribed(subscribedSid) {
29943
+ const findPublication = () => this.localParticipant.getTrackPublications().find(_ref3 => {
29944
+ let {
29945
+ trackSid
29946
+ } = _ref3;
29947
+ return trackSid === subscribedSid;
29948
+ });
29949
+ const trackPublication = findPublication();
29950
+ if (trackPublication) {
29951
+ this.emitLocalTrackSubscribed(trackPublication);
29952
+ return;
29953
+ }
29954
+ // the track publication may not be registered yet if the server signals
29955
+ // the subscription before publishTrack has finished adding the publication.
29956
+ // defer with a timeout until LocalTrackPublished fires for the matching trackSid
29957
+ this.log.debug('deferring LocalTrackSubscribed, publication not yet available', Object.assign(Object.assign({}, this.logContext), {
29958
+ subscribedSid
29959
+ }));
29960
+ const TIMEOUT_MS = 10000;
29961
+ let timer;
29962
+ const onPublished = pub => {
29963
+ if (pub.trackSid === subscribedSid) {
29964
+ cleanup();
29965
+ this.emitLocalTrackSubscribed(pub);
29966
+ }
29967
+ };
29968
+ const cleanup = () => {
29969
+ clearTimeout(timer);
29970
+ this.localParticipant.off(ParticipantEvent.LocalTrackPublished, onPublished);
29971
+ this.off(RoomEvent.Disconnected, cleanup);
29972
+ };
29973
+ this.localParticipant.on(ParticipantEvent.LocalTrackPublished, onPublished);
29974
+ this.once(RoomEvent.Disconnected, cleanup);
29975
+ timer = setTimeout(() => {
29976
+ cleanup();
29977
+ // final attempt in case the publication was added without emitting the event
29978
+ const pub = findPublication();
29979
+ if (pub) {
29980
+ this.emitLocalTrackSubscribed(pub);
29981
+ } else {
29982
+ this.log.warn('could not find local track publication for LocalTrackSubscribed event after timeout', Object.assign(Object.assign({}, this.logContext), {
29983
+ subscribedSid
29984
+ }));
29985
+ }
29986
+ }, TIMEOUT_MS);
29987
+ }
29988
+ emitLocalTrackSubscribed(trackPublication) {
29989
+ this.localParticipant.emit(ParticipantEvent.LocalTrackSubscribed, trackPublication);
29990
+ this.emitWhenConnected(RoomEvent.LocalTrackSubscribed, trackPublication, this.localParticipant);
29991
+ }
29847
29992
  handleDisconnect() {
29848
29993
  let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
29849
29994
  let reason = arguments.length > 1 ? arguments[1] : undefined;
@@ -30048,7 +30193,7 @@ class Room extends eventsExports.EventEmitter {
30048
30193
  participant = RemoteParticipant.fromParticipantInfo(this.engine.client, info, {
30049
30194
  loggerContextCb: () => this.logContext,
30050
30195
  loggerName: this.options.loggerName
30051
- });
30196
+ }, this.incomingDataTrackManager);
30052
30197
  } else {
30053
30198
  participant = new RemoteParticipant(this.engine.client, '', identity, undefined, undefined, undefined, {
30054
30199
  loggerContextCb: () => this.logContext,