@stream-io/video-client 1.8.0 → 1.8.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.
- package/CHANGELOG.md +14 -0
- package/dist/index.browser.es.js +63 -15
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +63 -15
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +63 -15
- package/dist/index.es.js.map +1 -1
- package/dist/src/helpers/RNSpeechDetector.d.ts +2 -0
- package/package.json +1 -1
- package/src/devices/InputMediaDeviceManager.ts +8 -1
- package/src/devices/devices.ts +5 -0
- package/src/events/call.ts +2 -3
- package/src/helpers/RNSpeechDetector.ts +25 -0
- package/src/rtc/Publisher.ts +24 -11
|
@@ -3,6 +3,7 @@ export declare class RNSpeechDetector {
|
|
|
3
3
|
private pc1;
|
|
4
4
|
private pc2;
|
|
5
5
|
private intervalId;
|
|
6
|
+
private audioStream;
|
|
6
7
|
/**
|
|
7
8
|
* Starts the speech detection.
|
|
8
9
|
*/
|
|
@@ -15,4 +16,5 @@ export declare class RNSpeechDetector {
|
|
|
15
16
|
* Public method that detects the audio levels and returns the status.
|
|
16
17
|
*/
|
|
17
18
|
onSpeakingDetectedStateChange(onSoundDetectedStateChanged: SoundStateChangeHandler): () => void;
|
|
19
|
+
private cleanupAudioStream;
|
|
18
20
|
}
|
package/package.json
CHANGED
|
@@ -279,7 +279,14 @@ export abstract class InputMediaDeviceManager<
|
|
|
279
279
|
|
|
280
280
|
private stopTracks() {
|
|
281
281
|
this.getTracks().forEach((track) => {
|
|
282
|
-
if (track.readyState === 'live')
|
|
282
|
+
if (track.readyState === 'live') {
|
|
283
|
+
track.stop();
|
|
284
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
285
|
+
if (typeof track.release === 'function') {
|
|
286
|
+
// @ts-expect-error
|
|
287
|
+
track.release();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
283
290
|
});
|
|
284
291
|
}
|
|
285
292
|
|
package/src/devices/devices.ts
CHANGED
|
@@ -277,6 +277,11 @@ export const disposeOfMediaStream = (stream: MediaStream) => {
|
|
|
277
277
|
stream.getTracks().forEach((track) => {
|
|
278
278
|
track.stop();
|
|
279
279
|
stream.removeTrack(track);
|
|
280
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
281
|
+
if (typeof track.release === 'function') {
|
|
282
|
+
// @ts-expect-error
|
|
283
|
+
track.release();
|
|
284
|
+
}
|
|
280
285
|
});
|
|
281
286
|
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
282
287
|
if (typeof stream.release === 'function') {
|
package/src/events/call.ts
CHANGED
|
@@ -76,9 +76,8 @@ export const watchCallEnded = (call: Call) => {
|
|
|
76
76
|
return function onCallEnded() {
|
|
77
77
|
const { callingState } = call.state;
|
|
78
78
|
if (
|
|
79
|
-
callingState
|
|
80
|
-
callingState
|
|
81
|
-
callingState === CallingState.JOINING
|
|
79
|
+
callingState !== CallingState.IDLE &&
|
|
80
|
+
callingState !== CallingState.LEFT
|
|
82
81
|
) {
|
|
83
82
|
call.leave({ reason: 'call.ended event received' }).catch((err) => {
|
|
84
83
|
call.logger('error', 'Failed to leave call after call.ended ', err);
|
|
@@ -8,15 +8,18 @@ export class RNSpeechDetector {
|
|
|
8
8
|
private pc1 = new RTCPeerConnection({});
|
|
9
9
|
private pc2 = new RTCPeerConnection({});
|
|
10
10
|
private intervalId: NodeJS.Timeout | undefined;
|
|
11
|
+
private audioStream: MediaStream | undefined;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Starts the speech detection.
|
|
14
15
|
*/
|
|
15
16
|
public async start() {
|
|
16
17
|
try {
|
|
18
|
+
this.cleanupAudioStream();
|
|
17
19
|
const audioStream = await navigator.mediaDevices.getUserMedia({
|
|
18
20
|
audio: true,
|
|
19
21
|
});
|
|
22
|
+
this.audioStream = audioStream;
|
|
20
23
|
|
|
21
24
|
this.pc1.addEventListener('icecandidate', async (e) => {
|
|
22
25
|
await this.pc2.addIceCandidate(
|
|
@@ -55,6 +58,7 @@ export class RNSpeechDetector {
|
|
|
55
58
|
public stop() {
|
|
56
59
|
this.pc1.close();
|
|
57
60
|
this.pc2.close();
|
|
61
|
+
this.cleanupAudioStream();
|
|
58
62
|
if (this.intervalId) {
|
|
59
63
|
clearInterval(this.intervalId);
|
|
60
64
|
}
|
|
@@ -97,4 +101,25 @@ export class RNSpeechDetector {
|
|
|
97
101
|
clearInterval(this.intervalId);
|
|
98
102
|
};
|
|
99
103
|
}
|
|
104
|
+
|
|
105
|
+
private cleanupAudioStream() {
|
|
106
|
+
if (!this.audioStream) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
this.audioStream.getTracks().forEach((track) => {
|
|
110
|
+
track.stop();
|
|
111
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
112
|
+
if (typeof track.release === 'function') {
|
|
113
|
+
// @ts-expect-error
|
|
114
|
+
track.release();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
if (
|
|
118
|
+
// @ts-expect-error release() is present in react-native-webrtc
|
|
119
|
+
typeof this.audioStream.release === 'function'
|
|
120
|
+
) {
|
|
121
|
+
// @ts-expect-error called to dispose the stream in RN
|
|
122
|
+
this.audioStream.release();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
100
125
|
}
|
package/src/rtc/Publisher.ts
CHANGED
|
@@ -316,6 +316,11 @@ export class Publisher {
|
|
|
316
316
|
if (previousTrack && previousTrack !== track) {
|
|
317
317
|
previousTrack.stop();
|
|
318
318
|
previousTrack.removeEventListener('ended', handleTrackEnded);
|
|
319
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
320
|
+
if (typeof previousTrack.release === 'function') {
|
|
321
|
+
// @ts-expect-error
|
|
322
|
+
track.release();
|
|
323
|
+
}
|
|
319
324
|
track.addEventListener('ended', handleTrackEnded);
|
|
320
325
|
}
|
|
321
326
|
if (!track.enabled) {
|
|
@@ -337,16 +342,18 @@ export class Publisher {
|
|
|
337
342
|
const transceiver = this.pc
|
|
338
343
|
.getTransceivers()
|
|
339
344
|
.find((t) => t === this.transceiverRegistry[trackType] && t.sender.track);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
345
|
+
const track = transceiver?.sender.track;
|
|
346
|
+
if (track && (stopTrack ? track.readyState === 'live' : track.enabled)) {
|
|
347
|
+
if (stopTrack) {
|
|
348
|
+
track.stop();
|
|
349
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
350
|
+
if (typeof track.release === 'function') {
|
|
351
|
+
// @ts-expect-error
|
|
352
|
+
track.release();
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
355
|
+
track.enabled = false;
|
|
356
|
+
}
|
|
350
357
|
// We don't need to notify SFU if unpublishing in response to remote soft mute
|
|
351
358
|
if (this.state.localParticipant?.publishedTracks.includes(trackType)) {
|
|
352
359
|
await this.notifyTrackMuteStateChanged(undefined, trackType, true);
|
|
@@ -399,7 +406,13 @@ export class Publisher {
|
|
|
399
406
|
private stopPublishing = () => {
|
|
400
407
|
this.logger('debug', 'Stopping publishing all tracks');
|
|
401
408
|
this.pc.getSenders().forEach((s) => {
|
|
402
|
-
s.track
|
|
409
|
+
const track = s.track;
|
|
410
|
+
track?.stop();
|
|
411
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the track
|
|
412
|
+
if (typeof track?.release === 'function') {
|
|
413
|
+
// @ts-expect-error
|
|
414
|
+
track.release();
|
|
415
|
+
}
|
|
403
416
|
if (this.pc.signalingState !== 'closed') {
|
|
404
417
|
this.pc.removeTrack(s);
|
|
405
418
|
}
|