@stream-io/video-client 0.3.13 → 0.3.14

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.
package/dist/index.cjs.js CHANGED
@@ -6513,6 +6513,9 @@ class Publisher {
6513
6513
  // by an external factor as permission revokes, device disconnected, etc.
6514
6514
  // keep in mind that `track.stop()` doesn't trigger this event.
6515
6515
  track.addEventListener('ended', handleTrackEnded);
6516
+ if (!track.enabled) {
6517
+ track.enabled = true;
6518
+ }
6516
6519
  transceiver = this.pc.addTransceiver(track, {
6517
6520
  direction: 'sendonly',
6518
6521
  streams: trackType === TrackType.VIDEO || trackType === TrackType.SCREEN_SHARE
@@ -6550,16 +6553,25 @@ class Publisher {
6550
6553
  * @param stopTrack specifies whether track should be stopped or just disabled
6551
6554
  */
6552
6555
  this.unpublishStream = (trackType, stopTrack) => __awaiter(this, void 0, void 0, function* () {
6556
+ var _b;
6553
6557
  const transceiver = this.pc
6554
6558
  .getTransceivers()
6555
6559
  .find((t) => t === this.transceiverRegistry[trackType] && t.sender.track);
6556
6560
  if (transceiver &&
6557
6561
  transceiver.sender.track &&
6558
- transceiver.sender.track.readyState === 'live') {
6562
+ (stopTrack
6563
+ ? transceiver.sender.track.readyState === 'live'
6564
+ : transceiver.sender.track.enabled)) {
6559
6565
  stopTrack
6560
6566
  ? transceiver.sender.track.stop()
6561
6567
  : (transceiver.sender.track.enabled = false);
6562
- return this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6568
+ // We don't need to notify SFU if unpublishing in response to remote soft mute
6569
+ if (!((_b = this.state.localParticipant) === null || _b === void 0 ? void 0 : _b.publishedTracks.includes(trackType))) {
6570
+ return;
6571
+ }
6572
+ else {
6573
+ return this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6574
+ }
6563
6575
  }
6564
6576
  });
6565
6577
  /**
@@ -6568,6 +6580,21 @@ class Publisher {
6568
6580
  * @param trackType the track type to check.
6569
6581
  */
6570
6582
  this.isPublishing = (trackType) => {
6583
+ const transceiverForTrackType = this.transceiverRegistry[trackType];
6584
+ if (transceiverForTrackType && transceiverForTrackType.sender) {
6585
+ const sender = transceiverForTrackType.sender;
6586
+ return (!!sender.track &&
6587
+ sender.track.readyState === 'live' &&
6588
+ sender.track.enabled);
6589
+ }
6590
+ return false;
6591
+ };
6592
+ /**
6593
+ * Returns true if the given track type is currently live
6594
+ *
6595
+ * @param trackType the track type to check.
6596
+ */
6597
+ this.isLive = (trackType) => {
6571
6598
  const transceiverForTrackType = this.transceiverRegistry[trackType];
6572
6599
  if (transceiverForTrackType && transceiverForTrackType.sender) {
6573
6600
  const sender = transceiverForTrackType.sender;
@@ -6608,9 +6635,9 @@ class Publisher {
6608
6635
  });
6609
6636
  };
6610
6637
  this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
6611
- var _b;
6638
+ var _c;
6612
6639
  logger$3('info', 'Update publish quality, requested rids by SFU:', enabledRids);
6613
- const videoSender = (_b = this.transceiverRegistry[TrackType.VIDEO]) === null || _b === void 0 ? void 0 : _b.sender;
6640
+ const videoSender = (_c = this.transceiverRegistry[TrackType.VIDEO]) === null || _c === void 0 ? void 0 : _c.sender;
6614
6641
  if (!videoSender) {
6615
6642
  logger$3('warn', 'Update publish quality, no video sender found.');
6616
6643
  return;
@@ -6708,8 +6735,8 @@ class Publisher {
6708
6735
  * @param options the optional offer options to use.
6709
6736
  */
6710
6737
  this.negotiate = (options) => __awaiter(this, void 0, void 0, function* () {
6711
- var _c;
6712
- this.isIceRestarting = (_c = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _c !== void 0 ? _c : false;
6738
+ var _d;
6739
+ this.isIceRestarting = (_d = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _d !== void 0 ? _d : false;
6713
6740
  const offer = yield this.pc.createOffer(options);
6714
6741
  offer.sdp = this.mungeCodecs(offer.sdp);
6715
6742
  const trackInfos = this.getCurrentTrackInfos(offer.sdp);
@@ -7497,6 +7524,9 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
7497
7524
  retryAttempt++;
7498
7525
  } while (((_a = rpcCallResult.response.error) === null || _a === void 0 ? void 0 : _a.shouldRetry) &&
7499
7526
  retryAttempt < MAX_RETRIES);
7527
+ if (rpcCallResult.response.error) {
7528
+ throw rpcCallResult.response.error;
7529
+ }
7500
7530
  return rpcCallResult;
7501
7531
  });
7502
7532
 
@@ -9820,6 +9850,190 @@ class CameraManagerState extends InputMediaDeviceManagerState {
9820
9850
  }
9821
9851
  }
9822
9852
 
9853
+ class InputMediaDeviceManager {
9854
+ constructor(call, state, trackType) {
9855
+ this.call = call;
9856
+ this.state = state;
9857
+ this.trackType = trackType;
9858
+ this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
9859
+ }
9860
+ /**
9861
+ * Lists the available audio/video devices
9862
+ *
9863
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9864
+ *
9865
+ * @returns an Observable that will be updated if a device is connected or disconnected
9866
+ */
9867
+ listDevices() {
9868
+ return this.getDevices();
9869
+ }
9870
+ /**
9871
+ * Starts camera/microphone
9872
+ */
9873
+ enable() {
9874
+ return __awaiter(this, void 0, void 0, function* () {
9875
+ if (this.state.status === 'enabled') {
9876
+ return;
9877
+ }
9878
+ this.enablePromise = this.unmuteStream();
9879
+ try {
9880
+ yield this.enablePromise;
9881
+ this.state.setStatus('enabled');
9882
+ }
9883
+ catch (error) {
9884
+ this.enablePromise = undefined;
9885
+ throw error;
9886
+ }
9887
+ });
9888
+ }
9889
+ /**
9890
+ * Stops camera/microphone
9891
+ *
9892
+ * @returns
9893
+ */
9894
+ disable() {
9895
+ return __awaiter(this, void 0, void 0, function* () {
9896
+ this.state.prevStatus = this.state.status;
9897
+ if (this.state.status === 'disabled') {
9898
+ return;
9899
+ }
9900
+ this.disablePromise = this.muteStream(this.state.disableMode === 'stop-tracks');
9901
+ try {
9902
+ yield this.disablePromise;
9903
+ this.state.setStatus('disabled');
9904
+ this.disablePromise = undefined;
9905
+ }
9906
+ catch (error) {
9907
+ this.disablePromise = undefined;
9908
+ throw error;
9909
+ }
9910
+ });
9911
+ }
9912
+ /**
9913
+ * If status was previously enabled, it will reenable the device.
9914
+ */
9915
+ resume() {
9916
+ return __awaiter(this, void 0, void 0, function* () {
9917
+ if (this.state.prevStatus === 'enabled' &&
9918
+ this.state.status === 'disabled') {
9919
+ this.enable();
9920
+ }
9921
+ });
9922
+ }
9923
+ /**
9924
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9925
+ *
9926
+ * @returns
9927
+ */
9928
+ toggle() {
9929
+ return __awaiter(this, void 0, void 0, function* () {
9930
+ if (this.state.status === 'enabled') {
9931
+ return this.disable();
9932
+ }
9933
+ else {
9934
+ return this.enable();
9935
+ }
9936
+ });
9937
+ }
9938
+ /**
9939
+ * Select device
9940
+ *
9941
+ * Note: this method is not supported in React Native
9942
+ *
9943
+ * @param deviceId
9944
+ */
9945
+ select(deviceId) {
9946
+ return __awaiter(this, void 0, void 0, function* () {
9947
+ if (isReactNative()) {
9948
+ throw new Error('This method is not supported in React Native');
9949
+ }
9950
+ if (deviceId === this.state.selectedDevice) {
9951
+ return;
9952
+ }
9953
+ this.state.setDevice(deviceId);
9954
+ yield this.applySettingsToStream();
9955
+ });
9956
+ }
9957
+ applySettingsToStream() {
9958
+ return __awaiter(this, void 0, void 0, function* () {
9959
+ if (this.state.status === 'enabled') {
9960
+ yield this.muteStream();
9961
+ yield this.unmuteStream();
9962
+ }
9963
+ });
9964
+ }
9965
+ muteStream(stopTracks = true) {
9966
+ var _a;
9967
+ return __awaiter(this, void 0, void 0, function* () {
9968
+ if (!this.state.mediaStream) {
9969
+ return;
9970
+ }
9971
+ this.logger('debug', `${stopTracks ? 'Stopping' : 'Disabling'} stream`);
9972
+ if (this.call.state.callingState === exports.CallingState.JOINED) {
9973
+ yield this.stopPublishStream(stopTracks);
9974
+ }
9975
+ this.muteLocalStream(stopTracks);
9976
+ if (((_a = this.getTrack()) === null || _a === void 0 ? void 0 : _a.readyState) === 'ended') {
9977
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9978
+ if (typeof this.state.mediaStream.release === 'function') {
9979
+ // @ts-expect-error
9980
+ this.state.mediaStream.release();
9981
+ }
9982
+ this.state.setMediaStream(undefined);
9983
+ }
9984
+ });
9985
+ }
9986
+ muteTrack() {
9987
+ const track = this.getTrack();
9988
+ if (!track || !track.enabled) {
9989
+ return;
9990
+ }
9991
+ track.enabled = false;
9992
+ }
9993
+ unmuteTrack() {
9994
+ const track = this.getTrack();
9995
+ if (!track || track.enabled) {
9996
+ return;
9997
+ }
9998
+ track.enabled = true;
9999
+ }
10000
+ stopTrack() {
10001
+ const track = this.getTrack();
10002
+ if (!track || track.readyState === 'ended') {
10003
+ return;
10004
+ }
10005
+ track.stop();
10006
+ }
10007
+ muteLocalStream(stopTracks) {
10008
+ if (!this.state.mediaStream) {
10009
+ return;
10010
+ }
10011
+ stopTracks ? this.stopTrack() : this.muteTrack();
10012
+ }
10013
+ unmuteStream() {
10014
+ var _a;
10015
+ return __awaiter(this, void 0, void 0, function* () {
10016
+ this.logger('debug', 'Starting stream');
10017
+ let stream;
10018
+ if (this.state.mediaStream && ((_a = this.getTrack()) === null || _a === void 0 ? void 0 : _a.readyState) === 'live') {
10019
+ stream = this.state.mediaStream;
10020
+ this.unmuteTrack();
10021
+ }
10022
+ else {
10023
+ if (this.state.mediaStream) {
10024
+ this.stopTrack();
10025
+ }
10026
+ const constraints = { deviceId: this.state.selectedDevice };
10027
+ stream = yield this.getStream(constraints);
10028
+ }
10029
+ if (this.call.state.callingState === exports.CallingState.JOINED) {
10030
+ yield this.publishStream(stream);
10031
+ }
10032
+ this.state.setMediaStream(stream);
10033
+ });
10034
+ }
10035
+ }
10036
+
9823
10037
  const getDevices = (constraints) => {
9824
10038
  return new rxjs.Observable((subscriber) => {
9825
10039
  navigator.mediaDevices
@@ -10068,156 +10282,9 @@ const disposeOfMediaStream = (stream) => {
10068
10282
  }
10069
10283
  };
10070
10284
 
10071
- class InputMediaDeviceManager {
10072
- constructor(call, state) {
10073
- this.call = call;
10074
- this.state = state;
10075
- }
10076
- /**
10077
- * Lists the available audio/video devices
10078
- *
10079
- * Note: It prompts the user for a permission to use devices (if not already granted)
10080
- *
10081
- * @returns an Observable that will be updated if a device is connected or disconnected
10082
- */
10083
- listDevices() {
10084
- return this.getDevices();
10085
- }
10086
- /**
10087
- * Starts camera/microphone
10088
- */
10089
- enable() {
10090
- return __awaiter(this, void 0, void 0, function* () {
10091
- if (this.state.status === 'enabled') {
10092
- return;
10093
- }
10094
- this.enablePromise = this.unmuteStream();
10095
- try {
10096
- yield this.enablePromise;
10097
- this.state.setStatus('enabled');
10098
- }
10099
- catch (error) {
10100
- this.enablePromise = undefined;
10101
- throw error;
10102
- }
10103
- });
10104
- }
10105
- /**
10106
- * Stops camera/microphone
10107
- *
10108
- * @returns
10109
- */
10110
- disable() {
10111
- return __awaiter(this, void 0, void 0, function* () {
10112
- this.state.prevStatus = this.state.status;
10113
- if (this.state.status === 'disabled') {
10114
- return;
10115
- }
10116
- this.disablePromise = this.muteStream(this.state.disableMode === 'stop-tracks');
10117
- try {
10118
- yield this.disablePromise;
10119
- this.state.setStatus('disabled');
10120
- this.disablePromise = undefined;
10121
- }
10122
- catch (error) {
10123
- this.disablePromise = undefined;
10124
- throw error;
10125
- }
10126
- });
10127
- }
10128
- /**
10129
- * If status was previously enabled, it will reenable the device.
10130
- */
10131
- resume() {
10132
- return __awaiter(this, void 0, void 0, function* () {
10133
- if (this.state.prevStatus === 'enabled' &&
10134
- this.state.status === 'disabled') {
10135
- this.enable();
10136
- }
10137
- });
10138
- }
10139
- /**
10140
- * If current device statis is disabled, it will enable the device, else it will disable it.
10141
- *
10142
- * @returns
10143
- */
10144
- toggle() {
10145
- return __awaiter(this, void 0, void 0, function* () {
10146
- if (this.state.status === 'enabled') {
10147
- return this.disable();
10148
- }
10149
- else {
10150
- return this.enable();
10151
- }
10152
- });
10153
- }
10154
- /**
10155
- * Select device
10156
- *
10157
- * Note: this method is not supported in React Native
10158
- *
10159
- * @param deviceId
10160
- */
10161
- select(deviceId) {
10162
- return __awaiter(this, void 0, void 0, function* () {
10163
- if (isReactNative()) {
10164
- throw new Error('This method is not supported in React Native');
10165
- }
10166
- if (deviceId === this.state.selectedDevice) {
10167
- return;
10168
- }
10169
- this.state.setDevice(deviceId);
10170
- yield this.applySettingsToStream();
10171
- });
10172
- }
10173
- applySettingsToStream() {
10174
- return __awaiter(this, void 0, void 0, function* () {
10175
- if (this.state.status === 'enabled') {
10176
- yield this.muteStream();
10177
- yield this.unmuteStream();
10178
- }
10179
- });
10180
- }
10181
- muteStream(stopTracks = true) {
10182
- return __awaiter(this, void 0, void 0, function* () {
10183
- if (!this.state.mediaStream) {
10184
- return;
10185
- }
10186
- if (this.call.state.callingState === exports.CallingState.JOINED) {
10187
- yield this.stopPublishStream(stopTracks);
10188
- }
10189
- else if (this.state.mediaStream) {
10190
- stopTracks
10191
- ? disposeOfMediaStream(this.state.mediaStream)
10192
- : this.muteTracks();
10193
- }
10194
- if (stopTracks) {
10195
- this.state.setMediaStream(undefined);
10196
- }
10197
- });
10198
- }
10199
- unmuteStream() {
10200
- return __awaiter(this, void 0, void 0, function* () {
10201
- let stream;
10202
- if (this.state.mediaStream) {
10203
- stream = this.state.mediaStream;
10204
- this.unmuteTracks();
10205
- }
10206
- else {
10207
- const constraints = { deviceId: this.state.selectedDevice };
10208
- stream = yield this.getStream(constraints);
10209
- }
10210
- if (this.call.state.callingState === exports.CallingState.JOINED) {
10211
- yield this.publishStream(stream);
10212
- }
10213
- this.state.setMediaStream(stream);
10214
- });
10215
- }
10216
- }
10217
-
10218
10285
  class CameraManager extends InputMediaDeviceManager {
10219
10286
  constructor(call) {
10220
- super(call, new CameraManagerState());
10287
+ super(call, new CameraManagerState(), TrackType.VIDEO);
10221
10288
  this.targetResolution = {
10222
10289
  width: 1280,
10223
10290
  height: 720,
@@ -10269,6 +10336,7 @@ class CameraManager extends InputMediaDeviceManager {
10269
10336
  if (width !== this.targetResolution.width ||
10270
10337
  height !== this.targetResolution.height)
10271
10338
  yield this.applySettingsToStream();
10339
+ this.logger('debug', `${width}x${height} target resolution applied to media stream`);
10272
10340
  }
10273
10341
  });
10274
10342
  }
@@ -10292,13 +10360,9 @@ class CameraManager extends InputMediaDeviceManager {
10292
10360
  stopPublishStream(stopTracks) {
10293
10361
  return this.call.stopPublish(TrackType.VIDEO, stopTracks);
10294
10362
  }
10295
- muteTracks() {
10296
- var _a;
10297
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((t) => (t.enabled = false));
10298
- }
10299
- unmuteTracks() {
10363
+ getTrack() {
10300
10364
  var _a;
10301
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((t) => (t.enabled = true));
10365
+ return (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0];
10302
10366
  }
10303
10367
  }
10304
10368
 
@@ -10314,7 +10378,7 @@ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10314
10378
 
10315
10379
  class MicrophoneManager extends InputMediaDeviceManager {
10316
10380
  constructor(call) {
10317
- super(call, new MicrophoneManagerState());
10381
+ super(call, new MicrophoneManagerState(), TrackType.AUDIO);
10318
10382
  }
10319
10383
  getDevices() {
10320
10384
  return getAudioDevices();
@@ -10328,13 +10392,9 @@ class MicrophoneManager extends InputMediaDeviceManager {
10328
10392
  stopPublishStream(stopTracks) {
10329
10393
  return this.call.stopPublish(TrackType.AUDIO, stopTracks);
10330
10394
  }
10331
- muteTracks() {
10332
- var _a;
10333
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((t) => (t.enabled = false));
10334
- }
10335
- unmuteTracks() {
10395
+ getTrack() {
10336
10396
  var _a;
10337
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((t) => (t.enabled = true));
10397
+ return (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
10338
10398
  }
10339
10399
  }
10340
10400
 
@@ -11020,7 +11080,7 @@ class Call {
11020
11080
  */
11021
11081
  this.stopPublish = (trackType, stopTrack = true) => __awaiter(this, void 0, void 0, function* () {
11022
11082
  var _j;
11023
- this.logger('info', `stopPublish ${TrackType[trackType]}`);
11083
+ this.logger('info', `stopPublish ${TrackType[trackType]}, stop tracks: ${stopTrack}`);
11024
11084
  yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType, stopTrack));
11025
11085
  });
11026
11086
  /**
@@ -11598,6 +11658,27 @@ class Call {
11598
11658
  this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(rxjs.debounce((v) => rxjs.timer(v.type)), rxjs.map((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
11599
11659
  this.camera = new CameraManager(this);
11600
11660
  this.microphone = new MicrophoneManager(this);
11661
+ this.state.localParticipant$.subscribe((p) => __awaiter(this, void 0, void 0, function* () {
11662
+ var _l, _m;
11663
+ // Mute via device manager
11664
+ // If integrator doesn't use device manager, we mute using stopPublish
11665
+ if (!(p === null || p === void 0 ? void 0 : p.publishedTracks.includes(TrackType.VIDEO)) &&
11666
+ ((_l = this.publisher) === null || _l === void 0 ? void 0 : _l.isPublishing(TrackType.VIDEO))) {
11667
+ this.logger('info', `Local participant's video track is muted remotely`);
11668
+ yield this.camera.disable();
11669
+ if (this.publisher.isPublishing(TrackType.VIDEO)) {
11670
+ this.stopPublish(TrackType.VIDEO);
11671
+ }
11672
+ }
11673
+ if (!(p === null || p === void 0 ? void 0 : p.publishedTracks.includes(TrackType.AUDIO)) &&
11674
+ ((_m = this.publisher) === null || _m === void 0 ? void 0 : _m.isPublishing(TrackType.AUDIO))) {
11675
+ this.logger('info', `Local participant's audio track is muted remotely`);
11676
+ yield this.microphone.disable();
11677
+ if (this.publisher.isPublishing(TrackType.AUDIO)) {
11678
+ this.stopPublish(TrackType.AUDIO);
11679
+ }
11680
+ }
11681
+ }));
11601
11682
  this.speaker = new SpeakerManager();
11602
11683
  }
11603
11684
  registerEffects() {
@@ -11623,9 +11704,27 @@ class Call {
11623
11704
  };
11624
11705
  for (const [permission, trackType] of Object.entries(permissionToTrackType)) {
11625
11706
  const hasPermission = this.permissionsContext.hasPermission(permission);
11626
- if (!hasPermission && this.publisher.isPublishing(trackType)) {
11627
- this.stopPublish(trackType).catch((err) => {
11707
+ if (!hasPermission &&
11708
+ (this.publisher.isPublishing(trackType) ||
11709
+ this.publisher.isLive(trackType))) {
11710
+ // Stop tracks, then notify device manager
11711
+ this.stopPublish(trackType)
11712
+ .catch((err) => {
11628
11713
  this.logger('error', `Error stopping publish ${trackType}`, err);
11714
+ })
11715
+ .then(() => {
11716
+ if (trackType === TrackType.VIDEO &&
11717
+ this.camera.state.status === 'enabled') {
11718
+ this.camera
11719
+ .disable()
11720
+ .catch((err) => this.logger('error', `Error disabling camera after pemission revoked`, err));
11721
+ }
11722
+ if (trackType === TrackType.AUDIO &&
11723
+ this.microphone.state.status === 'enabled') {
11724
+ this.microphone
11725
+ .disable()
11726
+ .catch((err) => this.logger('error', `Error disabling microphone after pemission revoked`, err));
11727
+ }
11629
11728
  });
11630
11729
  }
11631
11730
  }
@@ -12889,11 +12988,11 @@ class WSConnectionFallback {
12889
12988
  }
12890
12989
  }
12891
12990
 
12892
- const version = '0.3.13';
12991
+ const version = '0.3.14';
12893
12992
 
12894
12993
  const logger = getLogger(['location']);
12895
12994
  const HINT_URL = `https://hint.stream-io-video.com/`;
12896
- const getLocationHint = (hintUrl = HINT_URL, timeout = 1500) => __awaiter(void 0, void 0, void 0, function* () {
12995
+ const getLocationHint = (hintUrl = HINT_URL, timeout = 2000) => __awaiter(void 0, void 0, void 0, function* () {
12897
12996
  const abortController = new AbortController();
12898
12997
  const timeoutId = setTimeout(() => abortController.abort(), timeout);
12899
12998
  try {
@@ -12906,7 +13005,7 @@ const getLocationHint = (hintUrl = HINT_URL, timeout = 1500) => __awaiter(void 0
12906
13005
  return awsPop.substring(0, 3); // AMS1-P2 -> AMS
12907
13006
  }
12908
13007
  catch (e) {
12909
- logger('error', `Failed to get location hint from ${HINT_URL}`, e);
13008
+ logger('warn', `Failed to get location hint from ${HINT_URL}`, e);
12910
13009
  return 'ERR';
12911
13010
  }
12912
13011
  finally {