@stream-io/video-client 1.46.0 → 1.47.0
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 +18 -0
- package/dist/index.browser.es.js +65 -21
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +65 -21
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +65 -21
- package/dist/index.es.js.map +1 -1
- package/dist/src/gen/coordinator/index.d.ts +6 -0
- package/dist/src/helpers/RNSpeechDetector.d.ts +4 -2
- package/package.json +1 -1
- package/src/devices/CameraManager.ts +9 -2
- package/src/devices/DeviceManager.ts +13 -3
- package/src/devices/MicrophoneManager.ts +8 -1
- package/src/devices/SpeakerManager.ts +16 -4
- package/src/devices/__tests__/CameraManager.test.ts +32 -0
- package/src/devices/__tests__/DeviceManager.test.ts +71 -0
- package/src/devices/__tests__/MicrophoneManager.test.ts +23 -0
- package/src/devices/__tests__/SpeakerManager.test.ts +28 -0
- package/src/gen/coordinator/index.ts +6 -0
- package/src/helpers/RNSpeechDetector.ts +52 -16
- package/src/helpers/__tests__/RNSpeechDetector.test.ts +52 -0
package/dist/index.es.js
CHANGED
|
@@ -6285,7 +6285,7 @@ const getSdkVersion = (sdk) => {
|
|
|
6285
6285
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
6286
6286
|
};
|
|
6287
6287
|
|
|
6288
|
-
const version = "1.
|
|
6288
|
+
const version = "1.47.0";
|
|
6289
6289
|
const [major, minor, patch] = version.split('.');
|
|
6290
6290
|
let sdkInfo = {
|
|
6291
6291
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -10866,8 +10866,14 @@ class DeviceManager {
|
|
|
10866
10866
|
this.handleDisconnectedOrReplacedDevices();
|
|
10867
10867
|
}
|
|
10868
10868
|
if (this.devicePersistence.enabled) {
|
|
10869
|
-
this.subscriptions.push(createSubscription(combineLatest([
|
|
10870
|
-
|
|
10869
|
+
this.subscriptions.push(createSubscription(combineLatest([
|
|
10870
|
+
this.state.selectedDevice$,
|
|
10871
|
+
this.state.status$,
|
|
10872
|
+
this.state.browserPermissionState$,
|
|
10873
|
+
]), ([selectedDevice, status, browserPermissionState]) => {
|
|
10874
|
+
if (!status ||
|
|
10875
|
+
(this.isTrackStoppedDueToTrackEnd && status === 'disabled') ||
|
|
10876
|
+
browserPermissionState !== 'granted')
|
|
10871
10877
|
return;
|
|
10872
10878
|
this.persistPreference(selectedDevice, status);
|
|
10873
10879
|
}));
|
|
@@ -11632,7 +11638,10 @@ class CameraManager extends DeviceManager {
|
|
|
11632
11638
|
const shouldApplyDefaults = this.state.status === undefined &&
|
|
11633
11639
|
this.state.optimisticStatus === undefined;
|
|
11634
11640
|
let persistedPreferencesApplied = false;
|
|
11635
|
-
|
|
11641
|
+
const permissionState = await firstValueFrom(this.state.browserPermissionState$);
|
|
11642
|
+
if (shouldApplyDefaults &&
|
|
11643
|
+
this.devicePersistence.enabled &&
|
|
11644
|
+
permissionState === 'granted') {
|
|
11636
11645
|
persistedPreferencesApplied =
|
|
11637
11646
|
await this.applyPersistedPreferences(enabledInCallType);
|
|
11638
11647
|
}
|
|
@@ -11928,35 +11937,43 @@ class RNSpeechDetector {
|
|
|
11928
11937
|
constructor(externalAudioStream) {
|
|
11929
11938
|
this.pc1 = new RTCPeerConnection({});
|
|
11930
11939
|
this.pc2 = new RTCPeerConnection({});
|
|
11940
|
+
this.isStopped = false;
|
|
11931
11941
|
this.externalAudioStream = externalAudioStream;
|
|
11932
11942
|
}
|
|
11933
11943
|
/**
|
|
11934
11944
|
* Starts the speech detection.
|
|
11935
11945
|
*/
|
|
11936
11946
|
async start(onSoundDetectedStateChanged) {
|
|
11947
|
+
let detachListeners;
|
|
11948
|
+
let unsubscribe;
|
|
11937
11949
|
try {
|
|
11950
|
+
this.isStopped = false;
|
|
11938
11951
|
const audioStream = this.externalAudioStream != null
|
|
11939
11952
|
? this.externalAudioStream
|
|
11940
11953
|
: await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
11941
11954
|
this.audioStream = audioStream;
|
|
11942
|
-
|
|
11943
|
-
this.pc2
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
// do nothing
|
|
11950
|
-
});
|
|
11951
|
-
});
|
|
11952
|
-
this.pc2.addEventListener('track', (e) => {
|
|
11955
|
+
const onPc1IceCandidate = (e) => {
|
|
11956
|
+
this.forwardIceCandidate(this.pc2, e.candidate);
|
|
11957
|
+
};
|
|
11958
|
+
const onPc2IceCandidate = (e) => {
|
|
11959
|
+
this.forwardIceCandidate(this.pc1, e.candidate);
|
|
11960
|
+
};
|
|
11961
|
+
const onTrackPc2 = (e) => {
|
|
11953
11962
|
e.streams[0].getTracks().forEach((track) => {
|
|
11954
11963
|
// In RN, the remote track is automatically added to the audio output device
|
|
11955
11964
|
// so we need to mute it to avoid hearing the audio back
|
|
11956
11965
|
// @ts-expect-error _setVolume is a private method in react-native-webrtc
|
|
11957
11966
|
track._setVolume(0);
|
|
11958
11967
|
});
|
|
11959
|
-
}
|
|
11968
|
+
};
|
|
11969
|
+
this.pc1.addEventListener('icecandidate', onPc1IceCandidate);
|
|
11970
|
+
this.pc2.addEventListener('icecandidate', onPc2IceCandidate);
|
|
11971
|
+
this.pc2.addEventListener('track', onTrackPc2);
|
|
11972
|
+
detachListeners = () => {
|
|
11973
|
+
this.pc1.removeEventListener('icecandidate', onPc1IceCandidate);
|
|
11974
|
+
this.pc2.removeEventListener('icecandidate', onPc2IceCandidate);
|
|
11975
|
+
this.pc2.removeEventListener('track', onTrackPc2);
|
|
11976
|
+
};
|
|
11960
11977
|
audioStream
|
|
11961
11978
|
.getTracks()
|
|
11962
11979
|
.forEach((track) => this.pc1.addTrack(track, audioStream));
|
|
@@ -11966,13 +11983,17 @@ class RNSpeechDetector {
|
|
|
11966
11983
|
const answer = await this.pc2.createAnswer();
|
|
11967
11984
|
await this.pc1.setRemoteDescription(answer);
|
|
11968
11985
|
await this.pc2.setLocalDescription(answer);
|
|
11969
|
-
|
|
11986
|
+
unsubscribe = this.onSpeakingDetectedStateChange(onSoundDetectedStateChanged);
|
|
11970
11987
|
return () => {
|
|
11971
|
-
|
|
11988
|
+
detachListeners?.();
|
|
11989
|
+
unsubscribe?.();
|
|
11972
11990
|
this.stop();
|
|
11973
11991
|
};
|
|
11974
11992
|
}
|
|
11975
11993
|
catch (error) {
|
|
11994
|
+
detachListeners?.();
|
|
11995
|
+
unsubscribe?.();
|
|
11996
|
+
this.stop();
|
|
11976
11997
|
const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
|
|
11977
11998
|
logger.error('error handling permissions: ', error);
|
|
11978
11999
|
return () => { };
|
|
@@ -11982,6 +12003,9 @@ class RNSpeechDetector {
|
|
|
11982
12003
|
* Stops the speech detection and releases all allocated resources.
|
|
11983
12004
|
*/
|
|
11984
12005
|
stop() {
|
|
12006
|
+
if (this.isStopped)
|
|
12007
|
+
return;
|
|
12008
|
+
this.isStopped = true;
|
|
11985
12009
|
this.pc1.close();
|
|
11986
12010
|
this.pc2.close();
|
|
11987
12011
|
if (this.externalAudioStream != null) {
|
|
@@ -12081,6 +12105,18 @@ class RNSpeechDetector {
|
|
|
12081
12105
|
this.audioStream.release();
|
|
12082
12106
|
}
|
|
12083
12107
|
}
|
|
12108
|
+
forwardIceCandidate(destination, candidate) {
|
|
12109
|
+
if (this.isStopped ||
|
|
12110
|
+
!candidate ||
|
|
12111
|
+
destination.signalingState === 'closed') {
|
|
12112
|
+
return;
|
|
12113
|
+
}
|
|
12114
|
+
destination.addIceCandidate(candidate).catch(() => {
|
|
12115
|
+
// silently ignore the error
|
|
12116
|
+
const logger = videoLoggerSystem.getLogger('RNSpeechDetector');
|
|
12117
|
+
logger.info('cannot add ice candidate - ignoring');
|
|
12118
|
+
});
|
|
12119
|
+
}
|
|
12084
12120
|
}
|
|
12085
12121
|
|
|
12086
12122
|
class MicrophoneManager extends AudioDeviceManager {
|
|
@@ -12347,7 +12383,10 @@ class MicrophoneManager extends AudioDeviceManager {
|
|
|
12347
12383
|
const shouldApplyDefaults = this.state.status === undefined &&
|
|
12348
12384
|
this.state.optimisticStatus === undefined;
|
|
12349
12385
|
let persistedPreferencesApplied = false;
|
|
12350
|
-
|
|
12386
|
+
const permissionState = await firstValueFrom(this.state.browserPermissionState$);
|
|
12387
|
+
if (shouldApplyDefaults &&
|
|
12388
|
+
this.devicePersistence.enabled &&
|
|
12389
|
+
permissionState === 'granted') {
|
|
12351
12390
|
persistedPreferencesApplied = await this.applyPersistedPreferences(true);
|
|
12352
12391
|
}
|
|
12353
12392
|
const canPublish = this.call.permissionsContext.canPublish(this.trackType);
|
|
@@ -12731,7 +12770,12 @@ class SpeakerManager {
|
|
|
12731
12770
|
}));
|
|
12732
12771
|
}
|
|
12733
12772
|
if (!isReactNative() && this.devicePersistence.enabled) {
|
|
12734
|
-
this.subscriptions.push(createSubscription(
|
|
12773
|
+
this.subscriptions.push(createSubscription(combineLatest([
|
|
12774
|
+
this.state.selectedDevice$,
|
|
12775
|
+
getAudioBrowserPermission(this.call.tracer).asStateObservable(),
|
|
12776
|
+
]), ([selectedDevice, browserPermissionState]) => {
|
|
12777
|
+
if (!selectedDevice || browserPermissionState !== 'granted')
|
|
12778
|
+
return;
|
|
12735
12779
|
this.persistSpeakerDevicePreference(selectedDevice);
|
|
12736
12780
|
}));
|
|
12737
12781
|
}
|
|
@@ -16106,7 +16150,7 @@ class StreamClient {
|
|
|
16106
16150
|
this.getUserAgent = () => {
|
|
16107
16151
|
if (!this.cachedUserAgent) {
|
|
16108
16152
|
const { clientAppIdentifier = {} } = this.options;
|
|
16109
|
-
const { sdkName = 'js', sdkVersion = "1.
|
|
16153
|
+
const { sdkName = 'js', sdkVersion = "1.47.0", ...extras } = clientAppIdentifier;
|
|
16110
16154
|
this.cachedUserAgent = [
|
|
16111
16155
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
16112
16156
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|