@stream-io/video-client 0.0.7 → 0.0.9
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 +37 -10
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +37 -10
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +37 -10
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +6 -0
- package/dist/src/rtc/publisher.d.ts +6 -0
- package/package.json +1 -1
- package/src/Call.ts +25 -6
- package/src/rtc/publisher.ts +14 -0
- package/src/rtc/signal.ts +3 -3
package/dist/src/Call.d.ts
CHANGED
|
@@ -30,6 +30,12 @@ export declare class Call {
|
|
|
30
30
|
* The state of this call.
|
|
31
31
|
*/
|
|
32
32
|
readonly state: CallState;
|
|
33
|
+
private rejoinPromise;
|
|
34
|
+
/**
|
|
35
|
+
* A promise that exposes the reconnection logic
|
|
36
|
+
* The use-case is for the react-native platform where online/offline events are not available in the window
|
|
37
|
+
*/
|
|
38
|
+
get rejoin(): (() => Promise<void>) | undefined;
|
|
33
39
|
/**
|
|
34
40
|
* Flag indicating whether this call is "watched" and receives
|
|
35
41
|
* updates from the backend.
|
|
@@ -41,6 +41,12 @@ export declare class Publisher {
|
|
|
41
41
|
* @param trackType the track type to unpublish.
|
|
42
42
|
*/
|
|
43
43
|
unpublishStream: (trackType: TrackType) => Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Returns true if the given track type is currently being published to the SFU.
|
|
46
|
+
*
|
|
47
|
+
* @param trackType the track type to check.
|
|
48
|
+
*/
|
|
49
|
+
isPublishing: (trackType: TrackType) => boolean;
|
|
44
50
|
private notifyTrackMuteStateChanged;
|
|
45
51
|
/**
|
|
46
52
|
* Stops publishing all tracks and stop all tracks.
|
package/package.json
CHANGED
package/src/Call.ts
CHANGED
|
@@ -135,6 +135,16 @@ export class Call {
|
|
|
135
135
|
*/
|
|
136
136
|
readonly state = new CallState();
|
|
137
137
|
|
|
138
|
+
private rejoinPromise: (() => Promise<void>) | undefined;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* A promise that exposes the reconnection logic
|
|
142
|
+
* The use-case is for the react-native platform where online/offline events are not available in the window
|
|
143
|
+
*/
|
|
144
|
+
get rejoin(): (() => Promise<void>) | undefined {
|
|
145
|
+
return this.rejoinPromise;
|
|
146
|
+
}
|
|
147
|
+
|
|
138
148
|
/**
|
|
139
149
|
* Flag indicating whether this call is "watched" and receives
|
|
140
150
|
* updates from the backend.
|
|
@@ -254,22 +264,26 @@ export class Call {
|
|
|
254
264
|
// update the permission context.
|
|
255
265
|
this.permissionsContext.setPermissions(ownCapabilities);
|
|
256
266
|
|
|
267
|
+
if (!this.publisher) return;
|
|
268
|
+
|
|
257
269
|
// check if the user still has publishing permissions and stop publishing if not.
|
|
258
270
|
const permissionToTrackType = {
|
|
259
271
|
[OwnCapability.SEND_AUDIO]: TrackType.AUDIO,
|
|
260
272
|
[OwnCapability.SEND_VIDEO]: TrackType.VIDEO,
|
|
261
273
|
[OwnCapability.SCREENSHARE]: TrackType.SCREEN_SHARE,
|
|
262
274
|
};
|
|
263
|
-
|
|
275
|
+
for (const [permission, trackType] of Object.entries(
|
|
276
|
+
permissionToTrackType,
|
|
277
|
+
)) {
|
|
264
278
|
const hasPermission = this.permissionsContext.hasPermission(
|
|
265
279
|
permission as OwnCapability,
|
|
266
280
|
);
|
|
267
|
-
if (!hasPermission) {
|
|
268
|
-
this.stopPublish(
|
|
269
|
-
console.error('Error stopping publish',
|
|
281
|
+
if (!hasPermission && this.publisher.isPublishing(trackType)) {
|
|
282
|
+
this.stopPublish(trackType).catch((err) => {
|
|
283
|
+
console.error('Error stopping publish', trackType, err);
|
|
270
284
|
});
|
|
271
285
|
}
|
|
272
|
-
}
|
|
286
|
+
}
|
|
273
287
|
}),
|
|
274
288
|
|
|
275
289
|
// handles the case when the user is blocked by the call owner.
|
|
@@ -370,6 +384,7 @@ export class Call {
|
|
|
370
384
|
if (callingState === CallingState.LEFT) {
|
|
371
385
|
throw new Error('Cannot leave call that has already been left.');
|
|
372
386
|
}
|
|
387
|
+
this.rejoinPromise = undefined;
|
|
373
388
|
|
|
374
389
|
if (this.ringing) {
|
|
375
390
|
// I'm the one who started the call, so I should cancel it.
|
|
@@ -642,7 +657,7 @@ export class Call {
|
|
|
642
657
|
await sleep(retryInterval(this.reconnectAttempts));
|
|
643
658
|
await this.join(data);
|
|
644
659
|
console.log(`Rejoin: ${this.reconnectAttempts} successful!`);
|
|
645
|
-
if (localParticipant) {
|
|
660
|
+
if (localParticipant && !isReactNative()) {
|
|
646
661
|
const {
|
|
647
662
|
audioStream,
|
|
648
663
|
videoStream,
|
|
@@ -657,6 +672,8 @@ export class Call {
|
|
|
657
672
|
console.log(`Rejoin: state restored ${this.reconnectAttempts}`);
|
|
658
673
|
};
|
|
659
674
|
|
|
675
|
+
this.rejoinPromise = rejoin;
|
|
676
|
+
|
|
660
677
|
// reconnect if the connection was closed unexpectedly. example:
|
|
661
678
|
// - SFU crash or restart
|
|
662
679
|
// - network change
|
|
@@ -667,6 +684,8 @@ export class Call {
|
|
|
667
684
|
// do nothing if the connection was closed because of a policy violation
|
|
668
685
|
// e.g., the user has been blocked by an admin or moderator
|
|
669
686
|
if (e.code === KnownCodes.WS_POLICY_VIOLATION) return;
|
|
687
|
+
// do nothing for react-native as its handled by SDK
|
|
688
|
+
if (isReactNative()) return;
|
|
670
689
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
671
690
|
rejoin().catch(() => {
|
|
672
691
|
console.log(
|
package/src/rtc/publisher.ts
CHANGED
|
@@ -214,6 +214,20 @@ export class Publisher {
|
|
|
214
214
|
}
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Returns true if the given track type is currently being published to the SFU.
|
|
219
|
+
*
|
|
220
|
+
* @param trackType the track type to check.
|
|
221
|
+
*/
|
|
222
|
+
isPublishing = (trackType: TrackType): boolean => {
|
|
223
|
+
const transceiverForTrackType = this.transceiverRegistry[trackType];
|
|
224
|
+
if (transceiverForTrackType && transceiverForTrackType.sender) {
|
|
225
|
+
const sender = transceiverForTrackType.sender;
|
|
226
|
+
return !!sender.track && sender.track.readyState === 'live';
|
|
227
|
+
}
|
|
228
|
+
return false;
|
|
229
|
+
};
|
|
230
|
+
|
|
217
231
|
private notifyTrackMuteStateChanged = async (
|
|
218
232
|
mediaStream: MediaStream | undefined,
|
|
219
233
|
track: MediaStreamTrack,
|
package/src/rtc/signal.ts
CHANGED
|
@@ -9,15 +9,15 @@ export const createWebSocketSignalChannel = (opts: {
|
|
|
9
9
|
ws.binaryType = 'arraybuffer'; // do we need this?
|
|
10
10
|
|
|
11
11
|
ws.addEventListener('error', (e) => {
|
|
12
|
-
console.
|
|
12
|
+
console.log('Signaling WS channel error', e);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
ws.addEventListener('close', (e) => {
|
|
16
|
-
console.
|
|
16
|
+
console.log('Signaling WS channel is closed', e);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
ws.addEventListener('open', (e) => {
|
|
20
|
-
console.log('
|
|
20
|
+
console.log('Signaling WS channel is open', e);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
if (onMessage) {
|