livekit-client 1.15.3 → 1.15.5

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 (39) hide show
  1. package/dist/livekit-client.esm.mjs +91 -50
  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/proto/livekit_models_pb.d.ts +11 -1
  6. package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
  7. package/dist/src/room/RTCEngine.d.ts +4 -1
  8. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  9. package/dist/src/room/Room.d.ts.map +1 -1
  10. package/dist/src/room/events.d.ts +4 -1
  11. package/dist/src/room/events.d.ts.map +1 -1
  12. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  13. package/dist/src/room/participant/Participant.d.ts +6 -0
  14. package/dist/src/room/participant/Participant.d.ts.map +1 -1
  15. package/dist/src/room/stats.d.ts +1 -0
  16. package/dist/src/room/stats.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 +0 -3
  19. package/dist/src/room/track/Track.d.ts.map +1 -1
  20. package/dist/src/version.d.ts +1 -1
  21. package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +11 -1
  22. package/dist/ts4.2/src/room/RTCEngine.d.ts +4 -0
  23. package/dist/ts4.2/src/room/events.d.ts +4 -1
  24. package/dist/ts4.2/src/room/participant/Participant.d.ts +6 -0
  25. package/dist/ts4.2/src/room/stats.d.ts +1 -0
  26. package/dist/ts4.2/src/room/track/Track.d.ts +0 -3
  27. package/dist/ts4.2/src/version.d.ts +1 -1
  28. package/package.json +2 -2
  29. package/src/proto/livekit_models_pb.ts +15 -1
  30. package/src/proto/livekit_rtc_pb.ts +1 -1
  31. package/src/room/RTCEngine.ts +13 -0
  32. package/src/room/Room.ts +26 -8
  33. package/src/room/events.ts +3 -0
  34. package/src/room/participant/LocalParticipant.ts +4 -6
  35. package/src/room/participant/Participant.ts +11 -0
  36. package/src/room/stats.ts +2 -0
  37. package/src/room/track/RemoteVideoTrack.ts +8 -0
  38. package/src/room/track/Track.ts +34 -48
  39. package/src/version.ts +1 -1
@@ -3761,6 +3761,10 @@ var ConnectionQuality$1;
3761
3761
  * @generated from enum value: EXCELLENT = 2;
3762
3762
  */
3763
3763
  ConnectionQuality[ConnectionQuality["EXCELLENT"] = 2] = "EXCELLENT";
3764
+ /**
3765
+ * @generated from enum value: LOST = 3;
3766
+ */
3767
+ ConnectionQuality[ConnectionQuality["LOST"] = 3] = "LOST";
3764
3768
  })(ConnectionQuality$1 || (ConnectionQuality$1 = {}));
3765
3769
  // Retrieve enum metadata with: proto3.getEnumType(ConnectionQuality)
3766
3770
  proto3.util.setEnumType(ConnectionQuality$1, "livekit.ConnectionQuality", [{
@@ -3772,6 +3776,9 @@ proto3.util.setEnumType(ConnectionQuality$1, "livekit.ConnectionQuality", [{
3772
3776
  }, {
3773
3777
  no: 2,
3774
3778
  name: "EXCELLENT"
3779
+ }, {
3780
+ no: 3,
3781
+ name: "LOST"
3775
3782
  }]);
3776
3783
  /**
3777
3784
  * @generated from enum livekit.ClientConfigSetting
@@ -4203,6 +4210,12 @@ class ParticipantPermission extends Message {
4203
4210
  * @generated from field: bool can_update_metadata = 10;
4204
4211
  */
4205
4212
  this.canUpdateMetadata = false;
4213
+ /**
4214
+ * indicates that participant is an agent
4215
+ *
4216
+ * @generated from field: bool agent = 11;
4217
+ */
4218
+ this.agent = false;
4206
4219
  proto3.util.initPartial(data, this);
4207
4220
  }
4208
4221
  static fromBinary(bytes, options) {
@@ -4256,6 +4269,11 @@ ParticipantPermission.fields = proto3.util.newFieldList(() => [{
4256
4269
  name: "can_update_metadata",
4257
4270
  kind: "scalar",
4258
4271
  T: 8 /* ScalarType.BOOL */
4272
+ }, {
4273
+ no: 11,
4274
+ name: "agent",
4275
+ kind: "scalar",
4276
+ T: 8 /* ScalarType.BOOL */
4259
4277
  }]);
4260
4278
  /**
4261
4279
  * @generated from message livekit.ParticipantInfo
@@ -10396,6 +10414,9 @@ var EngineEvent;
10396
10414
  EngineEvent["ConnectionQualityUpdate"] = "connectionQualityUpdate";
10397
10415
  EngineEvent["SubscriptionError"] = "subscriptionError";
10398
10416
  EngineEvent["SubscriptionPermissionUpdate"] = "subscriptionPermissionUpdate";
10417
+ EngineEvent["RemoteMute"] = "remoteMute";
10418
+ EngineEvent["SubscribedQualityUpdate"] = "subscribedQualityUpdate";
10419
+ EngineEvent["LocalTrackUnpublished"] = "localTrackUnpublished";
10399
10420
  })(EngineEvent || (EngineEvent = {}));
10400
10421
  var TrackEvent;
10401
10422
  (function (TrackEvent) {
@@ -10565,10 +10586,10 @@ function getMatch(exp, ua) {
10565
10586
  return match && match.length >= id && match[id] || '';
10566
10587
  }
10567
10588
 
10568
- var version$1 = "1.15.3";
10589
+ var version$1 = "1.15.5";
10569
10590
 
10570
10591
  const version = version$1;
10571
- const protocolVersion = 10;
10592
+ const protocolVersion = 11;
10572
10593
 
10573
10594
  /**
10574
10595
  * Timers that can be overridden with platform specific implementations
@@ -12957,21 +12978,6 @@ class Track extends eventsExports.EventEmitter {
12957
12978
  this.handleAppVisibilityChanged();
12958
12979
  }
12959
12980
  };
12960
- this.handleElementSuspended = () => {
12961
- this.debouncedPlaybackStateChange(false);
12962
- };
12963
- this.handleElementPlay = () => {
12964
- this.debouncedPlaybackStateChange(true);
12965
- };
12966
- this.debouncedPlaybackStateChange = r(allowed => {
12967
- // we debounce this as Safari triggers both `playing` and `suspend` shortly after one another
12968
- // in order not to raise the wrong event, we debounce the call to make sure we only emit the correct status
12969
- if (this.kind === Track.Kind.Audio) {
12970
- this.emit(allowed ? TrackEvent.AudioPlaybackStarted : TrackEvent.AudioPlaybackFailed);
12971
- } else if (this.kind === Track.Kind.Video) {
12972
- this.emit(allowed ? TrackEvent.VideoPlaybackStarted : TrackEvent.VideoPlaybackFailed);
12973
- }
12974
- }, 300);
12975
12981
  this.setMaxListeners(100);
12976
12982
  this.kind = kind;
12977
12983
  this._mediaStreamTrack = mediaTrack;
@@ -13019,9 +13025,6 @@ class Track extends eventsExports.EventEmitter {
13019
13025
  }
13020
13026
  if (!this.attachedElements.includes(element)) {
13021
13027
  this.attachedElements.push(element);
13022
- // listen to suspend events in order to detect auto playback issues
13023
- element.addEventListener('suspend', this.handleElementSuspended);
13024
- element.addEventListener('playing', this.handleElementPlay);
13025
13028
  }
13026
13029
  // even if we believe it's already attached to the element, it's possible
13027
13030
  // the element's srcObject was set to something else out of band.
@@ -13029,20 +13032,27 @@ class Track extends eventsExports.EventEmitter {
13029
13032
  attachToElement(this.mediaStreamTrack, element);
13030
13033
  // handle auto playback failures
13031
13034
  const allMediaStreamTracks = element.srcObject.getTracks();
13032
- if (allMediaStreamTracks.some(tr => tr.kind === 'audio')) {
13033
- // manually play audio to detect audio playback status
13034
- element.play().then(() => {
13035
- this.emit(TrackEvent.AudioPlaybackStarted);
13036
- }).catch(e => {
13037
- // If audio playback isn't allowed make sure we still play back the video
13038
- if (element && allMediaStreamTracks.some(tr => tr.kind === 'video') && e.name === 'NotAllowedError') {
13039
- element.muted = true;
13040
- element.play().catch(() => {
13041
- // catch for Safari, exceeded options at this point to automatically play the media element
13042
- });
13043
- }
13044
- });
13045
- }
13035
+ const hasAudio = allMediaStreamTracks.some(tr => tr.kind === 'audio');
13036
+ // manually play media to detect auto playback status
13037
+ element.play().then(() => {
13038
+ this.emit(hasAudio ? TrackEvent.AudioPlaybackStarted : TrackEvent.VideoPlaybackStarted);
13039
+ }).catch(e => {
13040
+ if (e.name === 'NotAllowedError') {
13041
+ this.emit(hasAudio ? TrackEvent.AudioPlaybackFailed : TrackEvent.VideoPlaybackFailed, e);
13042
+ } else if (e.name === 'AbortError') {
13043
+ // commonly triggered by another `play` request, only log for debugging purposes
13044
+ livekitLogger.debug("".concat(hasAudio ? 'audio' : 'video', " playback aborted, likely due to new play request"));
13045
+ } else {
13046
+ livekitLogger.warn("could not playback ".concat(hasAudio ? 'audio' : 'video'), e);
13047
+ }
13048
+ // If audio playback isn't allowed make sure we still play back the video
13049
+ if (hasAudio && element && allMediaStreamTracks.some(tr => tr.kind === 'video') && e.name === 'NotAllowedError') {
13050
+ element.muted = true;
13051
+ element.play().catch(() => {
13052
+ // catch for Safari, exceeded options at this point to automatically play the media element
13053
+ });
13054
+ }
13055
+ });
13046
13056
  this.emit(TrackEvent.ElementAttached, element);
13047
13057
  return element;
13048
13058
  }
@@ -13055,8 +13065,6 @@ class Track extends eventsExports.EventEmitter {
13055
13065
  if (idx >= 0) {
13056
13066
  this.attachedElements.splice(idx, 1);
13057
13067
  this.recycleElement(element);
13058
- element.removeEventListener('suspend', this.handleElementSuspended);
13059
- element.removeEventListener('playing', this.handleElementPlay);
13060
13068
  this.emit(TrackEvent.ElementDetached, element);
13061
13069
  }
13062
13070
  return element;
@@ -13066,8 +13074,6 @@ class Track extends eventsExports.EventEmitter {
13066
13074
  detachTrack(this.mediaStreamTrack, elm);
13067
13075
  detached.push(elm);
13068
13076
  this.recycleElement(elm);
13069
- elm.removeEventListener('suspend', this.handleElementSuspended);
13070
- elm.removeEventListener('playing', this.handleElementPlay);
13071
13077
  this.emit(TrackEvent.ElementDetached, elm);
13072
13078
  });
13073
13079
  // remove all tracks
@@ -13176,7 +13182,7 @@ function attachToElement(track, element) {
13176
13182
  // when the window is backgrounded before the first frame is drawn
13177
13183
  // manually calling play here seems to fix that
13178
13184
  element.play().catch(() => {
13179
- /** do nothing, we watch the `suspended` event do deal with these failures */
13185
+ /** do nothing */
13180
13186
  });
13181
13187
  }, 0);
13182
13188
  }
@@ -17242,6 +17248,12 @@ class RTCEngine extends eventsExports.EventEmitter {
17242
17248
  this.client.onTokenRefresh = token => {
17243
17249
  this.token = token;
17244
17250
  };
17251
+ this.client.onRemoteMuteChanged = (trackSid, muted) => {
17252
+ this.emit(EngineEvent.RemoteMute, trackSid, muted);
17253
+ };
17254
+ this.client.onSubscribedQualityUpdate = update => {
17255
+ this.emit(EngineEvent.SubscribedQualityUpdate, update);
17256
+ };
17245
17257
  this.client.onClose = () => {
17246
17258
  this.handleDisconnect('signal', ReconnectReason.RR_SIGNAL_DISCONNECTED);
17247
17259
  };
@@ -19369,8 +19381,11 @@ class RemoteVideoTrack extends RemoteTrack {
19369
19381
  }
19370
19382
  const stats = yield this.receiver.getStats();
19371
19383
  let receiverStats;
19384
+ let codecID = '';
19385
+ let codecs = new Map();
19372
19386
  stats.forEach(v => {
19373
19387
  if (v.type === 'inbound-rtp') {
19388
+ codecID = v.codecId;
19374
19389
  receiverStats = {
19375
19390
  type: 'video',
19376
19391
  framesDecoded: v.framesDecoded,
@@ -19388,8 +19403,13 @@ class RemoteVideoTrack extends RemoteTrack {
19388
19403
  bytesReceived: v.bytesReceived,
19389
19404
  decoderImplementation: v.decoderImplementation
19390
19405
  };
19406
+ } else if (v.type === 'codec') {
19407
+ codecs.set(v.id, v);
19391
19408
  }
19392
19409
  });
19410
+ if (receiverStats && codecID !== '' && codecs.get(codecID)) {
19411
+ receiverStats.mimeType = codecs.get(codecID).mimeType;
19412
+ }
19393
19413
  return receiverStats;
19394
19414
  });
19395
19415
  }
@@ -19727,6 +19747,11 @@ var ConnectionQuality;
19727
19747
  ConnectionQuality["Excellent"] = "excellent";
19728
19748
  ConnectionQuality["Good"] = "good";
19729
19749
  ConnectionQuality["Poor"] = "poor";
19750
+ /**
19751
+ * Indicates that a participant has temporarily (or permanently) lost connection to LiveKit.
19752
+ * For permanent disconnection a `ParticipantDisconnected` event will be emitted after a timeout
19753
+ */
19754
+ ConnectionQuality["Lost"] = "lost";
19730
19755
  ConnectionQuality["Unknown"] = "unknown";
19731
19756
  })(ConnectionQuality || (ConnectionQuality = {}));
19732
19757
  function qualityFromProto(q) {
@@ -19737,6 +19762,8 @@ function qualityFromProto(q) {
19737
19762
  return ConnectionQuality.Good;
19738
19763
  case ConnectionQuality$1.POOR:
19739
19764
  return ConnectionQuality.Poor;
19765
+ case ConnectionQuality$1.LOST:
19766
+ return ConnectionQuality.Lost;
19740
19767
  default:
19741
19768
  return ConnectionQuality.Unknown;
19742
19769
  }
@@ -19745,6 +19772,10 @@ class Participant extends eventsExports.EventEmitter {
19745
19772
  get isEncrypted() {
19746
19773
  return this.tracks.size > 0 && Array.from(this.tracks.values()).every(tr => tr.isEncrypted);
19747
19774
  }
19775
+ get isAgent() {
19776
+ var _a, _b;
19777
+ return (_b = (_a = this.permissions) === null || _a === void 0 ? void 0 : _a.agent) !== null && _b !== void 0 ? _b : false;
19778
+ }
19748
19779
  /** @internal */
19749
19780
  constructor(sid, identity, name, metadata) {
19750
19781
  super();
@@ -20635,7 +20666,7 @@ class LocalParticipant extends Participant {
20635
20666
  */
20636
20667
  setupEngine(engine) {
20637
20668
  this.engine = engine;
20638
- this.engine.client.onRemoteMuteChanged = (trackSid, muted) => {
20669
+ this.engine.on(EngineEvent.RemoteMute, (trackSid, muted) => {
20639
20670
  const pub = this.tracks.get(trackSid);
20640
20671
  if (!pub || !pub.track) {
20641
20672
  return;
@@ -20645,10 +20676,8 @@ class LocalParticipant extends Participant {
20645
20676
  } else {
20646
20677
  pub.unmute();
20647
20678
  }
20648
- };
20649
- this.engine.client.onSubscribedQualityUpdate = this.handleSubscribedQualityUpdate;
20650
- this.engine.client.onLocalTrackUnpublished = this.handleLocalTrackUnpublished;
20651
- this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.Disconnected, this.handleDisconnected);
20679
+ });
20680
+ this.engine.on(EngineEvent.Connected, this.handleReconnected).on(EngineEvent.SignalRestarted, this.handleReconnected).on(EngineEvent.SignalResumed, this.handleReconnected).on(EngineEvent.Restarting, this.handleReconnecting).on(EngineEvent.Resuming, this.handleReconnecting).on(EngineEvent.LocalTrackUnpublished, this.handleLocalTrackUnpublished).on(EngineEvent.SubscribedQualityUpdate, this.handleSubscribedQualityUpdate).on(EngineEvent.Disconnected, this.handleDisconnected);
20652
20681
  }
20653
20682
  /**
20654
20683
  * Sets and updates the metadata of the local participant.
@@ -21808,18 +21837,26 @@ class Room extends eventsExports.EventEmitter {
21808
21837
  }
21809
21838
  });
21810
21839
  this.startVideo = () => __awaiter(this, void 0, void 0, function* () {
21840
+ const elements = [];
21811
21841
  for (const p of this.participants.values()) {
21812
21842
  p.videoTracks.forEach(tr => {
21813
21843
  var _a;
21814
21844
  (_a = tr.track) === null || _a === void 0 ? void 0 : _a.attachedElements.forEach(el => {
21815
- el.play().catch(e => {
21816
- if (e.name === 'NotAllowedError') {
21817
- livekitLogger.warn('Resuming video playback failed, make sure you call `startVideo` directly in a user gesture handler');
21818
- }
21819
- });
21845
+ if (!elements.includes(el)) {
21846
+ elements.push(el);
21847
+ }
21820
21848
  });
21821
21849
  });
21822
21850
  }
21851
+ yield Promise.all(elements.map(el => el.play())).then(() => {
21852
+ this.handleVideoPlaybackStarted();
21853
+ }).catch(e => {
21854
+ if (e.name === 'NotAllowedError') {
21855
+ this.handleVideoPlaybackFailed();
21856
+ } else {
21857
+ livekitLogger.warn('Resuming video playback failed, make sure you call `startVideo` directly in a user gesture handler');
21858
+ }
21859
+ });
21823
21860
  });
21824
21861
  this.handleRestarting = () => {
21825
21862
  this.clearConnectionReconcile();
@@ -22126,7 +22163,7 @@ class Room extends eventsExports.EventEmitter {
22126
22163
  this.localParticipant.activeDeviceMap.set('audioinput', unwrapConstraint(this.options.audioCaptureDefaults.deviceId));
22127
22164
  }
22128
22165
  if ((_a = this.options.audioOutput) === null || _a === void 0 ? void 0 : _a.deviceId) {
22129
- this.switchActiveDevice('audiooutput', unwrapConstraint(this.options.audioOutput.deviceId));
22166
+ this.switchActiveDevice('audiooutput', unwrapConstraint(this.options.audioOutput.deviceId)).catch(e => livekitLogger.warn("Could not set audio output: ".concat(e.message)));
22130
22167
  }
22131
22168
  if (this.options.e2ee) {
22132
22169
  this.setupE2EE();
@@ -22643,6 +22680,7 @@ class Room extends eventsExports.EventEmitter {
22643
22680
  });
22644
22681
  }
22645
22682
  createParticipant(id, info) {
22683
+ var _a;
22646
22684
  let participant;
22647
22685
  if (info) {
22648
22686
  participant = RemoteParticipant.fromParticipantInfo(this.engine.client, info);
@@ -22652,6 +22690,9 @@ class Room extends eventsExports.EventEmitter {
22652
22690
  if (this.options.expWebAudioMix) {
22653
22691
  participant.setAudioContext(this.audioContext);
22654
22692
  }
22693
+ if ((_a = this.options.audioOutput) === null || _a === void 0 ? void 0 : _a.deviceId) {
22694
+ participant.setAudioOutput(this.options.audioOutput).catch(e => livekitLogger.warn("Could not set audio output: ".concat(e.message)));
22695
+ }
22655
22696
  return participant;
22656
22697
  }
22657
22698
  getOrCreateParticipant(id, info) {