livekit-client 1.1.9 → 1.2.2

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 (34) hide show
  1. package/dist/livekit-client.esm.mjs +218 -70
  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/api/SignalClient.d.ts +3 -1
  6. package/dist/src/api/SignalClient.d.ts.map +1 -1
  7. package/dist/src/options.d.ts +1 -0
  8. package/dist/src/options.d.ts.map +1 -1
  9. package/dist/src/room/PCTransport.d.ts +9 -0
  10. package/dist/src/room/PCTransport.d.ts.map +1 -1
  11. package/dist/src/room/RTCEngine.d.ts +1 -0
  12. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  13. package/dist/src/room/Room.d.ts +1 -1
  14. package/dist/src/room/Room.d.ts.map +1 -1
  15. package/dist/src/room/events.d.ts +8 -1
  16. package/dist/src/room/events.d.ts.map +1 -1
  17. package/dist/src/room/participant/LocalParticipant.d.ts +3 -3
  18. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  19. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  20. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  21. package/dist/src/room/track/RemoteTrackPublication.d.ts +4 -1
  22. package/dist/src/room/track/RemoteTrackPublication.d.ts.map +1 -1
  23. package/package.json +1 -1
  24. package/src/api/SignalClient.ts +3 -1
  25. package/src/options.ts +1 -0
  26. package/src/room/PCTransport.ts +39 -0
  27. package/src/room/RTCEngine.ts +41 -16
  28. package/src/room/Room.ts +20 -16
  29. package/src/room/events.ts +7 -0
  30. package/src/room/participant/LocalParticipant.ts +70 -10
  31. package/src/room/participant/RemoteParticipant.ts +12 -10
  32. package/src/room/participant/publishUtils.ts +1 -1
  33. package/src/room/track/LocalTrack.ts +4 -0
  34. package/src/room/track/RemoteTrackPublication.ts +37 -11
@@ -10189,6 +10189,8 @@ var TrackEvent;
10189
10189
  TrackEvent["Muted"] = "muted";
10190
10190
  TrackEvent["Unmuted"] = "unmuted";
10191
10191
  TrackEvent["Ended"] = "ended";
10192
+ TrackEvent["Subscribed"] = "subscribed";
10193
+ TrackEvent["Unsubscribed"] = "unsubscribed";
10192
10194
  /** @internal */
10193
10195
 
10194
10196
  TrackEvent["UpdateSettings"] = "updateSettings";
@@ -10231,6 +10233,12 @@ var TrackEvent;
10231
10233
  */
10232
10234
 
10233
10235
  TrackEvent["UpstreamResumed"] = "upstreamResumed";
10236
+ /**
10237
+ * @internal
10238
+ * Fires on RemoteTrackPublication
10239
+ */
10240
+
10241
+ TrackEvent["SubscriptionPermissionChanged"] = "subscriptionPermissionChanged";
10234
10242
  })(TrackEvent || (TrackEvent = {}));
10235
10243
 
10236
10244
  const monitorFrequency = 2000;
@@ -10257,7 +10265,7 @@ function computeBitrate(currentStats, prevStats) {
10257
10265
  return (bytesNow - bytesPrev) * 8 * 1000 / (currentStats.timestamp - prevStats.timestamp);
10258
10266
  }
10259
10267
 
10260
- var version$1 = "1.1.9";
10268
+ var version$1 = "1.2.2";
10261
10269
 
10262
10270
  const version = version$1;
10263
10271
  const protocolVersion = 8;
@@ -11550,6 +11558,7 @@ class LocalTrack extends Track {
11550
11558
  }
11551
11559
 
11552
11560
  this._mediaStreamTrack = track;
11561
+ await this.resumeUpstream();
11553
11562
  this.attachedElements.forEach(el => {
11554
11563
  attachToElement(track, el);
11555
11564
  });
@@ -11599,6 +11608,7 @@ class LocalTrack extends Track {
11599
11608
  }
11600
11609
 
11601
11610
  this._mediaStreamTrack = newTrack;
11611
+ await this.resumeUpstream();
11602
11612
  this.attachedElements.forEach(el => {
11603
11613
  attachToElement(newTrack, el);
11604
11614
  });
@@ -13445,7 +13455,7 @@ function computeVideoEncodings(isScreenShare, width, height, options) {
13445
13455
  encodings.push({
13446
13456
  rid: videoRids[2 - i],
13447
13457
  scaleResolutionDownBy: 2 ** i,
13448
- maxBitrate: videoEncoding ? videoEncoding.maxBitrate / 2 ** i : 0,
13458
+ maxBitrate: videoEncoding ? videoEncoding.maxBitrate / 3 ** i : 0,
13449
13459
 
13450
13460
  /* @ts-ignore */
13451
13461
  maxFramerate: original.encoding.maxFramerate,
@@ -13612,7 +13622,7 @@ class RemoteTrackPublication extends TrackPublication {
13612
13622
  super(...arguments);
13613
13623
  /** @internal */
13614
13624
 
13615
- this._allowed = true;
13625
+ this.allowed = true;
13616
13626
  this.disabled = false;
13617
13627
  this.currentVideoQuality = VideoQuality.HIGH;
13618
13628
 
@@ -13644,7 +13654,10 @@ class RemoteTrackPublication extends TrackPublication {
13644
13654
 
13645
13655
 
13646
13656
  setSubscribed(subscribed) {
13647
- this.subscribed = subscribed;
13657
+ this.subscribed = subscribed; // reset allowed status when desired subscription state changes
13658
+ // server will notify client via signal message if it's not allowed
13659
+
13660
+ this.allowed = true;
13648
13661
  const sub = {
13649
13662
  trackSids: [this.trackSid],
13650
13663
  subscribe: this.subscribed,
@@ -13660,11 +13673,11 @@ class RemoteTrackPublication extends TrackPublication {
13660
13673
 
13661
13674
  get subscriptionStatus() {
13662
13675
  if (this.subscribed === false || !super.isSubscribed) {
13663
- return TrackPublication.SubscriptionStatus.Unsubscribed;
13664
- }
13676
+ if (!this.allowed) {
13677
+ return TrackPublication.SubscriptionStatus.NotAllowed;
13678
+ }
13665
13679
 
13666
- if (!this._allowed) {
13667
- return TrackPublication.SubscriptionStatus.NotAllowed;
13680
+ return TrackPublication.SubscriptionStatus.Unsubscribed;
13668
13681
  }
13669
13682
 
13670
13683
  return TrackPublication.SubscriptionStatus.Subscribed;
@@ -13679,10 +13692,6 @@ class RemoteTrackPublication extends TrackPublication {
13679
13692
  return false;
13680
13693
  }
13681
13694
 
13682
- if (!this._allowed) {
13683
- return false;
13684
- }
13685
-
13686
13695
  return super.isSubscribed;
13687
13696
  }
13688
13697
 
@@ -13750,11 +13759,14 @@ class RemoteTrackPublication extends TrackPublication {
13750
13759
 
13751
13760
 
13752
13761
  setTrack(track) {
13753
- if (this.track) {
13762
+ const prevStatus = this.subscriptionStatus;
13763
+ const prevTrack = this.track;
13764
+
13765
+ if (prevTrack) {
13754
13766
  // unregister listener
13755
- this.track.off(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange);
13756
- this.track.off(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13757
- this.track.off(TrackEvent.Ended, this.handleEnded);
13767
+ prevTrack.off(TrackEvent.VideoDimensionsChanged, this.handleVideoDimensionsChange);
13768
+ prevTrack.off(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13769
+ prevTrack.off(TrackEvent.Ended, this.handleEnded);
13758
13770
  }
13759
13771
 
13760
13772
  super.setTrack(track);
@@ -13765,6 +13777,25 @@ class RemoteTrackPublication extends TrackPublication {
13765
13777
  track.on(TrackEvent.VisibilityChanged, this.handleVisibilityChange);
13766
13778
  track.on(TrackEvent.Ended, this.handleEnded);
13767
13779
  }
13780
+
13781
+ this.emitSubscriptionUpdateIfChanged(prevStatus);
13782
+
13783
+ if (!!track !== !!prevTrack) {
13784
+ // when undefined status changes, there's a subscription changed event
13785
+ if (track) {
13786
+ this.emit(TrackEvent.Subscribed, track);
13787
+ } else {
13788
+ this.emit(TrackEvent.Unsubscribed, prevTrack);
13789
+ }
13790
+ }
13791
+ }
13792
+ /** @internal */
13793
+
13794
+
13795
+ setAllowed(allowed) {
13796
+ const prevStatus = this.subscriptionStatus;
13797
+ this.allowed = allowed;
13798
+ this.emitSubscriptionUpdateIfChanged(prevStatus);
13768
13799
  }
13769
13800
  /** @internal */
13770
13801
 
@@ -13777,6 +13808,16 @@ class RemoteTrackPublication extends TrackPublication {
13777
13808
  (_a = this.track) === null || _a === void 0 ? void 0 : _a.setMuted(info.muted);
13778
13809
  }
13779
13810
 
13811
+ emitSubscriptionUpdateIfChanged(previousStatus) {
13812
+ const currentStatus = this.subscriptionStatus;
13813
+
13814
+ if (previousStatus === currentStatus) {
13815
+ return;
13816
+ }
13817
+
13818
+ this.emit(TrackEvent.SubscriptionPermissionChanged, currentStatus, previousStatus);
13819
+ }
13820
+
13780
13821
  isManualOperationAllowed() {
13781
13822
  if (this.isAdaptiveStream) {
13782
13823
  livekitLogger.warn('adaptive stream is enabled, cannot change track settings', {
@@ -13851,8 +13892,14 @@ class RemoteParticipant extends Participant {
13851
13892
  });
13852
13893
  this.signalClient.sendUpdateSubscription(sub);
13853
13894
  });
13854
- publication.on(TrackEvent.Ended, track => {
13855
- this.emit(ParticipantEvent.TrackUnsubscribed, track, publication);
13895
+ publication.on(TrackEvent.SubscriptionPermissionChanged, status => {
13896
+ this.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, publication, status);
13897
+ });
13898
+ publication.on(TrackEvent.Subscribed, track => {
13899
+ this.emit(ParticipantEvent.TrackSubscribed, track, publication);
13900
+ });
13901
+ publication.on(TrackEvent.Unsubscribed, previousTrack => {
13902
+ this.emit(ParticipantEvent.TrackUnsubscribed, previousTrack, publication);
13856
13903
  });
13857
13904
  }
13858
13905
 
@@ -13953,15 +14000,12 @@ class RemoteParticipant extends Participant {
13953
14000
  track.isMuted = publication.isMuted;
13954
14001
  track.setMediaStream(mediaStream);
13955
14002
  track.start();
13956
- publication.setTrack(track); // subscription means participant has permissions to subscribe
13957
-
13958
- publication._allowed = true; // set participant volume on new microphone tracks
14003
+ publication.setTrack(track); // set participant volume on new microphone tracks
13959
14004
 
13960
14005
  if (this.volume !== undefined && track instanceof RemoteAudioTrack && track.source === Track.Source.Microphone) {
13961
14006
  track.setVolume(this.volume);
13962
14007
  }
13963
14008
 
13964
- this.emit(ParticipantEvent.TrackSubscribed, track, publication);
13965
14009
  return publication;
13966
14010
  }
13967
14011
  /** @internal */
@@ -14049,15 +14093,8 @@ class RemoteParticipant extends Participant {
14049
14093
  } = publication;
14050
14094
 
14051
14095
  if (track) {
14052
- const {
14053
- isSubscribed
14054
- } = publication;
14055
14096
  track.stop();
14056
- publication.setTrack(undefined); // always send unsubscribed, since apps may rely on this
14057
-
14058
- if (isSubscribed) {
14059
- this.emit(ParticipantEvent.TrackUnsubscribed, track, publication);
14060
- }
14097
+ publication.setTrack(undefined);
14061
14098
  }
14062
14099
 
14063
14100
  if (sendUnpublish) {
@@ -14178,11 +14215,47 @@ class LocalParticipant extends Participant {
14178
14215
  this.unpublishTrack(track.track);
14179
14216
  };
14180
14217
 
14181
- this.handleTrackEnded = track => {
14182
- livekitLogger.debug('unpublishing local track due to TrackEnded', {
14183
- track: track.sid
14184
- });
14185
- this.unpublishTrack(track);
14218
+ this.handleTrackEnded = async track => {
14219
+ if (track.source === Track.Source.ScreenShare || track.source === Track.Source.ScreenShareAudio) {
14220
+ livekitLogger.debug('unpublishing local track due to TrackEnded', {
14221
+ track: track.sid
14222
+ });
14223
+ this.unpublishTrack(track);
14224
+ } else if (track.isUserProvided) {
14225
+ await track.pauseUpstream();
14226
+ } else if (track instanceof LocalAudioTrack || track instanceof LocalVideoTrack) {
14227
+ try {
14228
+ if (isWeb()) {
14229
+ try {
14230
+ const currentPermissions = await (navigator === null || navigator === void 0 ? void 0 : navigator.permissions.query({
14231
+ // the permission query for camera and microphone currently not supported in Safari and Firefox
14232
+ // @ts-ignore
14233
+ name: track.source === Track.Source.Camera ? 'camera' : 'microphone'
14234
+ }));
14235
+
14236
+ if (currentPermissions && currentPermissions.state === 'denied') {
14237
+ livekitLogger.warn("user has revoked access to ".concat(track.source)); // detect granted change after permissions were denied to try and resume then
14238
+
14239
+ currentPermissions.onchange = () => {
14240
+ if (currentPermissions.state !== 'denied') {
14241
+ track.restartTrack();
14242
+ currentPermissions.onchange = null;
14243
+ }
14244
+ };
14245
+
14246
+ throw new Error('GetUserMedia Permission denied');
14247
+ }
14248
+ } catch (e) {// permissions query fails for firefox, we continue and try to restart the track
14249
+ }
14250
+ }
14251
+
14252
+ livekitLogger.debug('track ended, attempting to use a different device');
14253
+ await track.restartTrack();
14254
+ } catch (e) {
14255
+ livekitLogger.warn("could not restart track, pausing upstream instead");
14256
+ await track.pauseUpstream();
14257
+ }
14258
+ }
14186
14259
  };
14187
14260
 
14188
14261
  this.audioTracks = new Map();
@@ -14241,8 +14314,8 @@ class LocalParticipant extends Participant {
14241
14314
  */
14242
14315
 
14243
14316
 
14244
- setCameraEnabled(enabled, options) {
14245
- return this.setTrackEnabled(Track.Source.Camera, enabled, options);
14317
+ setCameraEnabled(enabled, options, publishOptions) {
14318
+ return this.setTrackEnabled(Track.Source.Camera, enabled, options, publishOptions);
14246
14319
  }
14247
14320
  /**
14248
14321
  * Enable or disable a participant's microphone track.
@@ -14252,8 +14325,8 @@ class LocalParticipant extends Participant {
14252
14325
  */
14253
14326
 
14254
14327
 
14255
- setMicrophoneEnabled(enabled, options) {
14256
- return this.setTrackEnabled(Track.Source.Microphone, enabled, options);
14328
+ setMicrophoneEnabled(enabled, options, publishOptions) {
14329
+ return this.setTrackEnabled(Track.Source.Microphone, enabled, options, publishOptions);
14257
14330
  }
14258
14331
  /**
14259
14332
  * Start or stop sharing a participant's screen
@@ -14261,8 +14334,8 @@ class LocalParticipant extends Participant {
14261
14334
  */
14262
14335
 
14263
14336
 
14264
- setScreenShareEnabled(enabled, options) {
14265
- return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options);
14337
+ setScreenShareEnabled(enabled, options, publishOptions) {
14338
+ return this.setTrackEnabled(Track.Source.ScreenShare, enabled, options, publishOptions);
14266
14339
  }
14267
14340
  /** @internal */
14268
14341
 
@@ -14278,7 +14351,7 @@ class LocalParticipant extends Participant {
14278
14351
  return changed;
14279
14352
  }
14280
14353
 
14281
- async setTrackEnabled(source, enabled, options) {
14354
+ async setTrackEnabled(source, enabled, options, publishOptions) {
14282
14355
  var _a, _b;
14283
14356
 
14284
14357
  livekitLogger.debug('setTrackEnabled', {
@@ -14328,7 +14401,7 @@ class LocalParticipant extends Participant {
14328
14401
  const publishPromises = [];
14329
14402
 
14330
14403
  for (const localTrack of localTracks) {
14331
- publishPromises.push(this.publishTrack(localTrack));
14404
+ publishPromises.push(this.publishTrack(localTrack, publishOptions));
14332
14405
  }
14333
14406
 
14334
14407
  const publishedTracks = await Promise.all(publishPromises); // for screen share publications including audio, this will only return the screen share publication, not the screen share audio one
@@ -14508,7 +14581,7 @@ class LocalParticipant extends Participant {
14508
14581
 
14509
14582
 
14510
14583
  async publishTrack(track, options) {
14511
- var _a, _b, _c, _d, _e, _f, _g;
14584
+ var _a, _b, _c, _d, _e, _f, _g, _h;
14512
14585
 
14513
14586
  const opts = _objectSpread2(_objectSpread2({}, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.publishDefaults), options); // convert raw media track into audio or video track
14514
14587
 
@@ -14652,6 +14725,10 @@ class LocalParticipant extends Participant {
14652
14725
  track.codec = opts.videoCodec;
14653
14726
  }
14654
14727
 
14728
+ if (track.codec === 'av1' && encodings && ((_h = encodings[0]) === null || _h === void 0 ? void 0 : _h.maxBitrate)) {
14729
+ this.engine.publisher.setTrackCodecBitrate(req.cid, track.codec, encodings[0].maxBitrate / 1000);
14730
+ }
14731
+
14655
14732
  this.engine.negotiate(); // store RTPSender
14656
14733
 
14657
14734
  track.sender = transceiver.sender;
@@ -14673,7 +14750,7 @@ class LocalParticipant extends Participant {
14673
14750
 
14674
14751
 
14675
14752
  async publishAdditionalCodecForTrack(track, videoCodec, options) {
14676
- var _a, _b, _c, _d, _e;
14753
+ var _a, _b, _c, _d, _e, _f;
14677
14754
 
14678
14755
  const opts = _objectSpread2(_objectSpread2({}, (_a = this.roomOptions) === null || _a === void 0 ? void 0 : _a.publishDefaults), options); // clear scalabilityMode setting for backup codec
14679
14756
 
@@ -14741,6 +14818,11 @@ class LocalParticipant extends Participant {
14741
14818
  const transceiver = await this.engine.publisher.pc.addTransceiver(simulcastTrack.mediaStreamTrack, transceiverInit);
14742
14819
  this.setPreferredCodec(transceiver, track.kind, opts.videoCodec);
14743
14820
  track.setSimulcastTrackSender(opts.videoCodec, transceiver.sender);
14821
+
14822
+ if (videoCodec === 'av1' && ((_f = encodings[0]) === null || _f === void 0 ? void 0 : _f.maxBitrate)) {
14823
+ this.engine.publisher.setTrackCodecBitrate(req.cid, videoCodec, encodings[0].maxBitrate / 1000);
14824
+ }
14825
+
14744
14826
  this.engine.negotiate();
14745
14827
  livekitLogger.debug("published ".concat(opts.videoCodec, " for track ").concat(track.sid), {
14746
14828
  encodings,
@@ -18974,7 +19056,8 @@ class PCTransport {
18974
19056
  constructor(config) {
18975
19057
  this.pendingCandidates = [];
18976
19058
  this.restartingIce = false;
18977
- this.renegotiate = false; // debounced negotiate interface
19059
+ this.renegotiate = false;
19060
+ this.trackBitrates = []; // debounced negotiate interface
18978
19061
 
18979
19062
  this.negotiate = r(() => {
18980
19063
  this.createAndSendOffer();
@@ -19038,11 +19121,38 @@ class PCTransport {
19038
19121
 
19039
19122
 
19040
19123
  livekitLogger.debug('starting to negotiate');
19041
- const offer = await this.pc.createOffer(options);
19124
+ const offer = await this.pc.createOffer(options); // mung sdp for codec bitrate setting that can't apply by sendEncoding
19125
+
19126
+ this.trackBitrates.forEach(trackbr => {
19127
+ var _a;
19128
+
19129
+ let sdp = (_a = offer.sdp) !== null && _a !== void 0 ? _a : '';
19130
+ const sidIndex = sdp.search(new RegExp("msid.* ".concat(trackbr.sid)));
19131
+
19132
+ if (sidIndex < 0) {
19133
+ return;
19134
+ }
19135
+
19136
+ const mlineStart = sdp.substring(0, sidIndex).lastIndexOf('m=');
19137
+ const mlineEnd = sdp.indexOf('m=', sidIndex);
19138
+ const mediaSection = sdp.substring(mlineStart, mlineEnd);
19139
+ const mungedMediaSection = mediaSection.replace(new RegExp("a=rtpmap:(\\d+) ".concat(trackbr.codec, "/\\d+"), 'i'), '$'.concat("&\r\na=fmtp:$1 x-google-max-bitrate=".concat(trackbr.maxbr)));
19140
+ sdp = sdp.substring(0, mlineStart) + mungedMediaSection + sdp.substring(mlineEnd);
19141
+ offer.sdp = sdp;
19142
+ });
19143
+ this.trackBitrates = [];
19042
19144
  await this.pc.setLocalDescription(offer);
19043
19145
  this.onOffer(offer);
19044
19146
  }
19045
19147
 
19148
+ setTrackCodecBitrate(sid, codec, maxbr) {
19149
+ this.trackBitrates.push({
19150
+ sid,
19151
+ codec,
19152
+ maxbr
19153
+ });
19154
+ }
19155
+
19046
19156
  close() {
19047
19157
  this.pc.close();
19048
19158
  }
@@ -19422,23 +19532,9 @@ class RTCEngine extends events.exports.EventEmitter {
19422
19532
  const track = ev.stream.getTracks()[0];
19423
19533
  this.emit(EngineEvent.MediaTrackAdded, track, ev.stream);
19424
19534
  };
19425
- } // data channels
19426
-
19427
-
19428
- this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, {
19429
- // will drop older packets that arrive
19430
- ordered: true,
19431
- maxRetransmits: 0
19432
- });
19433
- this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, {
19434
- ordered: true
19435
- }); // also handle messages over the pub channel, for backwards compatibility
19436
-
19437
- this.lossyDC.onmessage = this.handleDataMessage;
19438
- this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19535
+ }
19439
19536
 
19440
- this.lossyDC.onerror = this.handleDataError;
19441
- this.reliableDC.onerror = this.handleDataError; // configure signaling client
19537
+ this.createDataChannels(); // configure signaling client
19442
19538
 
19443
19539
  this.client.onAnswer = async sd => {
19444
19540
  if (!this.publisher) {
@@ -19523,6 +19619,39 @@ class RTCEngine extends events.exports.EventEmitter {
19523
19619
  };
19524
19620
  }
19525
19621
 
19622
+ createDataChannels() {
19623
+ if (!this.publisher) {
19624
+ return;
19625
+ } // clear old data channel callbacks if recreate
19626
+
19627
+
19628
+ if (this.lossyDC) {
19629
+ this.lossyDC.onmessage = null;
19630
+ this.lossyDC.onerror = null;
19631
+ }
19632
+
19633
+ if (this.reliableDC) {
19634
+ this.reliableDC.onmessage = null;
19635
+ this.reliableDC.onerror = null;
19636
+ } // create data channels
19637
+
19638
+
19639
+ this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, {
19640
+ // will drop older packets that arrive
19641
+ ordered: true,
19642
+ maxRetransmits: 0
19643
+ });
19644
+ this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, {
19645
+ ordered: true
19646
+ }); // also handle messages over the pub channel, for backwards compatibility
19647
+
19648
+ this.lossyDC.onmessage = this.handleDataMessage;
19649
+ this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19650
+
19651
+ this.lossyDC.onerror = this.handleDataError;
19652
+ this.reliableDC.onerror = this.handleDataError;
19653
+ }
19654
+
19526
19655
  async restartConnection() {
19527
19656
  var _a, _b;
19528
19657
 
@@ -19562,6 +19691,8 @@ class RTCEngine extends events.exports.EventEmitter {
19562
19691
  }
19563
19692
 
19564
19693
  async resumeConnection() {
19694
+ var _a;
19695
+
19565
19696
  if (!this.url || !this.token) {
19566
19697
  // permanent failure, don't attempt reconnection
19567
19698
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
@@ -19594,7 +19725,13 @@ class RTCEngine extends events.exports.EventEmitter {
19594
19725
  }
19595
19726
 
19596
19727
  await this.waitForPCConnected();
19597
- this.client.setReconnected(); // resume success
19728
+ this.client.setReconnected(); // recreate publish datachannel if it's id is null
19729
+ // (for safari https://bugs.webkit.org/show_bug.cgi?id=184688)
19730
+
19731
+ if (((_a = this.reliableDC) === null || _a === void 0 ? void 0 : _a.readyState) === 'open' && this.reliableDC.id === null) {
19732
+ this.createDataChannels();
19733
+ } // resume success
19734
+
19598
19735
 
19599
19736
  this.emit(EngineEvent.Resumed);
19600
19737
  }
@@ -19964,11 +20101,15 @@ class Room extends events.exports.EventEmitter {
19964
20101
  */
19965
20102
 
19966
20103
 
19967
- this.disconnect = function () {
20104
+ this.disconnect = async function () {
19968
20105
  let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
19969
20106
 
19970
20107
  var _a, _b;
19971
20108
 
20109
+ livekitLogger.info('disconnect from room', {
20110
+ identity: _this.localParticipant.identity
20111
+ });
20112
+
19972
20113
  if (_this.state === ConnectionState.Connecting) {
19973
20114
  // try aborting pending connection attempt
19974
20115
  livekitLogger.warn('abort connection attempt');
@@ -19978,7 +20119,7 @@ class Room extends events.exports.EventEmitter {
19978
20119
 
19979
20120
 
19980
20121
  if ((_b = _this.engine) === null || _b === void 0 ? void 0 : _b.client.isConnected) {
19981
- _this.engine.client.sendLeave();
20122
+ await _this.engine.client.sendLeave();
19982
20123
  } // close engine (also closes client)
19983
20124
 
19984
20125
 
@@ -19986,7 +20127,7 @@ class Room extends events.exports.EventEmitter {
19986
20127
  _this.engine.close();
19987
20128
  }
19988
20129
 
19989
- _this.handleDisconnect(stopTracks);
20130
+ _this.handleDisconnect(stopTracks, DisconnectReason.CLIENT_INITIATED);
19990
20131
  /* @ts-ignore */
19991
20132
 
19992
20133
 
@@ -20183,9 +20324,7 @@ class Room extends events.exports.EventEmitter {
20183
20324
  return;
20184
20325
  }
20185
20326
 
20186
- pub._allowed = update.allowed;
20187
- participant.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
20188
- this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
20327
+ pub.setAllowed(update.allowed);
20189
20328
  };
20190
20329
 
20191
20330
  this.handleDataPacket = (userPacket, kind) => {
@@ -20528,6 +20667,10 @@ class Room extends events.exports.EventEmitter {
20528
20667
 
20529
20668
  var _a;
20530
20669
 
20670
+ if (this.state === ConnectionState.Disconnected) {
20671
+ return;
20672
+ }
20673
+
20531
20674
  this.participants.forEach(p => {
20532
20675
  p.tracks.forEach(pub => {
20533
20676
  p.unpublishTrack(pub.trackSid);
@@ -20545,6 +20688,9 @@ class Room extends events.exports.EventEmitter {
20545
20688
  (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
20546
20689
  }
20547
20690
  });
20691
+ this.localParticipant.tracks.clear();
20692
+ this.localParticipant.videoTracks.clear();
20693
+ this.localParticipant.audioTracks.clear();
20548
20694
  this.participants.clear();
20549
20695
  this.activeSpeakers = [];
20550
20696
 
@@ -20646,6 +20792,8 @@ class Room extends events.exports.EventEmitter {
20646
20792
  this.emitWhenConnected(RoomEvent.ConnectionQualityChanged, quality, participant);
20647
20793
  }).on(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions => {
20648
20794
  this.emitWhenConnected(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
20795
+ }).on(ParticipantEvent.TrackSubscriptionPermissionChanged, (pub, status) => {
20796
+ this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
20649
20797
  }); // update info at the end after callbacks have been set up
20650
20798
 
20651
20799
  if (info) {