livekit-client 1.11.1 → 1.11.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.
@@ -14187,7 +14187,7 @@ function getMatch(exp, ua) {
14187
14187
  return match && match.length >= id && match[id] || '';
14188
14188
  }
14189
14189
 
14190
- var version$1 = "1.11.1";
14190
+ var version$1 = "1.11.2";
14191
14191
 
14192
14192
  const version = version$1;
14193
14193
  const protocolVersion = 9;
@@ -14636,6 +14636,27 @@ class Mutex {
14636
14636
  return willUnlock;
14637
14637
  }
14638
14638
  }
14639
+ function unwrapConstraint(constraint) {
14640
+ if (typeof constraint === 'string') {
14641
+ return constraint;
14642
+ }
14643
+ if (Array.isArray(constraint)) {
14644
+ return constraint[0];
14645
+ }
14646
+ if (constraint.exact) {
14647
+ if (Array.isArray(constraint.exact)) {
14648
+ return constraint.exact[0];
14649
+ }
14650
+ return constraint.exact;
14651
+ }
14652
+ if (constraint.ideal) {
14653
+ if (Array.isArray(constraint.ideal)) {
14654
+ return constraint.ideal[0];
14655
+ }
14656
+ return constraint.ideal;
14657
+ }
14658
+ throw Error('could not unwrap constraint');
14659
+ }
14639
14660
 
14640
14661
  var QueueTaskStatus;
14641
14662
  (function (QueueTaskStatus) {
@@ -16734,6 +16755,11 @@ var RoomEvent;
16734
16755
  * args: (isLow: boolean, kind: [[DataPacket_Kind]])
16735
16756
  */
16736
16757
  RoomEvent["DCBufferStatusChanged"] = "dcBufferStatusChanged";
16758
+ /**
16759
+ * Triggered by a call to room.switchActiveDevice
16760
+ * args: (kind: MediaDeviceKind, deviceId: string)
16761
+ */
16762
+ RoomEvent["ActiveDeviceChanged"] = "activeDeviceChanged";
16737
16763
  })(RoomEvent || (RoomEvent = {}));
16738
16764
  var ParticipantEvent;
16739
16765
  (function (ParticipantEvent) {
@@ -18564,7 +18590,7 @@ class LocalTrack extends Track {
18564
18590
  throw new TrackInvalidError('unable to replace an unpublished track');
18565
18591
  }
18566
18592
  livekitLogger.debug('replace MediaStreamTrack');
18567
- this.setMediaStreamTrack(track);
18593
+ yield this.setMediaStreamTrack(track);
18568
18594
  // this must be synced *after* setting mediaStreamTrack above, since it relies
18569
18595
  // on the previous state in order to cleanup
18570
18596
  this.providedByUser = userProvidedTrack;
@@ -18604,7 +18630,7 @@ class LocalTrack extends Track {
18604
18630
  const newTrack = mediaStream.getTracks()[0];
18605
18631
  newTrack.addEventListener('ended', this.handleEnded);
18606
18632
  livekitLogger.debug('re-acquired MediaStreamTrack');
18607
- this.setMediaStreamTrack(newTrack);
18633
+ yield this.setMediaStreamTrack(newTrack);
18608
18634
  this.constraints = constraints;
18609
18635
  if (this.processor) {
18610
18636
  const processor = this.processor;
@@ -18766,12 +18792,13 @@ class LocalAudioTrack extends LocalTrack {
18766
18792
  setDeviceId(deviceId) {
18767
18793
  return __awaiter(this, void 0, void 0, function* () {
18768
18794
  if (this.constraints.deviceId === deviceId) {
18769
- return;
18795
+ return true;
18770
18796
  }
18771
18797
  this.constraints.deviceId = deviceId;
18772
18798
  if (!this.isMuted) {
18773
18799
  yield this.restartTrack();
18774
18800
  }
18801
+ return unwrapConstraint(deviceId) === this.mediaStreamTrack.getSettings().deviceId;
18775
18802
  });
18776
18803
  }
18777
18804
  mute() {
@@ -19359,8 +19386,8 @@ class LocalVideoTrack extends LocalTrack {
19359
19386
  }
19360
19387
  setDeviceId(deviceId) {
19361
19388
  return __awaiter(this, void 0, void 0, function* () {
19362
- if (this.constraints.deviceId === deviceId) {
19363
- return;
19389
+ if (this.constraints.deviceId === deviceId && this._mediaStreamTrack.getSettings().deviceId === unwrapConstraint(deviceId)) {
19390
+ return true;
19364
19391
  }
19365
19392
  this.constraints.deviceId = deviceId;
19366
19393
  // when video is muted, underlying media stream track is stopped and
@@ -19368,6 +19395,7 @@ class LocalVideoTrack extends LocalTrack {
19368
19395
  if (!this.isMuted) {
19369
19396
  yield this.restartTrack();
19370
19397
  }
19398
+ return unwrapConstraint(deviceId) === this._mediaStreamTrack.getSettings().deviceId;
19371
19399
  });
19372
19400
  }
19373
19401
  restartTrack(options) {
@@ -19862,7 +19890,6 @@ class RemoteVideoTrack extends RemoteTrack {
19862
19890
  constructor(mediaTrack, sid, receiver, adaptiveStreamSettings) {
19863
19891
  super(mediaTrack, sid, Track.Kind.Video, receiver);
19864
19892
  this.elementInfos = [];
19865
- this.isObserved = false;
19866
19893
  this.monitorReceiver = () => __awaiter(this, void 0, void 0, function* () {
19867
19894
  if (!this.receiver) {
19868
19895
  this._currentBitrate = 0;
@@ -19882,10 +19909,10 @@ class RemoteVideoTrack extends RemoteTrack {
19882
19909
  get isAdaptiveStream() {
19883
19910
  return this.adaptiveStreamSettings !== undefined;
19884
19911
  }
19912
+ /**
19913
+ * Note: When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start
19914
+ */
19885
19915
  get mediaStreamTrack() {
19886
- if (this.isAdaptiveStream && !this.isObserved) {
19887
- livekitLogger.warn('When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start');
19888
- }
19889
19916
  return this._mediaStreamTrack;
19890
19917
  }
19891
19918
  /** @internal */
@@ -19934,7 +19961,6 @@ class RemoteVideoTrack extends RemoteTrack {
19934
19961
  // the tab comes into focus for the first time.
19935
19962
  this.debouncedHandleResize();
19936
19963
  this.updateVisibility();
19937
- this.isObserved = true;
19938
19964
  } else {
19939
19965
  livekitLogger.warn('visibility resize observer not triggered');
19940
19966
  }
@@ -22062,6 +22088,7 @@ class Room extends EventEmitter {
22062
22088
  */
22063
22089
  constructor(options) {
22064
22090
  var _this;
22091
+ var _a;
22065
22092
  super();
22066
22093
  _this = this;
22067
22094
  this.state = ConnectionState.Disconnected;
@@ -22087,7 +22114,7 @@ class Room extends EventEmitter {
22087
22114
  this.setAndEmitConnectionState(ConnectionState.Connecting);
22088
22115
  const urlProvider = new RegionUrlProvider(url, token);
22089
22116
  const connectFn = (resolve, reject, regionUrl) => __awaiter(this, void 0, void 0, function* () {
22090
- var _a;
22117
+ var _b;
22091
22118
  if (this.abortController) {
22092
22119
  this.abortController.abort();
22093
22120
  }
@@ -22102,7 +22129,7 @@ class Room extends EventEmitter {
22102
22129
  if (isCloud(new URL(url)) && e instanceof ConnectionError && e.reason !== 3 /* ConnectionErrorReason.Cancelled */) {
22103
22130
  let nextUrl = null;
22104
22131
  try {
22105
- nextUrl = yield urlProvider.getNextBestRegionUrl((_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal);
22132
+ nextUrl = yield urlProvider.getNextBestRegionUrl((_b = this.abortController) === null || _b === void 0 ? void 0 : _b.signal);
22106
22133
  } catch (error) {
22107
22134
  if (error instanceof ConnectionError && (error.status === 401 || error.reason === 3 /* ConnectionErrorReason.Cancelled */)) {
22108
22135
  reject(error);
@@ -22164,7 +22191,7 @@ class Room extends EventEmitter {
22164
22191
  }
22165
22192
  };
22166
22193
  this.attemptConnection = (url, token, opts, abortController) => __awaiter(this, void 0, void 0, function* () {
22167
- var _b;
22194
+ var _c;
22168
22195
  if (this.state === ConnectionState.Reconnecting) {
22169
22196
  livekitLogger.info('Reconnection attempt replaced by new connection attempt');
22170
22197
  // make sure we close and recreate the existing engine in order to get rid of any potentially ongoing reconnection attempts
@@ -22223,7 +22250,7 @@ class Room extends EventEmitter {
22223
22250
  }
22224
22251
  if (isWeb()) {
22225
22252
  document.addEventListener('freeze', this.onPageLeave);
22226
- (_b = navigator.mediaDevices) === null || _b === void 0 ? void 0 : _b.addEventListener('devicechange', this.handleDeviceChange);
22253
+ (_c = navigator.mediaDevices) === null || _c === void 0 ? void 0 : _c.addEventListener('devicechange', this.handleDeviceChange);
22227
22254
  }
22228
22255
  this.setAndEmitConnectionState(ConnectionState.Connected);
22229
22256
  this.emit(RoomEvent.Connected);
@@ -22235,7 +22262,7 @@ class Room extends EventEmitter {
22235
22262
  this.disconnect = function () {
22236
22263
  let stopTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
22237
22264
  return __awaiter(_this, void 0, void 0, function* () {
22238
- var _c, _d, _e, _f;
22265
+ var _d, _e, _f, _g;
22239
22266
  const unlock = yield this.disconnectLock.lock();
22240
22267
  try {
22241
22268
  if (this.state === ConnectionState.Disconnected) {
@@ -22248,13 +22275,13 @@ class Room extends EventEmitter {
22248
22275
  if (this.state === ConnectionState.Connecting || this.state === ConnectionState.Reconnecting) {
22249
22276
  // try aborting pending connection attempt
22250
22277
  livekitLogger.warn('abort connection attempt');
22251
- (_c = this.abortController) === null || _c === void 0 ? void 0 : _c.abort();
22278
+ (_d = this.abortController) === null || _d === void 0 ? void 0 : _d.abort();
22252
22279
  // in case the abort controller didn't manage to cancel the connection attempt, reject the connect promise explicitly
22253
- (_e = (_d = this.connectFuture) === null || _d === void 0 ? void 0 : _d.reject) === null || _e === void 0 ? void 0 : _e.call(_d, new ConnectionError('Client initiated disconnect'));
22280
+ (_f = (_e = this.connectFuture) === null || _e === void 0 ? void 0 : _e.reject) === null || _f === void 0 ? void 0 : _f.call(_e, new ConnectionError('Client initiated disconnect'));
22254
22281
  this.connectFuture = undefined;
22255
22282
  }
22256
22283
  // send leave
22257
- if ((_f = this.engine) === null || _f === void 0 ? void 0 : _f.client.isConnected) {
22284
+ if ((_g = this.engine) === null || _g === void 0 ? void 0 : _g.client.isConnected) {
22258
22285
  yield this.engine.client.sendLeave();
22259
22286
  }
22260
22287
  // close engine (also closes client)
@@ -22324,7 +22351,7 @@ class Room extends EventEmitter {
22324
22351
  livekitLogger.debug("fully reconnected to server", {
22325
22352
  region: joinResponse.serverRegion
22326
22353
  });
22327
- } catch (_g) {
22354
+ } catch (_h) {
22328
22355
  // reconnection failed, handleDisconnect is being invoked already, just return here
22329
22356
  return;
22330
22357
  }
@@ -22549,6 +22576,16 @@ class Room extends EventEmitter {
22549
22576
  this.options.publishDefaults = Object.assign(Object.assign({}, publishDefaults), options === null || options === void 0 ? void 0 : options.publishDefaults);
22550
22577
  this.maybeCreateEngine();
22551
22578
  this.disconnectLock = new Mutex();
22579
+ this.activeDeviceMap = new Map();
22580
+ if (this.options.videoCaptureDefaults.deviceId) {
22581
+ this.activeDeviceMap.set('videoinput', unwrapConstraint(this.options.videoCaptureDefaults.deviceId));
22582
+ }
22583
+ if (this.options.audioCaptureDefaults.deviceId) {
22584
+ this.activeDeviceMap.set('audioinput', unwrapConstraint(this.options.audioCaptureDefaults.deviceId));
22585
+ }
22586
+ if ((_a = this.options.audioOutput) === null || _a === void 0 ? void 0 : _a.deviceId) {
22587
+ this.switchActiveDevice('audiooutput', unwrapConstraint(this.options.audioOutput.deviceId));
22588
+ }
22552
22589
  this.localParticipant = new LocalParticipant('', '', this.engine, this.options);
22553
22590
  }
22554
22591
  /**
@@ -22814,15 +22851,16 @@ class Room extends EventEmitter {
22814
22851
  }
22815
22852
  /**
22816
22853
  * Returns the active audio output device used in this room.
22817
- *
22818
- * Note: to get the active `audioinput` or `videoinput` use [[LocalTrack.getDeviceId()]]
22819
- *
22820
22854
  * @return the previously successfully set audio output device ID or an empty string if the default device is used.
22855
+ * @deprecated use `getActiveDevice('audiooutput')` instead
22821
22856
  */
22822
22857
  getActiveAudioOutputDevice() {
22823
22858
  var _a, _b;
22824
22859
  return (_b = (_a = this.options.audioOutput) === null || _a === void 0 ? void 0 : _a.deviceId) !== null && _b !== void 0 ? _b : '';
22825
22860
  }
22861
+ getActiveDevice(kind) {
22862
+ return this.activeDeviceMap.get(kind);
22863
+ }
22826
22864
  /**
22827
22865
  * Switches all active devices used in this room to the given device.
22828
22866
  *
@@ -22835,21 +22873,24 @@ class Room extends EventEmitter {
22835
22873
  */
22836
22874
  switchActiveDevice(kind, deviceId) {
22837
22875
  let exact = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
22838
- var _a;
22839
- var _b;
22876
+ var _a, _b;
22877
+ var _c;
22840
22878
  return __awaiter(this, void 0, void 0, function* () {
22879
+ let deviceHasChanged = false;
22880
+ let success = true;
22841
22881
  const deviceConstraint = exact ? {
22842
22882
  exact: deviceId
22843
22883
  } : deviceId;
22844
22884
  if (kind === 'audioinput') {
22845
22885
  const prevDeviceId = this.options.audioCaptureDefaults.deviceId;
22846
22886
  this.options.audioCaptureDefaults.deviceId = deviceConstraint;
22887
+ deviceHasChanged = prevDeviceId !== deviceConstraint;
22847
22888
  const tracks = Array.from(this.localParticipant.audioTracks.values()).filter(track => track.source === Track.Source.Microphone);
22848
22889
  try {
22849
- yield Promise.all(tracks.map(t => {
22890
+ success = (yield Promise.all(tracks.map(t => {
22850
22891
  var _a;
22851
22892
  return (_a = t.audioTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceConstraint);
22852
- }));
22893
+ }))).every(val => val === true);
22853
22894
  } catch (e) {
22854
22895
  this.options.audioCaptureDefaults.deviceId = prevDeviceId;
22855
22896
  throw e;
@@ -22857,33 +22898,44 @@ class Room extends EventEmitter {
22857
22898
  } else if (kind === 'videoinput') {
22858
22899
  const prevDeviceId = this.options.videoCaptureDefaults.deviceId;
22859
22900
  this.options.videoCaptureDefaults.deviceId = deviceConstraint;
22901
+ deviceHasChanged = prevDeviceId !== deviceConstraint;
22860
22902
  const tracks = Array.from(this.localParticipant.videoTracks.values()).filter(track => track.source === Track.Source.Camera);
22861
22903
  try {
22862
- yield Promise.all(tracks.map(t => {
22904
+ success = (yield Promise.all(tracks.map(t => {
22863
22905
  var _a;
22864
22906
  return (_a = t.videoTrack) === null || _a === void 0 ? void 0 : _a.setDeviceId(deviceConstraint);
22865
- }));
22907
+ }))).every(val => val === true);
22866
22908
  } catch (e) {
22867
22909
  this.options.videoCaptureDefaults.deviceId = prevDeviceId;
22868
22910
  throw e;
22869
22911
  }
22870
22912
  } else if (kind === 'audiooutput') {
22871
- // TODO add support for webaudio mix once the API becomes available https://github.com/WebAudio/web-audio-api/pull/2498
22872
- if (!supportsSetSinkId()) {
22913
+ if (!supportsSetSinkId() && !this.options.expWebAudioMix || this.audioContext && !('setSinkId' in this.audioContext)) {
22873
22914
  throw new Error('cannot switch audio output, setSinkId not supported');
22874
22915
  }
22875
- (_a = (_b = this.options).audioOutput) !== null && _a !== void 0 ? _a : _b.audioOutput = {};
22916
+ (_a = (_c = this.options).audioOutput) !== null && _a !== void 0 ? _a : _c.audioOutput = {};
22876
22917
  const prevDeviceId = this.options.audioOutput.deviceId;
22877
22918
  this.options.audioOutput.deviceId = deviceId;
22919
+ deviceHasChanged = prevDeviceId !== deviceConstraint;
22878
22920
  try {
22879
- yield Promise.all(Array.from(this.participants.values()).map(p => p.setAudioOutput({
22880
- deviceId
22881
- })));
22921
+ if (this.options.expWebAudioMix) {
22922
+ // @ts-expect-error setSinkId is not yet in the typescript type of AudioContext
22923
+ (_b = this.audioContext) === null || _b === void 0 ? void 0 : _b.setSinkId(deviceId);
22924
+ } else {
22925
+ yield Promise.all(Array.from(this.participants.values()).map(p => p.setAudioOutput({
22926
+ deviceId
22927
+ })));
22928
+ }
22882
22929
  } catch (e) {
22883
22930
  this.options.audioOutput.deviceId = prevDeviceId;
22884
22931
  throw e;
22885
22932
  }
22886
22933
  }
22934
+ if (deviceHasChanged && success) {
22935
+ this.activeDeviceMap.set(kind, deviceId);
22936
+ this.emit(RoomEvent.ActiveDeviceChanged, kind, deviceId);
22937
+ }
22938
+ return success;
22887
22939
  });
22888
22940
  }
22889
22941
  setupLocalParticipantEvents() {