@stream-io/video-client 1.46.0 → 1.46.1

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
@@ -6304,7 +6304,7 @@ const getSdkVersion = (sdk) => {
6304
6304
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
6305
6305
  };
6306
6306
 
6307
- const version = "1.46.0";
6307
+ const version = "1.46.1";
6308
6308
  const [major, minor, patch] = version.split('.');
6309
6309
  let sdkInfo = {
6310
6310
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -11947,35 +11947,43 @@ class RNSpeechDetector {
11947
11947
  constructor(externalAudioStream) {
11948
11948
  this.pc1 = new RTCPeerConnection({});
11949
11949
  this.pc2 = new RTCPeerConnection({});
11950
+ this.isStopped = false;
11950
11951
  this.externalAudioStream = externalAudioStream;
11951
11952
  }
11952
11953
  /**
11953
11954
  * Starts the speech detection.
11954
11955
  */
11955
11956
  async start(onSoundDetectedStateChanged) {
11957
+ let detachListeners;
11958
+ let unsubscribe;
11956
11959
  try {
11960
+ this.isStopped = false;
11957
11961
  const audioStream = this.externalAudioStream != null
11958
11962
  ? this.externalAudioStream
11959
11963
  : await navigator.mediaDevices.getUserMedia({ audio: true });
11960
11964
  this.audioStream = audioStream;
11961
- this.pc1.addEventListener('icecandidate', (e) => {
11962
- this.pc2.addIceCandidate(e.candidate).catch(() => {
11963
- // do nothing
11964
- });
11965
- });
11966
- this.pc2.addEventListener('icecandidate', async (e) => {
11967
- this.pc1.addIceCandidate(e.candidate).catch(() => {
11968
- // do nothing
11969
- });
11970
- });
11971
- this.pc2.addEventListener('track', (e) => {
11965
+ const onPc1IceCandidate = (e) => {
11966
+ this.forwardIceCandidate(this.pc2, e.candidate);
11967
+ };
11968
+ const onPc2IceCandidate = (e) => {
11969
+ this.forwardIceCandidate(this.pc1, e.candidate);
11970
+ };
11971
+ const onTrackPc2 = (e) => {
11972
11972
  e.streams[0].getTracks().forEach((track) => {
11973
11973
  // In RN, the remote track is automatically added to the audio output device
11974
11974
  // so we need to mute it to avoid hearing the audio back
11975
11975
  // @ts-expect-error _setVolume is a private method in react-native-webrtc
11976
11976
  track._setVolume(0);
11977
11977
  });
11978
- });
11978
+ };
11979
+ this.pc1.addEventListener('icecandidate', onPc1IceCandidate);
11980
+ this.pc2.addEventListener('icecandidate', onPc2IceCandidate);
11981
+ this.pc2.addEventListener('track', onTrackPc2);
11982
+ detachListeners = () => {
11983
+ this.pc1.removeEventListener('icecandidate', onPc1IceCandidate);
11984
+ this.pc2.removeEventListener('icecandidate', onPc2IceCandidate);
11985
+ this.pc2.removeEventListener('track', onTrackPc2);
11986
+ };
11979
11987
  audioStream
11980
11988
  .getTracks()
11981
11989
  .forEach((track) => this.pc1.addTrack(track, audioStream));
@@ -11985,13 +11993,17 @@ class RNSpeechDetector {
11985
11993
  const answer = await this.pc2.createAnswer();
11986
11994
  await this.pc1.setRemoteDescription(answer);
11987
11995
  await this.pc2.setLocalDescription(answer);
11988
- const unsubscribe = this.onSpeakingDetectedStateChange(onSoundDetectedStateChanged);
11996
+ unsubscribe = this.onSpeakingDetectedStateChange(onSoundDetectedStateChanged);
11989
11997
  return () => {
11990
- unsubscribe();
11998
+ detachListeners?.();
11999
+ unsubscribe?.();
11991
12000
  this.stop();
11992
12001
  };
11993
12002
  }
11994
12003
  catch (error) {
12004
+ detachListeners?.();
12005
+ unsubscribe?.();
12006
+ this.stop();
11995
12007
  const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
11996
12008
  logger.error('error handling permissions: ', error);
11997
12009
  return () => { };
@@ -12001,6 +12013,9 @@ class RNSpeechDetector {
12001
12013
  * Stops the speech detection and releases all allocated resources.
12002
12014
  */
12003
12015
  stop() {
12016
+ if (this.isStopped)
12017
+ return;
12018
+ this.isStopped = true;
12004
12019
  this.pc1.close();
12005
12020
  this.pc2.close();
12006
12021
  if (this.externalAudioStream != null) {
@@ -12100,6 +12115,18 @@ class RNSpeechDetector {
12100
12115
  this.audioStream.release();
12101
12116
  }
12102
12117
  }
12118
+ forwardIceCandidate(destination, candidate) {
12119
+ if (this.isStopped ||
12120
+ !candidate ||
12121
+ destination.signalingState === 'closed') {
12122
+ return;
12123
+ }
12124
+ destination.addIceCandidate(candidate).catch(() => {
12125
+ // silently ignore the error
12126
+ const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
12127
+ logger.info('cannot add ice candidate - ignoring');
12128
+ });
12129
+ }
12103
12130
  }
12104
12131
 
12105
12132
  class MicrophoneManager extends AudioDeviceManager {
@@ -16125,7 +16152,7 @@ class StreamClient {
16125
16152
  this.getUserAgent = () => {
16126
16153
  if (!this.cachedUserAgent) {
16127
16154
  const { clientAppIdentifier = {} } = this.options;
16128
- const { sdkName = 'js', sdkVersion = "1.46.0", ...extras } = clientAppIdentifier;
16155
+ const { sdkName = 'js', sdkVersion = "1.46.1", ...extras } = clientAppIdentifier;
16129
16156
  this.cachedUserAgent = [
16130
16157
  `stream-video-${sdkName}-v${sdkVersion}`,
16131
16158
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),