livekit-client 1.1.9 → 1.2.0

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.
@@ -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.0";
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
  });
@@ -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();
@@ -19422,23 +19495,9 @@ class RTCEngine extends events.exports.EventEmitter {
19422
19495
  const track = ev.stream.getTracks()[0];
19423
19496
  this.emit(EngineEvent.MediaTrackAdded, track, ev.stream);
19424
19497
  };
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
19498
+ }
19436
19499
 
19437
- this.lossyDC.onmessage = this.handleDataMessage;
19438
- this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19439
-
19440
- this.lossyDC.onerror = this.handleDataError;
19441
- this.reliableDC.onerror = this.handleDataError; // configure signaling client
19500
+ this.createDataChannels(); // configure signaling client
19442
19501
 
19443
19502
  this.client.onAnswer = async sd => {
19444
19503
  if (!this.publisher) {
@@ -19523,6 +19582,39 @@ class RTCEngine extends events.exports.EventEmitter {
19523
19582
  };
19524
19583
  }
19525
19584
 
19585
+ createDataChannels() {
19586
+ if (!this.publisher) {
19587
+ return;
19588
+ } // clear old data channel callbacks if recreate
19589
+
19590
+
19591
+ if (this.lossyDC) {
19592
+ this.lossyDC.onmessage = null;
19593
+ this.lossyDC.onerror = null;
19594
+ }
19595
+
19596
+ if (this.reliableDC) {
19597
+ this.reliableDC.onmessage = null;
19598
+ this.reliableDC.onerror = null;
19599
+ } // create data channels
19600
+
19601
+
19602
+ this.lossyDC = this.publisher.pc.createDataChannel(lossyDataChannel, {
19603
+ // will drop older packets that arrive
19604
+ ordered: true,
19605
+ maxRetransmits: 0
19606
+ });
19607
+ this.reliableDC = this.publisher.pc.createDataChannel(reliableDataChannel, {
19608
+ ordered: true
19609
+ }); // also handle messages over the pub channel, for backwards compatibility
19610
+
19611
+ this.lossyDC.onmessage = this.handleDataMessage;
19612
+ this.reliableDC.onmessage = this.handleDataMessage; // handle datachannel errors
19613
+
19614
+ this.lossyDC.onerror = this.handleDataError;
19615
+ this.reliableDC.onerror = this.handleDataError;
19616
+ }
19617
+
19526
19618
  async restartConnection() {
19527
19619
  var _a, _b;
19528
19620
 
@@ -19562,6 +19654,8 @@ class RTCEngine extends events.exports.EventEmitter {
19562
19654
  }
19563
19655
 
19564
19656
  async resumeConnection() {
19657
+ var _a;
19658
+
19565
19659
  if (!this.url || !this.token) {
19566
19660
  // permanent failure, don't attempt reconnection
19567
19661
  throw new UnexpectedConnectionState('could not reconnect, url or token not saved');
@@ -19594,7 +19688,13 @@ class RTCEngine extends events.exports.EventEmitter {
19594
19688
  }
19595
19689
 
19596
19690
  await this.waitForPCConnected();
19597
- this.client.setReconnected(); // resume success
19691
+ this.client.setReconnected(); // recreate publish datachannel if it's id is null
19692
+ // (for safari https://bugs.webkit.org/show_bug.cgi?id=184688)
19693
+
19694
+ if (((_a = this.reliableDC) === null || _a === void 0 ? void 0 : _a.readyState) === 'open' && this.reliableDC.id === null) {
19695
+ this.createDataChannels();
19696
+ } // resume success
19697
+
19598
19698
 
19599
19699
  this.emit(EngineEvent.Resumed);
19600
19700
  }
@@ -19964,11 +20064,15 @@ class Room extends events.exports.EventEmitter {
19964
20064
  */
19965
20065
 
19966
20066
 
19967
- this.disconnect = function () {
20067
+ this.disconnect = async function () {
19968
20068
  let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
19969
20069
 
19970
20070
  var _a, _b;
19971
20071
 
20072
+ livekitLogger.info('disconnect from room', {
20073
+ identity: _this.localParticipant.identity
20074
+ });
20075
+
19972
20076
  if (_this.state === ConnectionState.Connecting) {
19973
20077
  // try aborting pending connection attempt
19974
20078
  livekitLogger.warn('abort connection attempt');
@@ -19978,7 +20082,7 @@ class Room extends events.exports.EventEmitter {
19978
20082
 
19979
20083
 
19980
20084
  if ((_b = _this.engine) === null || _b === void 0 ? void 0 : _b.client.isConnected) {
19981
- _this.engine.client.sendLeave();
20085
+ await _this.engine.client.sendLeave();
19982
20086
  } // close engine (also closes client)
19983
20087
 
19984
20088
 
@@ -19986,7 +20090,7 @@ class Room extends events.exports.EventEmitter {
19986
20090
  _this.engine.close();
19987
20091
  }
19988
20092
 
19989
- _this.handleDisconnect(stopTracks);
20093
+ _this.handleDisconnect(stopTracks, DisconnectReason.CLIENT_INITIATED);
19990
20094
  /* @ts-ignore */
19991
20095
 
19992
20096
 
@@ -20183,9 +20287,7 @@ class Room extends events.exports.EventEmitter {
20183
20287
  return;
20184
20288
  }
20185
20289
 
20186
- pub._allowed = update.allowed;
20187
- participant.emit(ParticipantEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus);
20188
- this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, pub.subscriptionStatus, participant);
20290
+ pub.setAllowed(update.allowed);
20189
20291
  };
20190
20292
 
20191
20293
  this.handleDataPacket = (userPacket, kind) => {
@@ -20528,6 +20630,10 @@ class Room extends events.exports.EventEmitter {
20528
20630
 
20529
20631
  var _a;
20530
20632
 
20633
+ if (this.state === ConnectionState.Disconnected) {
20634
+ return;
20635
+ }
20636
+
20531
20637
  this.participants.forEach(p => {
20532
20638
  p.tracks.forEach(pub => {
20533
20639
  p.unpublishTrack(pub.trackSid);
@@ -20545,6 +20651,9 @@ class Room extends events.exports.EventEmitter {
20545
20651
  (_b = pub.track) === null || _b === void 0 ? void 0 : _b.stop();
20546
20652
  }
20547
20653
  });
20654
+ this.localParticipant.tracks.clear();
20655
+ this.localParticipant.videoTracks.clear();
20656
+ this.localParticipant.audioTracks.clear();
20548
20657
  this.participants.clear();
20549
20658
  this.activeSpeakers = [];
20550
20659
 
@@ -20646,6 +20755,8 @@ class Room extends events.exports.EventEmitter {
20646
20755
  this.emitWhenConnected(RoomEvent.ConnectionQualityChanged, quality, participant);
20647
20756
  }).on(ParticipantEvent.ParticipantPermissionsChanged, prevPermissions => {
20648
20757
  this.emitWhenConnected(RoomEvent.ParticipantPermissionsChanged, prevPermissions, participant);
20758
+ }).on(ParticipantEvent.TrackSubscriptionPermissionChanged, (pub, status) => {
20759
+ this.emitWhenConnected(RoomEvent.TrackSubscriptionPermissionChanged, pub, status, participant);
20649
20760
  }); // update info at the end after callbacks have been set up
20650
20761
 
20651
20762
  if (info) {