@stream-io/video-client 1.0.0 → 1.0.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/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +254 -2
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +254 -2
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +254 -2
- package/dist/index.es.js.map +1 -1
- package/dist/src/events/participant.d.ts +5 -1
- package/dist/src/gen/video/sfu/event/events.d.ts +71 -1
- package/dist/src/gen/video/sfu/models/models.d.ts +70 -0
- package/package.json +1 -1
- package/src/events/__tests__/participant.test.ts +28 -1
- package/src/events/callEventHandlers.ts +2 -0
- package/src/events/participant.ts +12 -0
- package/src/gen/video/sfu/event/events.ts +284 -0
- package/src/gen/video/sfu/models/models.ts +70 -0
- package/src/rtc/Dispatcher.ts +2 -0
- package/src/store/CallState.ts +3 -0
- package/src/store/__tests__/CallState.test.ts +9 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ParticipantJoined, ParticipantLeft, TrackPublished, TrackUnpublished } from '../gen/video/sfu/event/events';
|
|
1
|
+
import type { ParticipantJoined, ParticipantLeft, ParticipantUpdated, TrackPublished, TrackUnpublished } from '../gen/video/sfu/event/events';
|
|
2
2
|
import { CallState } from '../store';
|
|
3
3
|
/**
|
|
4
4
|
* An event responder which handles the `participantJoined` event.
|
|
@@ -8,6 +8,10 @@ export declare const watchParticipantJoined: (state: CallState) => (e: Participa
|
|
|
8
8
|
* An event responder which handles the `participantLeft` event.
|
|
9
9
|
*/
|
|
10
10
|
export declare const watchParticipantLeft: (state: CallState) => (e: ParticipantLeft) => void;
|
|
11
|
+
/**
|
|
12
|
+
* An event responder which handles the `participantUpdated` event.
|
|
13
|
+
*/
|
|
14
|
+
export declare const watchParticipantUpdated: (state: CallState) => (e: ParticipantUpdated) => void;
|
|
11
15
|
/**
|
|
12
16
|
* An event responder which handles the `trackPublished` event.
|
|
13
17
|
* The SFU will send this event when a participant publishes a track.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BinaryReadOptions, BinaryWriteOptions, IBinaryReader, IBinaryWriter, PartialMessage } from '@protobuf-ts/runtime';
|
|
2
2
|
import { MessageType } from '@protobuf-ts/runtime';
|
|
3
|
-
import { CallGrants, CallState, ClientDetails, Codec, ConnectionQuality, Error as Error$, GoAwayReason, ICETrickle as ICETrickle$, Participant, ParticipantCount, PeerType, Pin, TrackInfo, TrackType, TrackUnpublishReason } from '../models/models';
|
|
3
|
+
import { CallEndedReason, CallGrants, CallState, ClientDetails, Codec, ConnectionQuality, Error as Error$, GoAwayReason, ICETrickle as ICETrickle$, Participant, ParticipantCount, PeerType, Pin, TrackInfo, TrackType, TrackUnpublishReason, WebsocketReconnectStrategy } from '../models/models';
|
|
4
4
|
import { TrackSubscriptionDetails } from '../signal_rpc/signal';
|
|
5
5
|
/**
|
|
6
6
|
* SFUEvent is a message that is sent from the SFU to the client.
|
|
@@ -176,6 +176,23 @@ export interface SfuEvent {
|
|
|
176
176
|
* @generated from protobuf field: stream.video.sfu.event.PinsChanged pins_updated = 22;
|
|
177
177
|
*/
|
|
178
178
|
pinsUpdated: PinsChanged;
|
|
179
|
+
} | {
|
|
180
|
+
oneofKind: 'callEnded';
|
|
181
|
+
/**
|
|
182
|
+
* CallEnded is sent by the SFU to the client to signal that the call has ended.
|
|
183
|
+
* The reason may specify why the call has ended.
|
|
184
|
+
*
|
|
185
|
+
* @generated from protobuf field: stream.video.sfu.event.CallEnded call_ended = 23;
|
|
186
|
+
*/
|
|
187
|
+
callEnded: CallEnded;
|
|
188
|
+
} | {
|
|
189
|
+
oneofKind: 'participantUpdated';
|
|
190
|
+
/**
|
|
191
|
+
* ParticipantUpdated is sent when user data is updated
|
|
192
|
+
*
|
|
193
|
+
* @generated from protobuf field: stream.video.sfu.event.ParticipantUpdated participant_updated = 24;
|
|
194
|
+
*/
|
|
195
|
+
participantUpdated: ParticipantUpdated;
|
|
179
196
|
} | {
|
|
180
197
|
oneofKind: undefined;
|
|
181
198
|
};
|
|
@@ -200,6 +217,12 @@ export interface Error {
|
|
|
200
217
|
* @generated from protobuf field: stream.video.sfu.models.Error error = 4;
|
|
201
218
|
*/
|
|
202
219
|
error?: Error$;
|
|
220
|
+
/**
|
|
221
|
+
* returns the reconnect strategy to be used by the client
|
|
222
|
+
*
|
|
223
|
+
* @generated from protobuf field: stream.video.sfu.models.WebsocketReconnectStrategy reconnect_strategy = 5;
|
|
224
|
+
*/
|
|
225
|
+
reconnectStrategy: WebsocketReconnectStrategy;
|
|
203
226
|
}
|
|
204
227
|
/**
|
|
205
228
|
* @generated from protobuf message stream.video.sfu.event.ICETrickle
|
|
@@ -424,6 +447,21 @@ export interface ParticipantLeft {
|
|
|
424
447
|
*/
|
|
425
448
|
participant?: Participant;
|
|
426
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* ParticipantUpdated is fired when user data is updated
|
|
452
|
+
*
|
|
453
|
+
* @generated from protobuf message stream.video.sfu.event.ParticipantUpdated
|
|
454
|
+
*/
|
|
455
|
+
export interface ParticipantUpdated {
|
|
456
|
+
/**
|
|
457
|
+
* @generated from protobuf field: string call_cid = 1;
|
|
458
|
+
*/
|
|
459
|
+
callCid: string;
|
|
460
|
+
/**
|
|
461
|
+
* @generated from protobuf field: stream.video.sfu.models.Participant participant = 2;
|
|
462
|
+
*/
|
|
463
|
+
participant?: Participant;
|
|
464
|
+
}
|
|
427
465
|
/**
|
|
428
466
|
* SubscriberOffer is sent when the SFU adds tracks to a subscription
|
|
429
467
|
*
|
|
@@ -697,6 +735,18 @@ export interface GoAway {
|
|
|
697
735
|
*/
|
|
698
736
|
reason: GoAwayReason;
|
|
699
737
|
}
|
|
738
|
+
/**
|
|
739
|
+
* CallEnded is sent by the SFU to the client to signal that the call has ended.
|
|
740
|
+
* The reason may specify why the call has ended.
|
|
741
|
+
*
|
|
742
|
+
* @generated from protobuf message stream.video.sfu.event.CallEnded
|
|
743
|
+
*/
|
|
744
|
+
export interface CallEnded {
|
|
745
|
+
/**
|
|
746
|
+
* @generated from protobuf field: stream.video.sfu.models.CallEndedReason reason = 1;
|
|
747
|
+
*/
|
|
748
|
+
reason: CallEndedReason;
|
|
749
|
+
}
|
|
700
750
|
declare class SfuEvent$Type extends MessageType<SfuEvent> {
|
|
701
751
|
constructor();
|
|
702
752
|
create(value?: PartialMessage<SfuEvent>): SfuEvent;
|
|
@@ -847,6 +897,16 @@ declare class ParticipantLeft$Type extends MessageType<ParticipantLeft> {
|
|
|
847
897
|
* @generated MessageType for protobuf message stream.video.sfu.event.ParticipantLeft
|
|
848
898
|
*/
|
|
849
899
|
export declare const ParticipantLeft: ParticipantLeft$Type;
|
|
900
|
+
declare class ParticipantUpdated$Type extends MessageType<ParticipantUpdated> {
|
|
901
|
+
constructor();
|
|
902
|
+
create(value?: PartialMessage<ParticipantUpdated>): ParticipantUpdated;
|
|
903
|
+
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ParticipantUpdated): ParticipantUpdated;
|
|
904
|
+
internalBinaryWrite(message: ParticipantUpdated, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* @generated MessageType for protobuf message stream.video.sfu.event.ParticipantUpdated
|
|
908
|
+
*/
|
|
909
|
+
export declare const ParticipantUpdated: ParticipantUpdated$Type;
|
|
850
910
|
declare class SubscriberOffer$Type extends MessageType<SubscriberOffer> {
|
|
851
911
|
constructor();
|
|
852
912
|
create(value?: PartialMessage<SubscriberOffer>): SubscriberOffer;
|
|
@@ -997,4 +1057,14 @@ declare class GoAway$Type extends MessageType<GoAway> {
|
|
|
997
1057
|
* @generated MessageType for protobuf message stream.video.sfu.event.GoAway
|
|
998
1058
|
*/
|
|
999
1059
|
export declare const GoAway: GoAway$Type;
|
|
1060
|
+
declare class CallEnded$Type extends MessageType<CallEnded> {
|
|
1061
|
+
constructor();
|
|
1062
|
+
create(value?: PartialMessage<CallEnded>): CallEnded;
|
|
1063
|
+
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CallEnded): CallEnded;
|
|
1064
|
+
internalBinaryWrite(message: CallEnded, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* @generated MessageType for protobuf message stream.video.sfu.event.CallEnded
|
|
1068
|
+
*/
|
|
1069
|
+
export declare const CallEnded: CallEnded$Type;
|
|
1000
1070
|
export {};
|
|
@@ -676,6 +676,9 @@ export declare enum TrackUnpublishReason {
|
|
|
676
676
|
MODERATION = 3
|
|
677
677
|
}
|
|
678
678
|
/**
|
|
679
|
+
* GoAwayReason represents the reason for the SFU to
|
|
680
|
+
* disconnect the client.
|
|
681
|
+
*
|
|
679
682
|
* @generated from protobuf enum stream.video.sfu.models.GoAwayReason
|
|
680
683
|
*/
|
|
681
684
|
export declare enum GoAwayReason {
|
|
@@ -692,6 +695,73 @@ export declare enum GoAwayReason {
|
|
|
692
695
|
*/
|
|
693
696
|
REBALANCE = 2
|
|
694
697
|
}
|
|
698
|
+
/**
|
|
699
|
+
* CallEndedReason represents the reason for the call to end.
|
|
700
|
+
*
|
|
701
|
+
* @generated from protobuf enum stream.video.sfu.models.CallEndedReason
|
|
702
|
+
*/
|
|
703
|
+
export declare enum CallEndedReason {
|
|
704
|
+
/**
|
|
705
|
+
* @generated from protobuf enum value: CALL_ENDED_REASON_UNSPECIFIED = 0;
|
|
706
|
+
*/
|
|
707
|
+
UNSPECIFIED = 0,
|
|
708
|
+
/**
|
|
709
|
+
* @generated from protobuf enum value: CALL_ENDED_REASON_ENDED = 1;
|
|
710
|
+
*/
|
|
711
|
+
ENDED = 1,
|
|
712
|
+
/**
|
|
713
|
+
* @generated from protobuf enum value: CALL_ENDED_REASON_LIVE_ENDED = 2;
|
|
714
|
+
*/
|
|
715
|
+
LIVE_ENDED = 2,
|
|
716
|
+
/**
|
|
717
|
+
* @generated from protobuf enum value: CALL_ENDED_REASON_KICKED = 3;
|
|
718
|
+
*/
|
|
719
|
+
KICKED = 3
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* WebsocketReconnectStrategy defines the ws strategies available for handling reconnections.
|
|
723
|
+
*
|
|
724
|
+
* @generated from protobuf enum stream.video.sfu.models.WebsocketReconnectStrategy
|
|
725
|
+
*/
|
|
726
|
+
export declare enum WebsocketReconnectStrategy {
|
|
727
|
+
/**
|
|
728
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_UNSPECIFIED = 0;
|
|
729
|
+
*/
|
|
730
|
+
UNSPECIFIED = 0,
|
|
731
|
+
/**
|
|
732
|
+
* Sent after reaching the maximum reconnection attempts, leading to permanent disconnect.
|
|
733
|
+
*
|
|
734
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_DISCONNECT = 1;
|
|
735
|
+
*/
|
|
736
|
+
DISCONNECT = 1,
|
|
737
|
+
/**
|
|
738
|
+
* SDK should maintaining existing publisher/subscriber pc instances
|
|
739
|
+
* and establish a new WebSocket connection.
|
|
740
|
+
*
|
|
741
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_FAST = 2;
|
|
742
|
+
*/
|
|
743
|
+
FAST = 2,
|
|
744
|
+
/**
|
|
745
|
+
* SDK should drop existing pc instances and creates a fresh WebSocket connection,
|
|
746
|
+
* ensuring a clean state for the reconnection.
|
|
747
|
+
*
|
|
748
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_CLEAN = 3;
|
|
749
|
+
*/
|
|
750
|
+
CLEAN = 3,
|
|
751
|
+
/**
|
|
752
|
+
* SDK should obtain new credentials from the coordinator, drops existing pc instances, and initializes
|
|
753
|
+
* a completely new WebSocket connection, ensuring a comprehensive reset.
|
|
754
|
+
*
|
|
755
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_FULL = 4;
|
|
756
|
+
*/
|
|
757
|
+
FULL = 4,
|
|
758
|
+
/**
|
|
759
|
+
* SDK should migrate to a new SFU instance
|
|
760
|
+
*
|
|
761
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_MIGRATE = 5;
|
|
762
|
+
*/
|
|
763
|
+
MIGRATE = 5
|
|
764
|
+
}
|
|
695
765
|
declare class CallState$Type extends MessageType<CallState> {
|
|
696
766
|
constructor();
|
|
697
767
|
create(value?: PartialMessage<CallState>): CallState;
|
package/package.json
CHANGED
|
@@ -2,26 +2,31 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { CallState } from '../../store';
|
|
3
3
|
import { VisibilityState } from '../../types';
|
|
4
4
|
import { TrackType } from '../../gen/video/sfu/models/models';
|
|
5
|
+
import { noopComparator } from '../../sorting';
|
|
5
6
|
import {
|
|
6
7
|
watchParticipantJoined,
|
|
7
8
|
watchParticipantLeft,
|
|
9
|
+
watchParticipantUpdated,
|
|
8
10
|
watchTrackPublished,
|
|
9
11
|
watchTrackUnpublished,
|
|
10
12
|
} from '../participant';
|
|
11
13
|
|
|
12
14
|
describe('Participant events', () => {
|
|
13
|
-
describe('participantJoined / participantLeft', () => {
|
|
15
|
+
describe('participantJoined / participantLeft / participantUpdated', () => {
|
|
14
16
|
it('adds and removes the participant to the list of participants', () => {
|
|
15
17
|
const state = new CallState();
|
|
18
|
+
state.setSortParticipantsBy(noopComparator());
|
|
16
19
|
|
|
17
20
|
const onParticipantJoined = watchParticipantJoined(state);
|
|
18
21
|
const onParticipantLeft = watchParticipantLeft(state);
|
|
22
|
+
const onParticipantUpdated = watchParticipantUpdated(state);
|
|
19
23
|
|
|
20
24
|
onParticipantJoined({
|
|
21
25
|
// @ts-ignore
|
|
22
26
|
participant: {
|
|
23
27
|
userId: 'user-id',
|
|
24
28
|
sessionId: 'session-id',
|
|
29
|
+
roles: ['user'],
|
|
25
30
|
},
|
|
26
31
|
});
|
|
27
32
|
|
|
@@ -29,6 +34,28 @@ describe('Participant events', () => {
|
|
|
29
34
|
{
|
|
30
35
|
userId: 'user-id',
|
|
31
36
|
sessionId: 'session-id',
|
|
37
|
+
roles: ['user'],
|
|
38
|
+
viewportVisibilityState: {
|
|
39
|
+
videoTrack: VisibilityState.UNKNOWN,
|
|
40
|
+
screenShareTrack: VisibilityState.UNKNOWN,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
onParticipantUpdated({
|
|
46
|
+
// @ts-expect-error incomplete data
|
|
47
|
+
participant: {
|
|
48
|
+
userId: 'user-id',
|
|
49
|
+
sessionId: 'session-id',
|
|
50
|
+
roles: ['host'],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(state.participants).toEqual([
|
|
55
|
+
{
|
|
56
|
+
userId: 'user-id',
|
|
57
|
+
sessionId: 'session-id',
|
|
58
|
+
roles: ['host'],
|
|
32
59
|
viewportVisibilityState: {
|
|
33
60
|
videoTrack: VisibilityState.UNKNOWN,
|
|
34
61
|
screenShareTrack: VisibilityState.UNKNOWN,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
watchParticipantCountChanged,
|
|
16
16
|
watchParticipantJoined,
|
|
17
17
|
watchParticipantLeft,
|
|
18
|
+
watchParticipantUpdated,
|
|
18
19
|
watchPinsUpdated,
|
|
19
20
|
watchSfuErrorReports,
|
|
20
21
|
watchTrackPublished,
|
|
@@ -54,6 +55,7 @@ export const registerEventHandlers = (
|
|
|
54
55
|
|
|
55
56
|
call.on('participantJoined', watchParticipantJoined(state)),
|
|
56
57
|
call.on('participantLeft', watchParticipantLeft(state)),
|
|
58
|
+
call.on('participantUpdated', watchParticipantUpdated(state)),
|
|
57
59
|
|
|
58
60
|
call.on('trackPublished', watchTrackPublished(state)),
|
|
59
61
|
call.on('trackUnpublished', watchTrackUnpublished(state)),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ParticipantJoined,
|
|
3
3
|
ParticipantLeft,
|
|
4
|
+
ParticipantUpdated,
|
|
4
5
|
TrackPublished,
|
|
5
6
|
TrackUnpublished,
|
|
6
7
|
} from '../gen/video/sfu/event/events';
|
|
@@ -51,6 +52,17 @@ export const watchParticipantLeft = (state: CallState) => {
|
|
|
51
52
|
};
|
|
52
53
|
};
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* An event responder which handles the `participantUpdated` event.
|
|
57
|
+
*/
|
|
58
|
+
export const watchParticipantUpdated = (state: CallState) => {
|
|
59
|
+
return function onParticipantUpdated(e: ParticipantUpdated) {
|
|
60
|
+
const { participant } = e;
|
|
61
|
+
if (!participant) return;
|
|
62
|
+
state.updateParticipant(participant.sessionId, participant);
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
54
66
|
/**
|
|
55
67
|
* An event responder which handles the `trackPublished` event.
|
|
56
68
|
* The SFU will send this event when a participant publishes a track.
|