livekit-client 1.6.5 → 1.6.7

Sign up to get free protection for your applications and to get access to all the features.
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 => {