livekit-client 1.9.1 → 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -14940,7 +14940,7 @@ var uaParser = {exports: {}};
14940
14940
  var uaParserExports = uaParser.exports;
14941
14941
  var UAParser = /*@__PURE__*/getDefaultExportFromCjs(uaParserExports);
14942
14942
 
14943
- var version$1 = "1.9.1";
14943
+ var version$1 = "1.9.2";
14944
14944
 
14945
14945
  const version = version$1;
14946
14946
  const protocolVersion = 9;
@@ -15509,13 +15509,7 @@ class SignalClient {
15509
15509
  this.handleSignalResponse(resp);
15510
15510
  };
15511
15511
  this.ws.onclose = ev => {
15512
- if (!this.isConnected) return;
15513
- livekitLogger.debug("websocket connection closed: ".concat(ev.reason));
15514
- this.isConnected = false;
15515
- if (this.onClose) {
15516
- this.onClose(ev.reason);
15517
- }
15518
- this.ws = undefined;
15512
+ this.handleOnClose(ev.reason);
15519
15513
  };
15520
15514
  });
15521
15515
  }
@@ -15784,6 +15778,17 @@ class SignalClient {
15784
15778
  }
15785
15779
  this.isReconnecting = false;
15786
15780
  }
15781
+ handleOnClose(reason) {
15782
+ if (!this.isConnected) return;
15783
+ this.clearPingInterval();
15784
+ this.clearPingTimeout();
15785
+ livekitLogger.debug("websocket connection closed: ".concat(reason));
15786
+ this.isConnected = false;
15787
+ if (this.onClose) {
15788
+ this.onClose(reason);
15789
+ }
15790
+ this.ws = undefined;
15791
+ }
15787
15792
  handleWSError(ev) {
15788
15793
  livekitLogger.error('websocket error', ev);
15789
15794
  }
@@ -15799,9 +15804,7 @@ class SignalClient {
15799
15804
  }
15800
15805
  this.pingTimeout = CriticalTimers.setTimeout(() => {
15801
15806
  livekitLogger.warn("ping timeout triggered. last pong received at: ".concat(new Date(Date.now() - this.pingTimeoutDuration * 1000).toUTCString()));
15802
- if (this.onClose) {
15803
- this.onClose('ping timeout');
15804
- }
15807
+ this.handleOnClose('ping timeout');
15805
15808
  }, this.pingTimeoutDuration * 1000);
15806
15809
  }
15807
15810
  /**
@@ -18571,7 +18574,7 @@ class RTCEngine extends eventsExports.EventEmitter {
18571
18574
  } else {
18572
18575
  livekitLogger.info("could not recover connection after ".concat(this.reconnectAttempts, " attempts, ").concat(Date.now() - this.reconnectStart, "ms. giving up"));
18573
18576
  this.emit(EngineEvent.Disconnected);
18574
- this.close();
18577
+ await this.close();
18575
18578
  }
18576
18579
  } finally {
18577
18580
  this.attemptingReconnect = false;
@@ -18792,6 +18795,30 @@ class RTCEngine extends eventsExports.EventEmitter {
18792
18795
  async ensurePublisherConnected(kind) {
18793
18796
  await this.ensureDataTransportConnected(kind, false);
18794
18797
  }
18798
+ /* @internal */
18799
+ verifyTransport() {
18800
+ // primary connection
18801
+ if (!this.primaryPC) {
18802
+ return false;
18803
+ }
18804
+ if (this.primaryPC.connectionState === 'closed' || this.primaryPC.connectionState === 'failed') {
18805
+ return false;
18806
+ }
18807
+ // also verify publisher connection if it's needed or different
18808
+ if (this.hasPublished && this.subscriberPrimary) {
18809
+ if (!this.publisher) {
18810
+ return false;
18811
+ }
18812
+ if (this.publisher.pc.connectionState === 'closed' || this.publisher.pc.connectionState === 'failed') {
18813
+ return false;
18814
+ }
18815
+ }
18816
+ // ensure signal is connected
18817
+ if (!this.client.ws || this.client.ws.readyState === WebSocket.CLOSED) {
18818
+ return false;
18819
+ }
18820
+ return true;
18821
+ }
18795
18822
  /** @internal */
18796
18823
  negotiate() {
18797
18824
  // observe signal state
@@ -22242,6 +22269,7 @@ var ConnectionState;
22242
22269
  ConnectionState["Connected"] = "connected";
22243
22270
  ConnectionState["Reconnecting"] = "reconnecting";
22244
22271
  })(ConnectionState || (ConnectionState = {}));
22272
+ const connectionReconcileFrequency = 2 * 1000;
22245
22273
  /** @deprecated RoomState has been renamed to [[ConnectionState]] */
22246
22274
  const RoomState = ConnectionState;
22247
22275
  /**
@@ -22421,6 +22449,7 @@ class Room extends eventsExports.EventEmitter {
22421
22449
  }
22422
22450
  this.setAndEmitConnectionState(ConnectionState.Connected);
22423
22451
  this.emit(RoomEvent.Connected);
22452
+ this.registerConnectionReconcile();
22424
22453
  };
22425
22454
  /**
22426
22455
  * disconnects the room, emits [[RoomEvent.Disconnected]]
@@ -22464,6 +22493,7 @@ class Room extends eventsExports.EventEmitter {
22464
22493
  await this.disconnect();
22465
22494
  };
22466
22495
  this.handleRestarting = () => {
22496
+ this.clearConnectionReconcile();
22467
22497
  // also unwind existing participants & existing subscriptions
22468
22498
  for (const p of this.participants.values()) {
22469
22499
  this.handleParticipantDisconnected(p.sid, p);
@@ -22520,6 +22550,7 @@ class Room extends eventsExports.EventEmitter {
22520
22550
  }
22521
22551
  this.setAndEmitConnectionState(ConnectionState.Connected);
22522
22552
  this.emit(RoomEvent.Reconnected);
22553
+ this.registerConnectionReconcile();
22523
22554
  // emit participant connected events after connection has been re-established
22524
22555
  this.participants.forEach(participant => {
22525
22556
  this.emit(RoomEvent.ParticipantConnected, participant);
@@ -22761,7 +22792,7 @@ class Room extends eventsExports.EventEmitter {
22761
22792
  return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.numPublishers) !== null && _b !== void 0 ? _b : 0;
22762
22793
  }
22763
22794
  maybeCreateEngine() {
22764
- if (this.engine) {
22795
+ if (this.engine && !this.engine.isClosed) {
22765
22796
  return;
22766
22797
  }
22767
22798
  this.engine = new RTCEngine(this.options);
@@ -22776,6 +22807,7 @@ class Room extends eventsExports.EventEmitter {
22776
22807
  }).on(EngineEvent.Disconnected, reason => {
22777
22808
  this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, reason);
22778
22809
  }).on(EngineEvent.ActiveSpeakersUpdate, this.handleActiveSpeakersUpdate).on(EngineEvent.DataPacketReceived, this.handleDataPacket).on(EngineEvent.Resuming, () => {
22810
+ this.clearConnectionReconcile();
22779
22811
  if (this.setAndEmitConnectionState(ConnectionState.Reconnecting)) {
22780
22812
  this.emit(RoomEvent.Reconnecting);
22781
22813
  }
@@ -22783,6 +22815,7 @@ class Room extends eventsExports.EventEmitter {
22783
22815
  }).on(EngineEvent.Resumed, () => {
22784
22816
  this.setAndEmitConnectionState(ConnectionState.Connected);
22785
22817
  this.emit(RoomEvent.Reconnected);
22818
+ this.registerConnectionReconcile();
22786
22819
  this.updateSubscriptions();
22787
22820
  // once reconnected, figure out if any participants connected during reconnect and emit events for it
22788
22821
  const diffParticipants = Array.from(this.participants.values()).filter(p => !this.cachedParticipantSids.includes(p.sid));
@@ -23093,41 +23126,45 @@ class Room extends eventsExports.EventEmitter {
23093
23126
  let shouldStopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
23094
23127
  let reason = arguments.length > 1 ? arguments[1] : undefined;
23095
23128
  var _a;
23129
+ this.clearConnectionReconcile();
23096
23130
  if (this.state === ConnectionState.Disconnected) {
23097
23131
  return;
23098
23132
  }
23099
- this.participants.forEach(p => {
23100
- p.tracks.forEach(pub => {
23101
- p.unpublishTrack(pub.trackSid);
23133
+ try {
23134
+ this.participants.forEach(p => {
23135
+ p.tracks.forEach(pub => {
23136
+ p.unpublishTrack(pub.trackSid);
23137
+ });
23102
23138
  });
23103
- });
23104
- this.localParticipant.tracks.forEach(pub => {
23105
- var _a, _b;
23106
- if (pub.track) {
23107
- this.localParticipant.unpublishTrack(pub.track, shouldStopTracks);
23108
- }
23109
- if (shouldStopTracks) {
23110
- (_a = pub.track) === null || _a === void 0 ? void 0 : _a.detach();
23111
- (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
23139
+ this.localParticipant.tracks.forEach(pub => {
23140
+ var _a, _b;
23141
+ if (pub.track) {
23142
+ this.localParticipant.unpublishTrack(pub.track, shouldStopTracks);
23143
+ }
23144
+ if (shouldStopTracks) {
23145
+ (_a = pub.track) === null || _a === void 0 ? void 0 : _a.detach();
23146
+ (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
23147
+ }
23148
+ });
23149
+ this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
23150
+ this.localParticipant.tracks.clear();
23151
+ this.localParticipant.videoTracks.clear();
23152
+ this.localParticipant.audioTracks.clear();
23153
+ this.participants.clear();
23154
+ this.activeSpeakers = [];
23155
+ if (this.audioContext && typeof this.options.expWebAudioMix === 'boolean') {
23156
+ this.audioContext.close();
23157
+ this.audioContext = undefined;
23158
+ }
23159
+ if (isWeb()) {
23160
+ window.removeEventListener('beforeunload', this.onPageLeave);
23161
+ window.removeEventListener('pagehide', this.onPageLeave);
23162
+ (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange);
23112
23163
  }
23113
- });
23114
- this.localParticipant.off(ParticipantEvent.ParticipantMetadataChanged, this.onLocalParticipantMetadataChanged).off(ParticipantEvent.ParticipantNameChanged, this.onLocalParticipantNameChanged).off(ParticipantEvent.TrackMuted, this.onLocalTrackMuted).off(ParticipantEvent.TrackUnmuted, this.onLocalTrackUnmuted).off(ParticipantEvent.LocalTrackPublished, this.onLocalTrackPublished).off(ParticipantEvent.LocalTrackUnpublished, this.onLocalTrackUnpublished).off(ParticipantEvent.ConnectionQualityChanged, this.onLocalConnectionQualityChanged).off(ParticipantEvent.MediaDevicesError, this.onMediaDevicesError).off(ParticipantEvent.ParticipantPermissionsChanged, this.onLocalParticipantPermissionsChanged);
23115
- this.localParticipant.tracks.clear();
23116
- this.localParticipant.videoTracks.clear();
23117
- this.localParticipant.audioTracks.clear();
23118
- this.participants.clear();
23119
- this.activeSpeakers = [];
23120
- if (this.audioContext && typeof this.options.expWebAudioMix === 'boolean') {
23121
- this.audioContext.close();
23122
- this.audioContext = undefined;
23123
- }
23124
- if (isWeb()) {
23125
- window.removeEventListener('beforeunload', this.onPageLeave);
23126
- window.removeEventListener('pagehide', this.onPageLeave);
23127
- (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.removeEventListener('devicechange', this.handleDeviceChange);
23164
+ } finally {
23165
+ this.setAndEmitConnectionState(ConnectionState.Disconnected);
23166
+ this.emit(RoomEvent.Disconnected, reason);
23128
23167
  }
23129
- this.setAndEmitConnectionState(ConnectionState.Disconnected);
23130
- this.emit(RoomEvent.Disconnected, reason);
23131
23168
  }
23132
23169
  handleParticipantDisconnected(sid, participant) {
23133
23170
  // remove and send event
@@ -23280,6 +23317,32 @@ class Room extends eventsExports.EventEmitter {
23280
23317
  }
23281
23318
  }
23282
23319
  }
23320
+ registerConnectionReconcile() {
23321
+ this.clearConnectionReconcile();
23322
+ let consecutiveFailures = 0;
23323
+ this.connectionReconcileInterval = CriticalTimers.setInterval(() => {
23324
+ if (
23325
+ // ensure we didn't tear it down
23326
+ !this.engine ||
23327
+ // engine detected close, but Room missed it
23328
+ this.engine.isClosed ||
23329
+ // transports failed without notifying engine
23330
+ !this.engine.verifyTransport()) {
23331
+ consecutiveFailures++;
23332
+ livekitLogger.warn('detected connection state mismatch', {
23333
+ numFailures: consecutiveFailures
23334
+ });
23335
+ if (consecutiveFailures >= 3) this.handleDisconnect(this.options.stopLocalTrackOnUnpublish, DisconnectReason.UNKNOWN_REASON);
23336
+ } else {
23337
+ consecutiveFailures = 0;
23338
+ }
23339
+ }, connectionReconcileFrequency);
23340
+ }
23341
+ clearConnectionReconcile() {
23342
+ if (this.connectionReconcileInterval) {
23343
+ CriticalTimers.clearInterval(this.connectionReconcileInterval);
23344
+ }
23345
+ }
23283
23346
  setAndEmitConnectionState(state) {
23284
23347
  if (state === this.state) {
23285
23348
  // unchanged