@stream-io/video-client 0.3.13 → 0.3.15

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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ### [0.3.15](https://github.com/GetStream/stream-video-js/compare/client0.3.14...client0.3.15) (2023-09-11)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * consider prior track publishing state before applying soft mutes ([#1070](https://github.com/GetStream/stream-video-js/issues/1070)) ([f542409](https://github.com/GetStream/stream-video-js/commit/f542409c641417bbbe6f0997d77e34684b881bfb)), closes [#988](https://github.com/GetStream/stream-video-js/issues/988)
11
+
12
+ ### [0.3.14](https://github.com/GetStream/stream-video-js/compare/client0.3.13...client0.3.14) (2023-09-05)
13
+
14
+
15
+ ### Features
16
+
17
+ * new device api remote mutes ([#988](https://github.com/GetStream/stream-video-js/issues/988)) ([5bbcefb](https://github.com/GetStream/stream-video-js/commit/5bbcefbf0d8be59025fef8111253a8a0baaf6001))
18
+
5
19
  ### [0.3.13](https://github.com/GetStream/stream-video-js/compare/client0.3.12...client0.3.13) (2023-08-31)
6
20
 
7
21
 
@@ -6409,6 +6409,14 @@ class Publisher {
6409
6409
  [TrackType.SCREEN_SHARE_AUDIO]: undefined,
6410
6410
  [TrackType.UNSPECIFIED]: undefined,
6411
6411
  };
6412
+ /**
6413
+ * A map keeping track of track types that were published to the SFU.
6414
+ * This map shouldn't be cleared when unpublishing a track, as it is used
6415
+ * to determine whether a track was published before.
6416
+ *
6417
+ * @private
6418
+ */
6419
+ this.trackTypePublishHistory = new Map();
6412
6420
  this.isIceRestarting = false;
6413
6421
  this.createPeerConnection = (connectionConfig) => {
6414
6422
  const pc = new RTCPeerConnection(connectionConfig);
@@ -6490,6 +6498,9 @@ class Publisher {
6490
6498
  // by an external factor as permission revokes, device disconnected, etc.
6491
6499
  // keep in mind that `track.stop()` doesn't trigger this event.
6492
6500
  track.addEventListener('ended', handleTrackEnded);
6501
+ if (!track.enabled) {
6502
+ track.enabled = true;
6503
+ }
6493
6504
  transceiver = this.pc.addTransceiver(track, {
6494
6505
  direction: 'sendonly',
6495
6506
  streams: trackType === TrackType.VIDEO || trackType === TrackType.SCREEN_SHARE
@@ -6500,6 +6511,7 @@ class Publisher {
6500
6511
  logger$3('debug', `Added ${TrackType[trackType]} transceiver`);
6501
6512
  this.transceiverInitOrder.push(trackType);
6502
6513
  this.transceiverRegistry[trackType] = transceiver;
6514
+ this.trackTypePublishHistory.set(trackType, true);
6503
6515
  if ('setCodecPreferences' in transceiver && codecPreferences) {
6504
6516
  logger$3('info', `Setting ${TrackType[trackType]} codec preferences`, codecPreferences);
6505
6517
  transceiver.setCodecPreferences(codecPreferences);
@@ -6527,16 +6539,25 @@ class Publisher {
6527
6539
  * @param stopTrack specifies whether track should be stopped or just disabled
6528
6540
  */
6529
6541
  this.unpublishStream = (trackType, stopTrack) => __awaiter(this, void 0, void 0, function* () {
6542
+ var _b;
6530
6543
  const transceiver = this.pc
6531
6544
  .getTransceivers()
6532
6545
  .find((t) => t === this.transceiverRegistry[trackType] && t.sender.track);
6533
6546
  if (transceiver &&
6534
6547
  transceiver.sender.track &&
6535
- transceiver.sender.track.readyState === 'live') {
6548
+ (stopTrack
6549
+ ? transceiver.sender.track.readyState === 'live'
6550
+ : transceiver.sender.track.enabled)) {
6536
6551
  stopTrack
6537
6552
  ? transceiver.sender.track.stop()
6538
6553
  : (transceiver.sender.track.enabled = false);
6539
- return this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6554
+ // We don't need to notify SFU if unpublishing in response to remote soft mute
6555
+ if (!((_b = this.state.localParticipant) === null || _b === void 0 ? void 0 : _b.publishedTracks.includes(trackType))) {
6556
+ return;
6557
+ }
6558
+ else {
6559
+ return this.notifyTrackMuteStateChanged(undefined, transceiver.sender.track, trackType, true);
6560
+ }
6540
6561
  }
6541
6562
  });
6542
6563
  /**
@@ -6545,6 +6566,32 @@ class Publisher {
6545
6566
  * @param trackType the track type to check.
6546
6567
  */
6547
6568
  this.isPublishing = (trackType) => {
6569
+ const transceiverForTrackType = this.transceiverRegistry[trackType];
6570
+ if (transceiverForTrackType && transceiverForTrackType.sender) {
6571
+ const sender = transceiverForTrackType.sender;
6572
+ return (!!sender.track &&
6573
+ sender.track.readyState === 'live' &&
6574
+ sender.track.enabled);
6575
+ }
6576
+ return false;
6577
+ };
6578
+ /**
6579
+ * Returns true if the given track type was ever published to the SFU.
6580
+ * Contrary to `isPublishing`, this method returns true if a certain
6581
+ * track type was published before, even if it is currently unpublished.
6582
+ *
6583
+ * @param trackType the track type to check.
6584
+ */
6585
+ this.hasEverPublished = (trackType) => {
6586
+ var _a;
6587
+ return (_a = this.trackTypePublishHistory.get(trackType)) !== null && _a !== void 0 ? _a : false;
6588
+ };
6589
+ /**
6590
+ * Returns true if the given track type is currently live
6591
+ *
6592
+ * @param trackType the track type to check.
6593
+ */
6594
+ this.isLive = (trackType) => {
6548
6595
  const transceiverForTrackType = this.transceiverRegistry[trackType];
6549
6596
  if (transceiverForTrackType && transceiverForTrackType.sender) {
6550
6597
  const sender = transceiverForTrackType.sender;
@@ -6585,9 +6632,9 @@ class Publisher {
6585
6632
  });
6586
6633
  };
6587
6634
  this.updateVideoPublishQuality = (enabledRids) => __awaiter(this, void 0, void 0, function* () {
6588
- var _b;
6635
+ var _c;
6589
6636
  logger$3('info', 'Update publish quality, requested rids by SFU:', enabledRids);
6590
- const videoSender = (_b = this.transceiverRegistry[TrackType.VIDEO]) === null || _b === void 0 ? void 0 : _b.sender;
6637
+ const videoSender = (_c = this.transceiverRegistry[TrackType.VIDEO]) === null || _c === void 0 ? void 0 : _c.sender;
6591
6638
  if (!videoSender) {
6592
6639
  logger$3('warn', 'Update publish quality, no video sender found.');
6593
6640
  return;
@@ -6685,8 +6732,8 @@ class Publisher {
6685
6732
  * @param options the optional offer options to use.
6686
6733
  */
6687
6734
  this.negotiate = (options) => __awaiter(this, void 0, void 0, function* () {
6688
- var _c;
6689
- this.isIceRestarting = (_c = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _c !== void 0 ? _c : false;
6735
+ var _d;
6736
+ this.isIceRestarting = (_d = options === null || options === void 0 ? void 0 : options.iceRestart) !== null && _d !== void 0 ? _d : false;
6690
6737
  const offer = yield this.pc.createOffer(options);
6691
6738
  offer.sdp = this.mungeCodecs(offer.sdp);
6692
6739
  const trackInfos = this.getCurrentTrackInfos(offer.sdp);
@@ -7474,6 +7521,9 @@ const retryable = (rpc, logger) => __awaiter(void 0, void 0, void 0, function* (
7474
7521
  retryAttempt++;
7475
7522
  } while (((_a = rpcCallResult.response.error) === null || _a === void 0 ? void 0 : _a.shouldRetry) &&
7476
7523
  retryAttempt < MAX_RETRIES);
7524
+ if (rpcCallResult.response.error) {
7525
+ throw rpcCallResult.response.error;
7526
+ }
7477
7527
  return rpcCallResult;
7478
7528
  });
7479
7529
 
@@ -9797,6 +9847,190 @@ class CameraManagerState extends InputMediaDeviceManagerState {
9797
9847
  }
9798
9848
  }
9799
9849
 
9850
+ class InputMediaDeviceManager {
9851
+ constructor(call, state, trackType) {
9852
+ this.call = call;
9853
+ this.state = state;
9854
+ this.trackType = trackType;
9855
+ this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
9856
+ }
9857
+ /**
9858
+ * Lists the available audio/video devices
9859
+ *
9860
+ * Note: It prompts the user for a permission to use devices (if not already granted)
9861
+ *
9862
+ * @returns an Observable that will be updated if a device is connected or disconnected
9863
+ */
9864
+ listDevices() {
9865
+ return this.getDevices();
9866
+ }
9867
+ /**
9868
+ * Starts camera/microphone
9869
+ */
9870
+ enable() {
9871
+ return __awaiter(this, void 0, void 0, function* () {
9872
+ if (this.state.status === 'enabled') {
9873
+ return;
9874
+ }
9875
+ this.enablePromise = this.unmuteStream();
9876
+ try {
9877
+ yield this.enablePromise;
9878
+ this.state.setStatus('enabled');
9879
+ }
9880
+ catch (error) {
9881
+ this.enablePromise = undefined;
9882
+ throw error;
9883
+ }
9884
+ });
9885
+ }
9886
+ /**
9887
+ * Stops camera/microphone
9888
+ *
9889
+ * @returns
9890
+ */
9891
+ disable() {
9892
+ return __awaiter(this, void 0, void 0, function* () {
9893
+ this.state.prevStatus = this.state.status;
9894
+ if (this.state.status === 'disabled') {
9895
+ return;
9896
+ }
9897
+ this.disablePromise = this.muteStream(this.state.disableMode === 'stop-tracks');
9898
+ try {
9899
+ yield this.disablePromise;
9900
+ this.state.setStatus('disabled');
9901
+ this.disablePromise = undefined;
9902
+ }
9903
+ catch (error) {
9904
+ this.disablePromise = undefined;
9905
+ throw error;
9906
+ }
9907
+ });
9908
+ }
9909
+ /**
9910
+ * If status was previously enabled, it will reenable the device.
9911
+ */
9912
+ resume() {
9913
+ return __awaiter(this, void 0, void 0, function* () {
9914
+ if (this.state.prevStatus === 'enabled' &&
9915
+ this.state.status === 'disabled') {
9916
+ this.enable();
9917
+ }
9918
+ });
9919
+ }
9920
+ /**
9921
+ * If current device statis is disabled, it will enable the device, else it will disable it.
9922
+ *
9923
+ * @returns
9924
+ */
9925
+ toggle() {
9926
+ return __awaiter(this, void 0, void 0, function* () {
9927
+ if (this.state.status === 'enabled') {
9928
+ return this.disable();
9929
+ }
9930
+ else {
9931
+ return this.enable();
9932
+ }
9933
+ });
9934
+ }
9935
+ /**
9936
+ * Select device
9937
+ *
9938
+ * Note: this method is not supported in React Native
9939
+ *
9940
+ * @param deviceId
9941
+ */
9942
+ select(deviceId) {
9943
+ return __awaiter(this, void 0, void 0, function* () {
9944
+ if (isReactNative()) {
9945
+ throw new Error('This method is not supported in React Native');
9946
+ }
9947
+ if (deviceId === this.state.selectedDevice) {
9948
+ return;
9949
+ }
9950
+ this.state.setDevice(deviceId);
9951
+ yield this.applySettingsToStream();
9952
+ });
9953
+ }
9954
+ applySettingsToStream() {
9955
+ return __awaiter(this, void 0, void 0, function* () {
9956
+ if (this.state.status === 'enabled') {
9957
+ yield this.muteStream();
9958
+ yield this.unmuteStream();
9959
+ }
9960
+ });
9961
+ }
9962
+ muteStream(stopTracks = true) {
9963
+ var _a;
9964
+ return __awaiter(this, void 0, void 0, function* () {
9965
+ if (!this.state.mediaStream) {
9966
+ return;
9967
+ }
9968
+ this.logger('debug', `${stopTracks ? 'Stopping' : 'Disabling'} stream`);
9969
+ if (this.call.state.callingState === CallingState.JOINED) {
9970
+ yield this.stopPublishStream(stopTracks);
9971
+ }
9972
+ this.muteLocalStream(stopTracks);
9973
+ if (((_a = this.getTrack()) === null || _a === void 0 ? void 0 : _a.readyState) === 'ended') {
9974
+ // @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
9975
+ if (typeof this.state.mediaStream.release === 'function') {
9976
+ // @ts-expect-error
9977
+ this.state.mediaStream.release();
9978
+ }
9979
+ this.state.setMediaStream(undefined);
9980
+ }
9981
+ });
9982
+ }
9983
+ muteTrack() {
9984
+ const track = this.getTrack();
9985
+ if (!track || !track.enabled) {
9986
+ return;
9987
+ }
9988
+ track.enabled = false;
9989
+ }
9990
+ unmuteTrack() {
9991
+ const track = this.getTrack();
9992
+ if (!track || track.enabled) {
9993
+ return;
9994
+ }
9995
+ track.enabled = true;
9996
+ }
9997
+ stopTrack() {
9998
+ const track = this.getTrack();
9999
+ if (!track || track.readyState === 'ended') {
10000
+ return;
10001
+ }
10002
+ track.stop();
10003
+ }
10004
+ muteLocalStream(stopTracks) {
10005
+ if (!this.state.mediaStream) {
10006
+ return;
10007
+ }
10008
+ stopTracks ? this.stopTrack() : this.muteTrack();
10009
+ }
10010
+ unmuteStream() {
10011
+ var _a;
10012
+ return __awaiter(this, void 0, void 0, function* () {
10013
+ this.logger('debug', 'Starting stream');
10014
+ let stream;
10015
+ if (this.state.mediaStream && ((_a = this.getTrack()) === null || _a === void 0 ? void 0 : _a.readyState) === 'live') {
10016
+ stream = this.state.mediaStream;
10017
+ this.unmuteTrack();
10018
+ }
10019
+ else {
10020
+ if (this.state.mediaStream) {
10021
+ this.stopTrack();
10022
+ }
10023
+ const constraints = { deviceId: this.state.selectedDevice };
10024
+ stream = yield this.getStream(constraints);
10025
+ }
10026
+ if (this.call.state.callingState === CallingState.JOINED) {
10027
+ yield this.publishStream(stream);
10028
+ }
10029
+ this.state.setMediaStream(stream);
10030
+ });
10031
+ }
10032
+ }
10033
+
9800
10034
  const getDevices = (constraints) => {
9801
10035
  return new Observable((subscriber) => {
9802
10036
  navigator.mediaDevices
@@ -10045,156 +10279,9 @@ const disposeOfMediaStream = (stream) => {
10045
10279
  }
10046
10280
  };
10047
10281
 
10048
- class InputMediaDeviceManager {
10049
- constructor(call, state) {
10050
- this.call = call;
10051
- this.state = state;
10052
- }
10053
- /**
10054
- * Lists the available audio/video devices
10055
- *
10056
- * Note: It prompts the user for a permission to use devices (if not already granted)
10057
- *
10058
- * @returns an Observable that will be updated if a device is connected or disconnected
10059
- */
10060
- listDevices() {
10061
- return this.getDevices();
10062
- }
10063
- /**
10064
- * Starts camera/microphone
10065
- */
10066
- enable() {
10067
- return __awaiter(this, void 0, void 0, function* () {
10068
- if (this.state.status === 'enabled') {
10069
- return;
10070
- }
10071
- this.enablePromise = this.unmuteStream();
10072
- try {
10073
- yield this.enablePromise;
10074
- this.state.setStatus('enabled');
10075
- }
10076
- catch (error) {
10077
- this.enablePromise = undefined;
10078
- throw error;
10079
- }
10080
- });
10081
- }
10082
- /**
10083
- * Stops camera/microphone
10084
- *
10085
- * @returns
10086
- */
10087
- disable() {
10088
- return __awaiter(this, void 0, void 0, function* () {
10089
- this.state.prevStatus = this.state.status;
10090
- if (this.state.status === 'disabled') {
10091
- return;
10092
- }
10093
- this.disablePromise = this.muteStream(this.state.disableMode === 'stop-tracks');
10094
- try {
10095
- yield this.disablePromise;
10096
- this.state.setStatus('disabled');
10097
- this.disablePromise = undefined;
10098
- }
10099
- catch (error) {
10100
- this.disablePromise = undefined;
10101
- throw error;
10102
- }
10103
- });
10104
- }
10105
- /**
10106
- * If status was previously enabled, it will reenable the device.
10107
- */
10108
- resume() {
10109
- return __awaiter(this, void 0, void 0, function* () {
10110
- if (this.state.prevStatus === 'enabled' &&
10111
- this.state.status === 'disabled') {
10112
- this.enable();
10113
- }
10114
- });
10115
- }
10116
- /**
10117
- * If current device statis is disabled, it will enable the device, else it will disable it.
10118
- *
10119
- * @returns
10120
- */
10121
- toggle() {
10122
- return __awaiter(this, void 0, void 0, function* () {
10123
- if (this.state.status === 'enabled') {
10124
- return this.disable();
10125
- }
10126
- else {
10127
- return this.enable();
10128
- }
10129
- });
10130
- }
10131
- /**
10132
- * Select device
10133
- *
10134
- * Note: this method is not supported in React Native
10135
- *
10136
- * @param deviceId
10137
- */
10138
- select(deviceId) {
10139
- return __awaiter(this, void 0, void 0, function* () {
10140
- if (isReactNative()) {
10141
- throw new Error('This method is not supported in React Native');
10142
- }
10143
- if (deviceId === this.state.selectedDevice) {
10144
- return;
10145
- }
10146
- this.state.setDevice(deviceId);
10147
- yield this.applySettingsToStream();
10148
- });
10149
- }
10150
- applySettingsToStream() {
10151
- return __awaiter(this, void 0, void 0, function* () {
10152
- if (this.state.status === 'enabled') {
10153
- yield this.muteStream();
10154
- yield this.unmuteStream();
10155
- }
10156
- });
10157
- }
10158
- muteStream(stopTracks = true) {
10159
- return __awaiter(this, void 0, void 0, function* () {
10160
- if (!this.state.mediaStream) {
10161
- return;
10162
- }
10163
- if (this.call.state.callingState === CallingState.JOINED) {
10164
- yield this.stopPublishStream(stopTracks);
10165
- }
10166
- else if (this.state.mediaStream) {
10167
- stopTracks
10168
- ? disposeOfMediaStream(this.state.mediaStream)
10169
- : this.muteTracks();
10170
- }
10171
- if (stopTracks) {
10172
- this.state.setMediaStream(undefined);
10173
- }
10174
- });
10175
- }
10176
- unmuteStream() {
10177
- return __awaiter(this, void 0, void 0, function* () {
10178
- let stream;
10179
- if (this.state.mediaStream) {
10180
- stream = this.state.mediaStream;
10181
- this.unmuteTracks();
10182
- }
10183
- else {
10184
- const constraints = { deviceId: this.state.selectedDevice };
10185
- stream = yield this.getStream(constraints);
10186
- }
10187
- if (this.call.state.callingState === CallingState.JOINED) {
10188
- yield this.publishStream(stream);
10189
- }
10190
- this.state.setMediaStream(stream);
10191
- });
10192
- }
10193
- }
10194
-
10195
10282
  class CameraManager extends InputMediaDeviceManager {
10196
10283
  constructor(call) {
10197
- super(call, new CameraManagerState());
10284
+ super(call, new CameraManagerState(), TrackType.VIDEO);
10198
10285
  this.targetResolution = {
10199
10286
  width: 1280,
10200
10287
  height: 720,
@@ -10246,6 +10333,7 @@ class CameraManager extends InputMediaDeviceManager {
10246
10333
  if (width !== this.targetResolution.width ||
10247
10334
  height !== this.targetResolution.height)
10248
10335
  yield this.applySettingsToStream();
10336
+ this.logger('debug', `${width}x${height} target resolution applied to media stream`);
10249
10337
  }
10250
10338
  });
10251
10339
  }
@@ -10269,13 +10357,9 @@ class CameraManager extends InputMediaDeviceManager {
10269
10357
  stopPublishStream(stopTracks) {
10270
10358
  return this.call.stopPublish(TrackType.VIDEO, stopTracks);
10271
10359
  }
10272
- muteTracks() {
10273
- var _a;
10274
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((t) => (t.enabled = false));
10275
- }
10276
- unmuteTracks() {
10360
+ getTrack() {
10277
10361
  var _a;
10278
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks().forEach((t) => (t.enabled = true));
10362
+ return (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0];
10279
10363
  }
10280
10364
  }
10281
10365
 
@@ -10291,7 +10375,7 @@ class MicrophoneManagerState extends InputMediaDeviceManagerState {
10291
10375
 
10292
10376
  class MicrophoneManager extends InputMediaDeviceManager {
10293
10377
  constructor(call) {
10294
- super(call, new MicrophoneManagerState());
10378
+ super(call, new MicrophoneManagerState(), TrackType.AUDIO);
10295
10379
  }
10296
10380
  getDevices() {
10297
10381
  return getAudioDevices();
@@ -10305,13 +10389,9 @@ class MicrophoneManager extends InputMediaDeviceManager {
10305
10389
  stopPublishStream(stopTracks) {
10306
10390
  return this.call.stopPublish(TrackType.AUDIO, stopTracks);
10307
10391
  }
10308
- muteTracks() {
10309
- var _a;
10310
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((t) => (t.enabled = false));
10311
- }
10312
- unmuteTracks() {
10392
+ getTrack() {
10313
10393
  var _a;
10314
- (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().forEach((t) => (t.enabled = true));
10394
+ return (_a = this.state.mediaStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
10315
10395
  }
10316
10396
  }
10317
10397
 
@@ -10997,7 +11077,7 @@ class Call {
10997
11077
  */
10998
11078
  this.stopPublish = (trackType, stopTrack = true) => __awaiter(this, void 0, void 0, function* () {
10999
11079
  var _j;
11000
- this.logger('info', `stopPublish ${TrackType[trackType]}`);
11080
+ this.logger('info', `stopPublish ${TrackType[trackType]}, stop tracks: ${stopTrack}`);
11001
11081
  yield ((_j = this.publisher) === null || _j === void 0 ? void 0 : _j.unpublishStream(trackType, stopTrack));
11002
11082
  });
11003
11083
  /**
@@ -11575,6 +11655,40 @@ class Call {
11575
11655
  this.leaveCallHooks.add(createSubscription(this.trackSubscriptionsSubject.pipe(debounce((v) => timer(v.type)), map$2((v) => v.data)), (subscriptions) => { var _a; return (_a = this.sfuClient) === null || _a === void 0 ? void 0 : _a.updateSubscriptions(subscriptions); }));
11576
11656
  this.camera = new CameraManager(this);
11577
11657
  this.microphone = new MicrophoneManager(this);
11658
+ // FIXME OL: disable soft-mutes as they are not working properly
11659
+ // this.state.localParticipant$.subscribe(async (p) => {
11660
+ // if (!this.publisher) return;
11661
+ // // Mute via device manager
11662
+ // // If integrator doesn't use device manager, we mute using stopPublish
11663
+ // if (
11664
+ // this.publisher.hasEverPublished(TrackType.VIDEO) &&
11665
+ // this.publisher.isPublishing(TrackType.VIDEO) &&
11666
+ // !p?.publishedTracks.includes(TrackType.VIDEO)
11667
+ // ) {
11668
+ // this.logger(
11669
+ // 'info',
11670
+ // `Local participant's video track is muted remotely`,
11671
+ // );
11672
+ // await this.camera.disable();
11673
+ // if (this.publisher.isPublishing(TrackType.VIDEO)) {
11674
+ // await this.stopPublish(TrackType.VIDEO);
11675
+ // }
11676
+ // }
11677
+ // if (
11678
+ // this.publisher.hasEverPublished(TrackType.AUDIO) &&
11679
+ // this.publisher.isPublishing(TrackType.AUDIO) &&
11680
+ // !p?.publishedTracks.includes(TrackType.AUDIO)
11681
+ // ) {
11682
+ // this.logger(
11683
+ // 'info',
11684
+ // `Local participant's audio track is muted remotely`,
11685
+ // );
11686
+ // await this.microphone.disable();
11687
+ // if (this.publisher.isPublishing(TrackType.AUDIO)) {
11688
+ // await this.stopPublish(TrackType.AUDIO);
11689
+ // }
11690
+ // }
11691
+ // });
11578
11692
  this.speaker = new SpeakerManager();
11579
11693
  }
11580
11694
  registerEffects() {
@@ -11600,9 +11714,27 @@ class Call {
11600
11714
  };
11601
11715
  for (const [permission, trackType] of Object.entries(permissionToTrackType)) {
11602
11716
  const hasPermission = this.permissionsContext.hasPermission(permission);
11603
- if (!hasPermission && this.publisher.isPublishing(trackType)) {
11604
- this.stopPublish(trackType).catch((err) => {
11717
+ if (!hasPermission &&
11718
+ (this.publisher.isPublishing(trackType) ||
11719
+ this.publisher.isLive(trackType))) {
11720
+ // Stop tracks, then notify device manager
11721
+ this.stopPublish(trackType)
11722
+ .catch((err) => {
11605
11723
  this.logger('error', `Error stopping publish ${trackType}`, err);
11724
+ })
11725
+ .then(() => {
11726
+ if (trackType === TrackType.VIDEO &&
11727
+ this.camera.state.status === 'enabled') {
11728
+ this.camera
11729
+ .disable()
11730
+ .catch((err) => this.logger('error', `Error disabling camera after pemission revoked`, err));
11731
+ }
11732
+ if (trackType === TrackType.AUDIO &&
11733
+ this.microphone.state.status === 'enabled') {
11734
+ this.microphone
11735
+ .disable()
11736
+ .catch((err) => this.logger('error', `Error disabling microphone after pemission revoked`, err));
11737
+ }
11606
11738
  });
11607
11739
  }
11608
11740
  }
@@ -12865,11 +12997,11 @@ class WSConnectionFallback {
12865
12997
  }
12866
12998
  }
12867
12999
 
12868
- const version = '0.3.13';
13000
+ const version = '0.3.15';
12869
13001
 
12870
13002
  const logger = getLogger(['location']);
12871
13003
  const HINT_URL = `https://hint.stream-io-video.com/`;
12872
- const getLocationHint = (hintUrl = HINT_URL, timeout = 1500) => __awaiter(void 0, void 0, void 0, function* () {
13004
+ const getLocationHint = (hintUrl = HINT_URL, timeout = 2000) => __awaiter(void 0, void 0, void 0, function* () {
12873
13005
  const abortController = new AbortController();
12874
13006
  const timeoutId = setTimeout(() => abortController.abort(), timeout);
12875
13007
  try {
@@ -12882,7 +13014,7 @@ const getLocationHint = (hintUrl = HINT_URL, timeout = 1500) => __awaiter(void 0
12882
13014
  return awsPop.substring(0, 3); // AMS1-P2 -> AMS
12883
13015
  }
12884
13016
  catch (e) {
12885
- logger('error', `Failed to get location hint from ${HINT_URL}`, e);
13017
+ logger('warn', `Failed to get location hint from ${HINT_URL}`, e);
12886
13018
  return 'ERR';
12887
13019
  }
12888
13020
  finally {