livekit-client 1.6.5 → 1.6.7

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 (38) hide show
  1. package/dist/livekit-client.esm.mjs +149 -130
  2. package/dist/livekit-client.esm.mjs.map +1 -1
  3. package/dist/livekit-client.umd.js +1 -1
  4. package/dist/livekit-client.umd.js.map +1 -1
  5. package/dist/src/room/PCTransport.d.ts.map +1 -1
  6. package/dist/src/room/RTCEngine.d.ts +10 -3
  7. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  8. package/dist/src/room/Room.d.ts.map +1 -1
  9. package/dist/src/room/events.d.ts +2 -1
  10. package/dist/src/room/events.d.ts.map +1 -1
  11. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  12. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  13. package/dist/src/room/track/LocalVideoTrack.d.ts +1 -0
  14. package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
  15. package/dist/src/room/track/RemoteTrackPublication.d.ts +1 -1
  16. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  17. package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
  18. package/dist/src/room/track/Track.d.ts +2 -1
  19. package/dist/src/room/track/Track.d.ts.map +1 -1
  20. package/dist/src/room/track/options.d.ts +2 -2
  21. package/dist/ts4.2/src/room/RTCEngine.d.ts +10 -3
  22. package/dist/ts4.2/src/room/events.d.ts +2 -1
  23. package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +1 -0
  24. package/dist/ts4.2/src/room/track/RemoteTrackPublication.d.ts +1 -1
  25. package/dist/ts4.2/src/room/track/Track.d.ts +2 -1
  26. package/dist/ts4.2/src/room/track/options.d.ts +2 -2
  27. package/package.json +13 -13
  28. package/src/room/PCTransport.ts +2 -0
  29. package/src/room/RTCEngine.ts +46 -51
  30. package/src/room/Room.ts +13 -3
  31. package/src/room/events.ts +2 -1
  32. package/src/room/participant/LocalParticipant.ts +20 -8
  33. package/src/room/participant/RemoteParticipant.ts +2 -3
  34. package/src/room/track/LocalVideoTrack.ts +62 -46
  35. package/src/room/track/RemoteTrackPublication.ts +3 -2
  36. package/src/room/track/RemoteVideoTrack.ts +0 -3
  37. package/src/room/track/Track.ts +2 -1
  38. package/src/room/track/options.ts +2 -2
@@ -12877,7 +12877,8 @@ var RoomEvent;
12877
12877
  */
12878
12878
  RoomEvent["SignalConnected"] = "signalConnected";
12879
12879
  /**
12880
- * Recording of a room has started/stopped.
12880
+ * Recording of a room has started/stopped. Room.isRecording will be updated too.
12881
+ * args: (isRecording: boolean)
12881
12882
  */
12882
12883
  RoomEvent["RecordingStatusChanged"] = "recordingStatusChanged";
12883
12884
  })(RoomEvent || (RoomEvent = {}));
@@ -13799,7 +13800,7 @@ var uaParser = {
13799
13800
  })(uaParser, uaParserExports);
13800
13801
  var UAParser = uaParserExports;
13801
13802
 
13802
- var version$1 = "1.6.5";
13803
+ var version$1 = "1.6.7";
13803
13804
 
13804
13805
  const version = version$1;
13805
13806
  const protocolVersion = 8;
@@ -14780,7 +14781,8 @@ class Track extends eventsExports.EventEmitter {
14780
14781
  this.attachedElements = [];
14781
14782
  this.isMuted = false;
14782
14783
  /**
14783
- * indicates current state of stream
14784
+ * indicates current state of stream, it'll indicate `paused` if the track
14785
+ * has been paused by congestion controller
14784
14786
  */
14785
14787
  this.streamState = Track.StreamState.Active;
14786
14788
  this._currentBitrate = 0;
@@ -15465,6 +15467,7 @@ class LocalVideoTrack extends LocalTrack {
15465
15467
  }
15466
15468
  this.prevStats = statsMap;
15467
15469
  };
15470
+ this.senderLock = new Mutex();
15468
15471
  }
15469
15472
  get isSimulcast() {
15470
15473
  if (this.sender && this.sender.getParameters().encodings.length > 1) {
@@ -15657,7 +15660,7 @@ class LocalVideoTrack extends LocalTrack {
15657
15660
  }
15658
15661
  } else if (simulcastCodecInfo.encodings) {
15659
15662
  livekitLogger.debug("try setPublishingLayersForSender ".concat(codec.codec));
15660
- await setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities);
15663
+ await setPublishingLayersForSender(simulcastCodecInfo.sender, simulcastCodecInfo.encodings, codec.qualities, this.senderLock);
15661
15664
  }
15662
15665
  }
15663
15666
  }
@@ -15687,7 +15690,7 @@ class LocalVideoTrack extends LocalTrack {
15687
15690
  if (!this.sender || !this.encodings) {
15688
15691
  return;
15689
15692
  }
15690
- await setPublishingLayersForSender(this.sender, this.encodings, qualities);
15693
+ await setPublishingLayersForSender(this.sender, this.encodings, qualities, this.senderLock);
15691
15694
  }
15692
15695
  async handleAppVisibilityChanged() {
15693
15696
  await super.handleAppVisibilityChanged();
@@ -15697,59 +15700,64 @@ class LocalVideoTrack extends LocalTrack {
15697
15700
  }
15698
15701
  }
15699
15702
  }
15700
- async function setPublishingLayersForSender(sender, senderEncodings, qualities) {
15703
+ async function setPublishingLayersForSender(sender, senderEncodings, qualities, senderLock) {
15704
+ const unlock = await senderLock.lock();
15701
15705
  livekitLogger.debug('setPublishingLayersForSender', {
15702
15706
  sender,
15703
15707
  qualities,
15704
15708
  senderEncodings
15705
15709
  });
15706
- const params = sender.getParameters();
15707
- const {
15708
- encodings
15709
- } = params;
15710
- if (!encodings) {
15711
- return;
15712
- }
15713
- if (encodings.length !== senderEncodings.length) {
15714
- livekitLogger.warn('cannot set publishing layers, encodings mismatch');
15715
- return;
15716
- }
15717
- let hasChanged = false;
15718
- encodings.forEach((encoding, idx) => {
15719
- var _a;
15720
- let rid = (_a = encoding.rid) !== null && _a !== void 0 ? _a : '';
15721
- if (rid === '') {
15722
- rid = 'q';
15710
+ try {
15711
+ const params = sender.getParameters();
15712
+ const {
15713
+ encodings
15714
+ } = params;
15715
+ if (!encodings) {
15716
+ return;
15723
15717
  }
15724
- const quality = videoQualityForRid(rid);
15725
- const subscribedQuality = qualities.find(q => q.quality === quality);
15726
- if (!subscribedQuality) {
15718
+ if (encodings.length !== senderEncodings.length) {
15719
+ livekitLogger.warn('cannot set publishing layers, encodings mismatch');
15727
15720
  return;
15728
15721
  }
15729
- if (encoding.active !== subscribedQuality.enabled) {
15730
- hasChanged = true;
15731
- encoding.active = subscribedQuality.enabled;
15732
- livekitLogger.debug("setting layer ".concat(subscribedQuality.quality, " to ").concat(encoding.active ? 'enabled' : 'disabled'));
15733
- // FireFox does not support setting encoding.active to false, so we
15734
- // have a workaround of lowering its bitrate and resolution to the min.
15735
- if (isFireFox()) {
15736
- if (subscribedQuality.enabled) {
15737
- encoding.scaleResolutionDownBy = senderEncodings[idx].scaleResolutionDownBy;
15738
- encoding.maxBitrate = senderEncodings[idx].maxBitrate;
15739
- /* @ts-ignore */
15740
- encoding.maxFrameRate = senderEncodings[idx].maxFrameRate;
15741
- } else {
15742
- encoding.scaleResolutionDownBy = 4;
15743
- encoding.maxBitrate = 10;
15744
- /* @ts-ignore */
15745
- encoding.maxFrameRate = 2;
15722
+ let hasChanged = false;
15723
+ encodings.forEach((encoding, idx) => {
15724
+ var _a;
15725
+ let rid = (_a = encoding.rid) !== null && _a !== void 0 ? _a : '';
15726
+ if (rid === '') {
15727
+ rid = 'q';
15728
+ }
15729
+ const quality = videoQualityForRid(rid);
15730
+ const subscribedQuality = qualities.find(q => q.quality === quality);
15731
+ if (!subscribedQuality) {
15732
+ return;
15733
+ }
15734
+ if (encoding.active !== subscribedQuality.enabled) {
15735
+ hasChanged = true;
15736
+ encoding.active = subscribedQuality.enabled;
15737
+ livekitLogger.debug("setting layer ".concat(subscribedQuality.quality, " to ").concat(encoding.active ? 'enabled' : 'disabled'));
15738
+ // FireFox does not support setting encoding.active to false, so we
15739
+ // have a workaround of lowering its bitrate and resolution to the min.
15740
+ if (isFireFox()) {
15741
+ if (subscribedQuality.enabled) {
15742
+ encoding.scaleResolutionDownBy = senderEncodings[idx].scaleResolutionDownBy;
15743
+ encoding.maxBitrate = senderEncodings[idx].maxBitrate;
15744
+ /* @ts-ignore */
15745
+ encoding.maxFrameRate = senderEncodings[idx].maxFrameRate;
15746
+ } else {
15747
+ encoding.scaleResolutionDownBy = 4;
15748
+ encoding.maxBitrate = 10;
15749
+ /* @ts-ignore */
15750
+ encoding.maxFrameRate = 2;
15751
+ }
15746
15752
  }
15747
15753
  }
15754
+ });
15755
+ if (hasChanged) {
15756
+ params.encodings = encodings;
15757
+ await sender.setParameters(params);
15748
15758
  }
15749
- });
15750
- if (hasChanged) {
15751
- params.encodings = encodings;
15752
- await sender.setParameters(params);
15759
+ } finally {
15760
+ unlock();
15753
15761
  }
15754
15762
  }
15755
15763
  function videoQualityForRid(rid) {
@@ -16108,9 +16116,6 @@ class RemoteVideoTrack extends RemoteTrack {
16108
16116
  this.updateDimensions();
16109
16117
  }, REACTION_DELAY);
16110
16118
  this.adaptiveStreamSettings = adaptiveStreamSettings;
16111
- if (this.isAdaptiveStream) {
16112
- this.streamState = Track.StreamState.Paused;
16113
- }
16114
16119
  }
16115
16120
  get isAdaptiveStream() {
16116
16121
  return this.adaptiveStreamSettings !== undefined;
@@ -17016,8 +17021,8 @@ function sortPresets(presets) {
17016
17021
  }
17017
17022
 
17018
17023
  class RemoteTrackPublication extends TrackPublication {
17019
- constructor(kind, id, name, autoSubscribe) {
17020
- super(kind, id, name);
17024
+ constructor(kind, ti, autoSubscribe) {
17025
+ super(kind, ti.sid, ti.name);
17021
17026
  this.track = undefined;
17022
17027
  /** @internal */
17023
17028
  this.allowed = true;
@@ -17042,6 +17047,7 @@ class RemoteTrackPublication extends TrackPublication {
17042
17047
  this.emitTrackUpdate();
17043
17048
  };
17044
17049
  this.subscribed = autoSubscribe;
17050
+ this.updateInfo(ti);
17045
17051
  }
17046
17052
  /**
17047
17053
  * Subscribe or unsubscribe to this remote track
@@ -17408,12 +17414,12 @@ class RemoteParticipant extends Participant {
17408
17414
  if (!kind) {
17409
17415
  return;
17410
17416
  }
17411
- publication = new RemoteTrackPublication(kind, ti.sid, ti.name, (_a = this.signalClient.connectOptions) === null || _a === void 0 ? void 0 : _a.autoSubscribe);
17417
+ publication = new RemoteTrackPublication(kind, ti, (_a = this.signalClient.connectOptions) === null || _a === void 0 ? void 0 : _a.autoSubscribe);
17412
17418
  publication.updateInfo(ti);
17413
17419
  newTracks.set(ti.sid, publication);
17414
17420
  const existingTrackOfSource = Array.from(this.tracks.values()).find(publishedTrack => publishedTrack.source === (publication === null || publication === void 0 ? void 0 : publication.source));
17415
17421
  if (existingTrackOfSource && publication.source !== Track.Source.Unknown) {
17416
- livekitLogger.warn("received a second track publication for ".concat(this.identity, " with the same source: ").concat(publication.source), {
17422
+ livekitLogger.debug("received a second track publication for ".concat(this.identity, " with the same source: ").concat(publication.source), {
17417
17423
  oldTrack: existingTrackOfSource,
17418
17424
  newTrack: publication,
17419
17425
  participant: this,
@@ -17588,7 +17594,7 @@ class LocalParticipant extends Participant {
17588
17594
  }
17589
17595
  }
17590
17596
  } else if (update.subscribedQualities.length > 0) {
17591
- (_b = pub.videoTrack) === null || _b === void 0 ? void 0 : _b.setPublishingLayers(update.subscribedQualities);
17597
+ await ((_b = pub.videoTrack) === null || _b === void 0 ? void 0 : _b.setPublishingLayers(update.subscribedQualities));
17592
17598
  }
17593
17599
  };
17594
17600
  this.handleLocalTrackUnpublished = unpublished => {
@@ -17921,7 +17927,7 @@ class LocalParticipant extends Participant {
17921
17927
  * @param options
17922
17928
  */
17923
17929
  async publishTrack(track, options) {
17924
- var _a, _b, _c, _d, _e;
17930
+ var _a, _b, _c, _d, _e, _f;
17925
17931
  // convert raw media track into audio or video track
17926
17932
  if (track instanceof MediaStreamTrack) {
17927
17933
  switch (track.kind) {
@@ -17946,7 +17952,11 @@ class LocalParticipant extends Participant {
17946
17952
  if (options.dtx === undefined) {
17947
17953
  livekitLogger.info("Opus DTX will be disabled for stereo tracks by default. Enable them explicitly to make it work.");
17948
17954
  }
17955
+ if (options.red === undefined) {
17956
+ livekitLogger.info("Opus RED will be disabled for stereo tracks by default. Enable them explicitly to make it work.");
17957
+ }
17949
17958
  (_a = options.dtx) !== null && _a !== void 0 ? _a : options.dtx = false;
17959
+ (_b = options.red) !== null && _b !== void 0 ? _b : options.red = false;
17950
17960
  }
17951
17961
  const opts = _objectSpread2(_objectSpread2({}, this.roomOptions.publishDefaults), options);
17952
17962
  // is it already published? if so skip
@@ -18004,9 +18014,9 @@ class LocalParticipant extends Participant {
18004
18014
  type: Track.kindToProto(track.kind),
18005
18015
  muted: track.isMuted,
18006
18016
  source: Track.sourceToProto(track.source),
18007
- disableDtx: !((_b = opts.dtx) !== null && _b !== void 0 ? _b : true),
18017
+ disableDtx: !((_c = opts.dtx) !== null && _c !== void 0 ? _c : true),
18008
18018
  stereo: isStereo,
18009
- disableRed: !((_c = opts.red) !== null && _c !== void 0 ? _c : true)
18019
+ disableRed: !((_d = opts.red) !== null && _d !== void 0 ? _d : true)
18010
18020
  });
18011
18021
  // compute encodings and layers for video
18012
18022
  let encodings;
@@ -18029,7 +18039,7 @@ class LocalParticipant extends Participant {
18029
18039
  if (track instanceof LocalVideoTrack) {
18030
18040
  if ((opts === null || opts === void 0 ? void 0 : opts.videoCodec) === 'av1') {
18031
18041
  // set scalabilityMode to 'L3T3' by default
18032
- opts.scalabilityMode = (_d = opts.scalabilityMode) !== null && _d !== void 0 ? _d : 'L3T3';
18042
+ opts.scalabilityMode = (_e = opts.scalabilityMode) !== null && _e !== void 0 ? _e : 'L3T3';
18033
18043
  }
18034
18044
  // set up backup
18035
18045
  if (opts.videoCodec && opts.backupCodec && opts.videoCodec !== opts.backupCodec.codec) {
@@ -18071,7 +18081,7 @@ class LocalParticipant extends Participant {
18071
18081
  });
18072
18082
  // store RTPSender
18073
18083
  track.sender = await this.engine.createSender(track, opts, encodings);
18074
- if (track.codec === 'av1' && encodings && ((_e = encodings[0]) === null || _e === void 0 ? void 0 : _e.maxBitrate)) {
18084
+ if (track.codec === 'av1' && encodings && ((_f = encodings[0]) === null || _f === void 0 ? void 0 : _f.maxBitrate)) {
18075
18085
  this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
18076
18086
  }
18077
18087
  this.engine.negotiate();
@@ -18167,13 +18177,20 @@ class LocalParticipant extends Participant {
18167
18177
  if (stopOnUnpublish) {
18168
18178
  track.stop();
18169
18179
  }
18170
- if (this.engine.publisher && this.engine.publisher.pc.connectionState !== 'closed' && track.sender) {
18180
+ let negotiationNeeded = false;
18181
+ const trackSender = track.sender;
18182
+ track.sender = undefined;
18183
+ if (this.engine.publisher && this.engine.publisher.pc.connectionState !== 'closed' && trackSender) {
18171
18184
  try {
18172
- this.engine.removeTrack(track.sender);
18185
+ if (this.engine.removeTrack(trackSender)) {
18186
+ negotiationNeeded = true;
18187
+ }
18173
18188
  if (track instanceof LocalVideoTrack) {
18174
18189
  for (const [, trackInfo] of track.simulcastCodecs) {
18175
18190
  if (trackInfo.sender) {
18176
- this.engine.removeTrack(trackInfo.sender);
18191
+ if (this.engine.removeTrack(trackInfo.sender)) {
18192
+ negotiationNeeded = true;
18193
+ }
18177
18194
  trackInfo.sender = undefined;
18178
18195
  }
18179
18196
  }
@@ -18184,11 +18201,8 @@ class LocalParticipant extends Participant {
18184
18201
  error: e,
18185
18202
  method: 'unpublishTrack'
18186
18203
  });
18187
- } finally {
18188
- await this.engine.negotiate();
18189
18204
  }
18190
18205
  }
18191
- track.sender = undefined;
18192
18206
  // remove from our maps
18193
18207
  this.tracks.delete(publication.trackSid);
18194
18208
  switch (publication.kind) {
@@ -18201,6 +18215,9 @@ class LocalParticipant extends Participant {
18201
18215
  }
18202
18216
  this.emit(ParticipantEvent.LocalTrackUnpublished, publication);
18203
18217
  publication.setTrack(undefined);
18218
+ if (negotiationNeeded) {
18219
+ await this.engine.negotiate();
18220
+ }
18204
18221
  return publication;
18205
18222
  }
18206
18223
  async unpublishTracks(tracks) {
@@ -19750,6 +19767,8 @@ class PCTransport extends eventsExports {
19750
19767
  });
19751
19768
  }
19752
19769
  close() {
19770
+ this.pc.onconnectionstatechange = null;
19771
+ this.pc.oniceconnectionstatechange = null;
19753
19772
  this.pc.close();
19754
19773
  }
19755
19774
  async setMungedLocalDescription(sd, munged) {
@@ -19868,9 +19887,7 @@ class RTCEngine extends eventsExports.EventEmitter {
19868
19887
  return this._isClosed;
19869
19888
  }
19870
19889
  constructor(options) {
19871
- var _this;
19872
19890
  super();
19873
- _this = this;
19874
19891
  this.options = options;
19875
19892
  this.rtcConfig = {};
19876
19893
  this.peerConnectionTimeout = roomConnectOptionDefaults.peerConnectionTimeout;
@@ -19889,6 +19906,7 @@ class RTCEngine extends eventsExports.EventEmitter {
19889
19906
  this.joinAttempts = 0;
19890
19907
  /** specifies how often an initial join connection is allowed to retry */
19891
19908
  this.maxJoinAttempts = 1;
19909
+ this.shouldFailNext = false;
19892
19910
  this.handleDataChannel = async _ref => {
19893
19911
  let {
19894
19912
  channel
@@ -19941,26 +19959,24 @@ class RTCEngine extends eventsExports.EventEmitter {
19941
19959
  // websocket reconnect behavior. if websocket is interrupted, and the PeerConnection
19942
19960
  // continues to work, we can reconnect to websocket to continue the session
19943
19961
  // after a number of retries, we'll close and give up permanently
19944
- this.handleDisconnect = function (connection) {
19945
- let signalEvents = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
19946
- let disconnectReason = arguments.length > 2 ? arguments[2] : undefined;
19947
- if (_this._isClosed) {
19962
+ this.handleDisconnect = (connection, disconnectReason) => {
19963
+ if (this._isClosed) {
19948
19964
  return;
19949
19965
  }
19950
19966
  livekitLogger.warn("".concat(connection, " disconnected"));
19951
- if (_this.reconnectAttempts === 0) {
19967
+ if (this.reconnectAttempts === 0) {
19952
19968
  // only reset start time on the first try
19953
- _this.reconnectStart = Date.now();
19969
+ this.reconnectStart = Date.now();
19954
19970
  }
19955
19971
  const disconnect = duration => {
19956
- livekitLogger.warn("could not recover connection after ".concat(_this.reconnectAttempts, " attempts, ").concat(duration, "ms. giving up"));
19957
- _this.emit(EngineEvent.Disconnected);
19958
- _this.close();
19972
+ livekitLogger.warn("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(duration, "ms. giving up"));
19973
+ this.emit(EngineEvent.Disconnected);
19974
+ this.close();
19959
19975
  };
19960
- const duration = Date.now() - _this.reconnectStart;
19961
- let delay = _this.getNextRetryDelay({
19976
+ const duration = Date.now() - this.reconnectStart;
19977
+ let delay = this.getNextRetryDelay({
19962
19978
  elapsedMs: duration,
19963
- retryCount: _this.reconnectAttempts
19979
+ retryCount: this.reconnectAttempts
19964
19980
  });
19965
19981
  if (delay === null) {
19966
19982
  disconnect(duration);
@@ -19970,14 +19986,14 @@ class RTCEngine extends eventsExports.EventEmitter {
19970
19986
  delay = 0;
19971
19987
  }
19972
19988
  livekitLogger.debug("reconnecting in ".concat(delay, "ms"));
19973
- _this.clearReconnectTimeout();
19974
- _this.reconnectTimeout = CriticalTimers.setTimeout(() => _this.attemptReconnect(signalEvents, disconnectReason), delay);
19989
+ this.clearReconnectTimeout();
19990
+ this.reconnectTimeout = CriticalTimers.setTimeout(() => this.attemptReconnect(disconnectReason), delay);
19975
19991
  };
19976
19992
  this.handleBrowserOnLine = () => {
19977
19993
  // in case the engine is currently reconnecting, attempt a reconnect immediately after the browser state has changed to 'onLine'
19978
19994
  if (this.client.isReconnecting) {
19979
19995
  this.clearReconnectTimeout();
19980
- this.attemptReconnect(true, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
19996
+ this.attemptReconnect(ReconnectReason.REASON_SIGNAL_DISCONNECTED);
19981
19997
  }
19982
19998
  };
19983
19999
  this.client = new SignalClient();
@@ -20076,6 +20092,12 @@ class RTCEngine extends eventsExports.EventEmitter {
20076
20092
  this.client.sendAddTrack(req);
20077
20093
  });
20078
20094
  }
20095
+ /**
20096
+ * Removes sender from PeerConnection, returning true if it was removed successfully
20097
+ * and a negotiation is necessary
20098
+ * @param sender
20099
+ * @returns
20100
+ */
20079
20101
  removeTrack(sender) {
20080
20102
  var _a;
20081
20103
  if (sender.track && this.pendingTrackResolvers[sender.track.id]) {
@@ -20089,12 +20111,14 @@ class RTCEngine extends eventsExports.EventEmitter {
20089
20111
  }
20090
20112
  try {
20091
20113
  (_a = this.publisher) === null || _a === void 0 ? void 0 : _a.pc.removeTrack(sender);
20114
+ return true;
20092
20115
  } catch (e) {
20093
20116
  livekitLogger.warn('failed to remove track', {
20094
20117
  error: e,
20095
20118
  method: 'removeTrack'
20096
20119
  });
20097
20120
  }
20121
+ return false;
20098
20122
  }
20099
20123
  updateMuteStatus(trackSid, muted) {
20100
20124
  this.client.sendMuteTrack(trackSid, muted);
@@ -20103,8 +20127,11 @@ class RTCEngine extends eventsExports.EventEmitter {
20103
20127
  var _a;
20104
20128
  return (_a = this.reliableDCSub) === null || _a === void 0 ? void 0 : _a.readyState;
20105
20129
  }
20106
- get connectedServerAddress() {
20107
- return this.connectedServerAddr;
20130
+ async getConnectedServerAddress() {
20131
+ if (this.primaryPC === undefined) {
20132
+ return undefined;
20133
+ }
20134
+ return getConnectedAddress(this.primaryPC);
20108
20135
  }
20109
20136
  configure(joinResponse) {
20110
20137
  var _a;
@@ -20142,13 +20169,6 @@ class RTCEngine extends eventsExports.EventEmitter {
20142
20169
  primaryPC.onconnectionstatechange = async () => {
20143
20170
  livekitLogger.debug("primary PC state changed ".concat(primaryPC.connectionState));
20144
20171
  if (primaryPC.connectionState === 'connected') {
20145
- try {
20146
- this.connectedServerAddr = await getConnectedAddress(primaryPC);
20147
- } catch (e) {
20148
- livekitLogger.warn('could not get connected server address', {
20149
- error: e
20150
- });
20151
- }
20152
20172
  const shouldEmit = this.pcState === PCState.New;
20153
20173
  this.pcState = PCState.Connected;
20154
20174
  if (shouldEmit) {
@@ -20158,7 +20178,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20158
20178
  // on Safari, PeerConnection will switch to 'disconnected' during renegotiation
20159
20179
  if (this.pcState === PCState.Connected) {
20160
20180
  this.pcState = PCState.Disconnected;
20161
- this.handleDisconnect('primary peerconnection', false, subscriberPrimary ? ReconnectReason.REASON_SUBSCRIBER_FAILED : ReconnectReason.REASON_PUBLISHER_FAILED);
20181
+ this.handleDisconnect('primary peerconnection', subscriberPrimary ? ReconnectReason.REASON_SUBSCRIBER_FAILED : ReconnectReason.REASON_PUBLISHER_FAILED);
20162
20182
  }
20163
20183
  }
20164
20184
  };
@@ -20166,7 +20186,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20166
20186
  livekitLogger.debug("secondary PC state changed ".concat(secondaryPC.connectionState));
20167
20187
  // also reconnect if secondary peerconnection fails
20168
20188
  if (secondaryPC.connectionState === 'failed') {
20169
- this.handleDisconnect('secondary peerconnection', false, subscriberPrimary ? ReconnectReason.REASON_PUBLISHER_FAILED : ReconnectReason.REASON_SUBSCRIBER_FAILED);
20189
+ this.handleDisconnect('secondary peerconnection', subscriberPrimary ? ReconnectReason.REASON_PUBLISHER_FAILED : ReconnectReason.REASON_SUBSCRIBER_FAILED);
20170
20190
  }
20171
20191
  };
20172
20192
  this.subscriber.pc.ontrack = ev => {
@@ -20229,7 +20249,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20229
20249
  this.token = token;
20230
20250
  };
20231
20251
  this.client.onClose = () => {
20232
- this.handleDisconnect('signal', false, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
20252
+ this.handleDisconnect('signal', ReconnectReason.REASON_SIGNAL_DISCONNECTED);
20233
20253
  };
20234
20254
  this.client.onLeave = leave => {
20235
20255
  if (leave === null || leave === void 0 ? void 0 : leave.canReconnect) {
@@ -20403,9 +20423,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20403
20423
  }
20404
20424
  return this.publisher.pc.addTrack(track);
20405
20425
  }
20406
- async attemptReconnect() {
20407
- let signalEvents = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
20408
- let reason = arguments.length > 1 ? arguments[1] : undefined;
20426
+ async attemptReconnect(reason) {
20409
20427
  var _a, _b, _c;
20410
20428
  if (this._isClosed) {
20411
20429
  return;
@@ -20423,17 +20441,15 @@ class RTCEngine extends eventsExports.EventEmitter {
20423
20441
  try {
20424
20442
  this.attemptingReconnect = true;
20425
20443
  if (this.fullReconnectOnNext) {
20426
- await this.restartConnection(signalEvents);
20444
+ await this.restartConnection();
20427
20445
  } else {
20428
- await this.resumeConnection(signalEvents, reason);
20446
+ await this.resumeConnection(reason);
20429
20447
  }
20430
20448
  this.clearPendingReconnect();
20431
20449
  this.fullReconnectOnNext = false;
20432
20450
  } catch (e) {
20433
20451
  this.reconnectAttempts += 1;
20434
- let reconnectRequired = false;
20435
20452
  let recoverable = true;
20436
- let requireSignalEvents = false;
20437
20453
  if (e instanceof UnexpectedConnectionState) {
20438
20454
  livekitLogger.debug('received unrecoverable error', {
20439
20455
  error: e
@@ -20442,16 +20458,10 @@ class RTCEngine extends eventsExports.EventEmitter {
20442
20458
  recoverable = false;
20443
20459
  } else if (!(e instanceof SignalReconnectError)) {
20444
20460
  // cannot resume
20445
- reconnectRequired = true;
20446
- }
20447
- // when we flip from resume to reconnect
20448
- // we need to fire the right reconnecting events
20449
- if (reconnectRequired && !this.fullReconnectOnNext) {
20450
20461
  this.fullReconnectOnNext = true;
20451
- requireSignalEvents = true;
20452
20462
  }
20453
20463
  if (recoverable) {
20454
- this.handleDisconnect('reconnect', requireSignalEvents, ReconnectReason.REASON_UNKOWN);
20464
+ this.handleDisconnect('reconnect', ReconnectReason.REASON_UNKOWN);
20455
20465
  } else {
20456
20466
  livekitLogger.info("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(Date.now() - this.reconnectStart, "ms. giving up"));
20457
20467
  this.emit(EngineEvent.Disconnected);
@@ -20473,16 +20483,13 @@ class RTCEngine extends eventsExports.EventEmitter {
20473
20483
  return null;
20474
20484
  }
20475
20485
  async restartConnection() {
20476
- let emitRestarting = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
20477
20486
  var _a, _b;
20478
20487
  if (!this.url || !this.token) {
20479
20488
  // permanent failure, don't attempt reconnection
20480
20489
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
20481
20490
  }
20482
20491
  livekitLogger.info("reconnecting, attempt: ".concat(this.reconnectAttempts));
20483
- if (emitRestarting || this.reconnectAttempts === 0) {
20484
- this.emit(EngineEvent.Restarting);
20485
- }
20492
+ this.emit(EngineEvent.Restarting);
20486
20493
  if (this.client.isConnected) {
20487
20494
  await this.client.sendLeave();
20488
20495
  }
@@ -20502,14 +20509,16 @@ class RTCEngine extends eventsExports.EventEmitter {
20502
20509
  } catch (e) {
20503
20510
  throw new SignalReconnectError();
20504
20511
  }
20512
+ if (this.shouldFailNext) {
20513
+ this.shouldFailNext = false;
20514
+ throw new Error('simulated failure');
20515
+ }
20505
20516
  await this.waitForPCConnected();
20506
20517
  this.client.setReconnected();
20507
20518
  // reconnect success
20508
20519
  this.emit(EngineEvent.Restarted, joinResponse);
20509
20520
  }
20510
- async resumeConnection() {
20511
- let emitResuming = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
20512
- let reason = arguments.length > 1 ? arguments[1] : undefined;
20521
+ async resumeConnection(reason) {
20513
20522
  var _a;
20514
20523
  if (!this.url || !this.token) {
20515
20524
  // permanent failure, don't attempt reconnection
@@ -20520,9 +20529,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20520
20529
  throw new UnexpectedConnectionState('publisher and subscriber connections unset');
20521
20530
  }
20522
20531
  livekitLogger.info("resuming signal connection, attempt ".concat(this.reconnectAttempts));
20523
- if (emitResuming || this.reconnectAttempts === 0) {
20524
- this.emit(EngineEvent.Resuming);
20525
- }
20532
+ this.emit(EngineEvent.Resuming);
20526
20533
  try {
20527
20534
  const res = await this.client.reconnect(this.url, this.token, this.participantSid, reason);
20528
20535
  if (res) {
@@ -20538,6 +20545,10 @@ class RTCEngine extends eventsExports.EventEmitter {
20538
20545
  throw new SignalReconnectError(message);
20539
20546
  }
20540
20547
  this.emit(EngineEvent.SignalResumed);
20548
+ if (this.shouldFailNext) {
20549
+ this.shouldFailNext = false;
20550
+ throw new Error('simulated failure');
20551
+ }
20541
20552
  this.subscriber.restartingIce = true;
20542
20553
  // only restart publisher if it's needed
20543
20554
  if (this.hasPublished) {
@@ -20571,13 +20582,6 @@ class RTCEngine extends eventsExports.EventEmitter {
20571
20582
  // manually
20572
20583
  now - startTime > minReconnectWait && ((_a = this.primaryPC) === null || _a === void 0 ? void 0 : _a.connectionState) === 'connected') {
20573
20584
  this.pcState = PCState.Connected;
20574
- try {
20575
- this.connectedServerAddr = await getConnectedAddress(this.primaryPC);
20576
- } catch (e) {
20577
- livekitLogger.warn('could not get connected server address', {
20578
- error: e
20579
- });
20580
- }
20581
20585
  }
20582
20586
  if (this.pcState === PCState.Connected) {
20583
20587
  return;
@@ -20649,7 +20653,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20649
20653
  this.on(EngineEvent.Closing, handleClosed);
20650
20654
  const negotiationTimeout = setTimeout(() => {
20651
20655
  reject('negotiation timed out');
20652
- this.handleDisconnect('negotiation', false, ReconnectReason.REASON_SIGNAL_DISCONNECTED);
20656
+ this.handleDisconnect('negotiation', ReconnectReason.REASON_SIGNAL_DISCONNECTED);
20653
20657
  }, this.peerConnectionTimeout);
20654
20658
  const cleanup = () => {
20655
20659
  clearTimeout(negotiationTimeout);
@@ -20668,7 +20672,7 @@ class RTCEngine extends eventsExports.EventEmitter {
20668
20672
  if (e instanceof NegotiationError) {
20669
20673
  this.fullReconnectOnNext = true;
20670
20674
  }
20671
- this.handleDisconnect('negotiation', false, ReconnectReason.REASON_UNKOWN);
20675
+ this.handleDisconnect('negotiation', ReconnectReason.REASON_UNKOWN);
20672
20676
  });
20673
20677
  });
20674
20678
  }
@@ -20689,6 +20693,11 @@ class RTCEngine extends eventsExports.EventEmitter {
20689
20693
  }
20690
20694
  }
20691
20695
  }
20696
+ /* @internal */
20697
+ failNext() {
20698
+ // debugging method to fail the next reconnect/resume attempt
20699
+ this.shouldFailNext = true;
20700
+ }
20692
20701
  clearReconnectTimeout() {
20693
20702
  if (this.reconnectTimeout) {
20694
20703
  CriticalTimers.clearTimeout(this.reconnectTimeout);
@@ -21008,6 +21017,9 @@ class Room extends eventsExports.EventEmitter {
21008
21017
  });
21009
21018
  await track.restartTrack();
21010
21019
  }
21020
+ livekitLogger.debug('publishing new track', {
21021
+ track: pub.trackSid
21022
+ });
21011
21023
  await this.localParticipant.publishTrack(track, pub.options);
21012
21024
  }
21013
21025
  }));
@@ -21330,6 +21342,13 @@ class Room extends eventsExports.EventEmitter {
21330
21342
  }
21331
21343
  });
21332
21344
  break;
21345
+ case 'resume-reconnect':
21346
+ this.engine.failNext();
21347
+ await this.engine.client.close();
21348
+ if (this.engine.client.onClose) {
21349
+ this.engine.client.onClose('simulate resume-reconnect');
21350
+ }
21351
+ break;
21333
21352
  case 'force-tcp':
21334
21353
  case 'force-tls':
21335
21354
  req = SimulateScenario.fromPartial({
@@ -21564,7 +21583,7 @@ class Room extends eventsExports.EventEmitter {
21564
21583
  participant.tracks.forEach(publication => {
21565
21584
  participant.unpublishTrack(publication.trackSid, true);
21566
21585
  });
21567
- this.emitWhenConnected(RoomEvent.ParticipantDisconnected, participant);
21586
+ this.emit(RoomEvent.ParticipantDisconnected, participant);
21568
21587
  }
21569
21588
  async acquireAudioContext() {
21570
21589
  var _a, _b;
@@ -21625,7 +21644,7 @@ class Room extends eventsExports.EventEmitter {
21625
21644
  }
21626
21645
  this.emit(RoomEvent.TrackSubscribed, track, publication, participant);
21627
21646
  }).on(ParticipantEvent.TrackUnpublished, publication => {
21628
- this.emitWhenConnected(RoomEvent.TrackUnpublished, publication, participant);
21647
+ this.emit(RoomEvent.TrackUnpublished, publication, participant);
21629
21648
  }).on(ParticipantEvent.TrackUnsubscribed, (track, publication) => {
21630
21649
  this.emit(RoomEvent.TrackUnsubscribed, track, publication, participant);
21631
21650
  }).on(ParticipantEvent.TrackSubscriptionFailed, sid => {