@stream-io/video-client 1.59.1 → 1.61.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 +744 -156
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +744 -155
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +744 -156
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +34 -8
- package/dist/src/coordinator/connection/types.d.ts +16 -0
- package/dist/src/events/call.d.ts +0 -11
- package/dist/src/gen/coordinator/index.d.ts +73 -0
- package/dist/src/reporting/ClientEventReporter.d.ts +11 -1
- package/dist/src/ringing/RingStatePoller.d.ts +46 -0
- package/dist/src/ringing/RingTimeout.d.ts +27 -0
- package/dist/src/ringing/index.d.ts +4 -0
- package/dist/src/ringing/reconcileRingState.d.ts +18 -0
- package/dist/src/ringing/resolveOwnRingOutcome.d.ts +32 -0
- package/dist/src/rtc/Publisher.d.ts +18 -0
- package/dist/src/rtc/TransceiverCache.d.ts +10 -0
- package/dist/src/rtc/e2ee/E2EEManager.d.ts +10 -1
- package/dist/src/stats/utils.d.ts +6 -0
- package/dist/src/store/CallState.d.ts +10 -1
- package/dist/src/types.d.ts +30 -1
- package/index.ts +1 -0
- package/package.json +1 -1
- package/src/Call.ts +272 -108
- package/src/StreamSfuClient.ts +6 -2
- package/src/__tests__/Call.autodrop.test.ts +116 -64
- package/src/__tests__/Call.getRingState.test.ts +87 -0
- package/src/__tests__/Call.lifecycle.test.ts +498 -5
- package/src/__tests__/Call.ringSettled.test.ts +71 -0
- package/src/__tests__/Call.ringingLifecycle.test.ts +242 -0
- package/src/__tests__/StreamSfuClient.test.ts +48 -0
- package/src/coordinator/connection/types.ts +19 -0
- package/src/events/__tests__/call.test.ts +2 -217
- package/src/events/call.ts +1 -73
- package/src/events/callEventHandlers.ts +12 -23
- package/src/gen/coordinator/index.ts +67 -0
- package/src/reporting/ClientEventReporter.ts +30 -4
- package/src/reporting/__tests__/ClientEventReporter.test.ts +184 -7
- package/src/ringing/RingStatePoller.ts +177 -0
- package/src/ringing/RingTimeout.ts +90 -0
- package/src/ringing/__tests__/RingStatePoller.test.ts +462 -0
- package/src/ringing/__tests__/RingTimeout.test.ts +199 -0
- package/src/ringing/__tests__/reconcileRingState.test.ts +330 -0
- package/src/ringing/__tests__/resolveOwnRingOutcome.test.ts +103 -0
- package/src/ringing/index.ts +4 -0
- package/src/ringing/reconcileRingState.ts +108 -0
- package/src/ringing/resolveOwnRingOutcome.ts +58 -0
- package/src/rtc/Publisher.ts +66 -12
- package/src/rtc/TransceiverCache.ts +17 -0
- package/src/rtc/__tests__/Publisher.test.ts +209 -0
- package/src/rtc/__tests__/mocks/webrtc.mocks.ts +1 -0
- package/src/rtc/e2ee/E2EEManager.ts +10 -1
- package/src/rtc/e2ee/EncryptionManager.ts +1 -1
- package/src/rtc/e2ee/SPEC.md +1 -1
- package/src/stats/__tests__/utils.test.ts +33 -0
- package/src/stats/utils.ts +15 -0
- package/src/store/CallState.ts +25 -0
- package/src/store/__tests__/CallState.test.ts +59 -0
- package/src/types.ts +37 -1
package/dist/src/Call.d.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { type CallMediaEngine, Publisher, Subscriber, TrackPublishOptions } from
|
|
|
2
2
|
import type { E2EEManager } from './rtc/e2ee/E2EEManager';
|
|
3
3
|
import { CallState } from './store';
|
|
4
4
|
import { ScopedLogger } from './logger';
|
|
5
|
-
import { AcceptCallResponse, BlockUserResponse, CallRingEvent, CallSettingsResponse, CallStateResponseFields, CollectUserFeedbackRequest, CollectUserFeedbackResponse, DeleteCallRequest, DeleteCallResponse, DeleteRecordingResponse, DeleteTranscriptionResponse, EndCallResponse, GetCallReportResponse, GetCallResponse, GetCallSessionParticipantStatsDetailsResponse, GetOrCreateCallRequest, GetOrCreateCallResponse, GoLiveRequest, GoLiveResponse, JoinCallResponse, KickUserRequest, KickUserResponse, ListRecordingsResponse, ListTranscriptionsResponse, MuteUsersResponse, PinRequest, PinResponse, QueryCallMembersRequest, QueryCallMembersResponse, QueryCallParticipantsRequest, QueryCallParticipantsResponse, QueryCallSessionParticipantStatsResponse, QueryCallSessionParticipantStatsTimelineResponse, QueryCallStatsMapResponse, RejectCallResponse, RequestPermissionRequest, RequestPermissionResponse, RingCallRequest, RingCallResponse, SendCallEventResponse, SendVideoReactionRequest, SendVideoReactionResponse, StartClosedCaptionsRequest, StartClosedCaptionsResponse, StartFrameRecordingRequest, StartFrameRecordingResponse, StartHLSBroadcastingResponse, StartRTMPBroadcastsRequest, StartRTMPBroadcastsResponse, StartTranscriptionRequest, StartTranscriptionResponse, StopAllRTMPBroadcastsResponse, StopClosedCaptionsRequest, StopClosedCaptionsResponse, StopFrameRecordingResponse, StopHLSBroadcastingResponse, StopLiveRequest, StopLiveResponse, StopRecordingResponse, StopRTMPBroadcastsResponse, StopTranscriptionResponse, UnblockUserResponse, UnpinRequest, UnpinResponse, UpdateCallMembersRequest, UpdateCallMembersResponse, UpdateCallRequest, UpdateCallResponse, UpdateUserPermissionsRequest, UpdateUserPermissionsRequestGrantPermissionsEnum, UpdateUserPermissionsRequestRevokePermissionsEnum, UpdateUserPermissionsResponse } from './gen/coordinator';
|
|
5
|
+
import { AcceptCallResponse, BlockUserResponse, CallRingEvent, CallSettingsResponse, CallStateResponseFields, CollectUserFeedbackRequest, CollectUserFeedbackResponse, DeleteCallRequest, DeleteCallResponse, DeleteRecordingResponse, DeleteTranscriptionResponse, EndCallResponse, GetCallReportResponse, GetCallResponse, GetCallRingStateResponse, GetCallSessionParticipantStatsDetailsResponse, GetOrCreateCallRequest, GetOrCreateCallResponse, GoLiveRequest, GoLiveResponse, JoinCallResponse, KickUserRequest, KickUserResponse, ListRecordingsResponse, ListTranscriptionsResponse, MuteUsersResponse, PinRequest, PinResponse, QueryCallMembersRequest, QueryCallMembersResponse, QueryCallParticipantsRequest, QueryCallParticipantsResponse, QueryCallSessionParticipantStatsResponse, QueryCallSessionParticipantStatsTimelineResponse, QueryCallStatsMapResponse, RejectCallResponse, RequestPermissionRequest, RequestPermissionResponse, RingCallRequest, RingCallResponse, SendCallEventResponse, SendVideoReactionRequest, SendVideoReactionResponse, StartClosedCaptionsRequest, StartClosedCaptionsResponse, StartFrameRecordingRequest, StartFrameRecordingResponse, StartHLSBroadcastingResponse, StartRTMPBroadcastsRequest, StartRTMPBroadcastsResponse, StartTranscriptionRequest, StartTranscriptionResponse, StopAllRTMPBroadcastsResponse, StopClosedCaptionsRequest, StopClosedCaptionsResponse, StopFrameRecordingResponse, StopHLSBroadcastingResponse, StopLiveRequest, StopLiveResponse, StopRecordingResponse, StopRTMPBroadcastsResponse, StopTranscriptionResponse, UnblockUserResponse, UnpinRequest, UnpinResponse, UpdateCallMembersRequest, UpdateCallMembersResponse, UpdateCallRequest, UpdateCallResponse, UpdateUserPermissionsRequest, UpdateUserPermissionsRequestGrantPermissionsEnum, UpdateUserPermissionsRequestRevokePermissionsEnum, UpdateUserPermissionsResponse } from './gen/coordinator';
|
|
6
6
|
import { AudioTrackType, CallConstructor, CallLeaveOptions, CallRecordingType, ClientPublishOptions, ClosedCaptionsSettings, JoinCallData, StartCallRecordingFnType, TrackMuteType, VideoTrackType } from './types';
|
|
7
7
|
import { ClientCapability, TrackType, VideoDimension } from './gen/video/sfu/models/models';
|
|
8
8
|
import { Tracer } from './stats';
|
|
9
|
-
import type { ClientEventReporter } from './reporting';
|
|
9
|
+
import type { ClientEventReporter, JoinSource } from './reporting';
|
|
10
10
|
import { AudioBindingsWatchdog } from './helpers/AudioBindingsWatchdog';
|
|
11
11
|
import { BlockedAudioTracker } from './helpers/BlockedAudioTracker';
|
|
12
12
|
import { TrackSubscriptionManager } from './helpers/TrackSubscriptionManager';
|
|
@@ -107,7 +107,8 @@ export declare class Call {
|
|
|
107
107
|
private statsReporter?;
|
|
108
108
|
private sfuStatsReporter?;
|
|
109
109
|
private lastStatsOptions?;
|
|
110
|
-
private
|
|
110
|
+
private ringTimeout;
|
|
111
|
+
private ringStatePoller;
|
|
111
112
|
private readonly clientStore;
|
|
112
113
|
readonly streamClient: StreamClient;
|
|
113
114
|
readonly clientEventReporter: ClientEventReporter;
|
|
@@ -265,6 +266,15 @@ export declare class Call {
|
|
|
265
266
|
* All users should be members of the call.
|
|
266
267
|
*/
|
|
267
268
|
ring: (data?: RingCallRequest) => Promise<RingCallResponse>;
|
|
269
|
+
/**
|
|
270
|
+
* Returns who accepted, rejected or missed the ring for a call session.
|
|
271
|
+
* Safe to poll: it performs no writes and emits no events.
|
|
272
|
+
*
|
|
273
|
+
* @param callSessionId the call session to read. Defaults to the current one.
|
|
274
|
+
* Pass it explicitly to read a session that has already ended, as ending a
|
|
275
|
+
* call clears its current session.
|
|
276
|
+
*/
|
|
277
|
+
getRingState: (callSessionId?: string) => Promise<GetCallRingStateResponse>;
|
|
268
278
|
/**
|
|
269
279
|
* A shortcut for {@link Call.get} with `notify` parameter set to `true`.
|
|
270
280
|
* Will send a `call.notification` event to the call members.
|
|
@@ -291,6 +301,10 @@ export declare class Call {
|
|
|
291
301
|
/**
|
|
292
302
|
* Will start to watch for call related WebSocket events and initiate a call session with the server.
|
|
293
303
|
*
|
|
304
|
+
* One instance is one call flow: discard it after leaving, cancelling, or a
|
|
305
|
+
* failed join, and create a fresh one for a later flow. Reconnection inside a
|
|
306
|
+
* live call is handled here and needs no new instance.
|
|
307
|
+
*
|
|
294
308
|
* @returns a promise which resolves once the call join-flow has finished.
|
|
295
309
|
*/
|
|
296
310
|
join: (args_0?: (JoinCallData & {
|
|
@@ -298,6 +312,7 @@ export declare class Call {
|
|
|
298
312
|
joinResponseTimeout?: number;
|
|
299
313
|
rpcRequestTimeout?: number;
|
|
300
314
|
allowOwnTracksLoopback?: boolean;
|
|
315
|
+
joinSource?: JoinSource;
|
|
301
316
|
}) | undefined) => Promise<void>;
|
|
302
317
|
/**
|
|
303
318
|
* Will make a single attempt to watch for call related WebSocket events
|
|
@@ -344,8 +359,9 @@ export declare class Call {
|
|
|
344
359
|
*
|
|
345
360
|
* @internal
|
|
346
361
|
* @param data the join call data.
|
|
362
|
+
* @returns The coordinator response, or undefined if leave superseded the request before it was sent.
|
|
347
363
|
*/
|
|
348
|
-
doJoinRequest: (data?: JoinCallData) => Promise<JoinCallResponse>;
|
|
364
|
+
doJoinRequest: (data?: JoinCallData) => Promise<JoinCallResponse | undefined>;
|
|
349
365
|
/**
|
|
350
366
|
* Whether the per-call media engine currently exists. True from join until leave.
|
|
351
367
|
*
|
|
@@ -473,10 +489,11 @@ export declare class Call {
|
|
|
473
489
|
* Must be called before {@link join} so the RTCPeerConnection can be
|
|
474
490
|
* configured for E2EE.
|
|
475
491
|
*
|
|
476
|
-
* The
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
492
|
+
* The application owns the manager's lifetime - the SDK never disposes it, and
|
|
493
|
+
* closing the peer connections does not release it. Discard the manager
|
|
494
|
+
* together with this call instance once its flow has ended, and create a fresh
|
|
495
|
+
* pair for a later flow: a disposed manager throws from `encrypt`/`decrypt`
|
|
496
|
+
* rather than silently publishing nothing.
|
|
480
497
|
*
|
|
481
498
|
* @param e2ee - Any `E2EEManager`. Use `EncryptionManager.create()` for the
|
|
482
499
|
* built-in AES-GCM scheme, or pass your own implementation.
|
|
@@ -769,6 +786,15 @@ export declare class Call {
|
|
|
769
786
|
* Cancels a scheduled auto-drop timeout.
|
|
770
787
|
*/
|
|
771
788
|
private cancelAutoDrop;
|
|
789
|
+
/**
|
|
790
|
+
* Starts polling for the ring outcome. Applicable only to ringing calls the
|
|
791
|
+
* current user created.
|
|
792
|
+
*/
|
|
793
|
+
private scheduleRingStatePolling;
|
|
794
|
+
/**
|
|
795
|
+
* Cancels the ring state polling.
|
|
796
|
+
*/
|
|
797
|
+
private cancelRingStatePolling;
|
|
772
798
|
/**
|
|
773
799
|
* Retrieves the list of recordings for the current call or call session.
|
|
774
800
|
*
|
|
@@ -136,6 +136,16 @@ export type AllClientCallEvents = {
|
|
|
136
136
|
export type AllCallEvents = AllClientCallEvents & AllSfuEvents;
|
|
137
137
|
export type CallEventListener<E extends keyof AllCallEvents> = (event: AllCallEvents[E]) => void;
|
|
138
138
|
export type Logger = (logLevel: LogLevel, message: string, ...args: unknown[]) => void;
|
|
139
|
+
export type RingStatePollingOptions = {
|
|
140
|
+
/**
|
|
141
|
+
* Quiet time after the ring starts, before the first poll. Defaults to 15_000.
|
|
142
|
+
*/
|
|
143
|
+
startAfterMs?: number;
|
|
144
|
+
/**
|
|
145
|
+
* The interval between polls. Defaults to 5_000.
|
|
146
|
+
*/
|
|
147
|
+
intervalMs?: number;
|
|
148
|
+
};
|
|
139
149
|
export type StreamClientOptions = Partial<AxiosRequestConfig> & {
|
|
140
150
|
/**
|
|
141
151
|
* Used to disable warnings that are triggered by using connectUser or connectAnonymousUser server-side.
|
|
@@ -227,6 +237,12 @@ export type StreamClientOptions = Partial<AxiosRequestConfig> & {
|
|
|
227
237
|
* When set to true, the incoming calls are rejected when the user is busy in an another call.
|
|
228
238
|
*/
|
|
229
239
|
rejectCallWhenBusy?: boolean;
|
|
240
|
+
/**
|
|
241
|
+
* Caller-side polling for the ring outcome, used when the `call.accepted`,
|
|
242
|
+
* `call.rejected` or `call.missed` event never arrives. Enabled by default;
|
|
243
|
+
* set to `false` to disable, or pass an object to tune the timings.
|
|
244
|
+
*/
|
|
245
|
+
ringStatePolling?: false | RingStatePollingOptions;
|
|
230
246
|
/**
|
|
231
247
|
* Device persistence preference options (web only).
|
|
232
248
|
*/
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import { Call } from '../Call';
|
|
2
|
-
import { CallAcceptedEvent, CallRejectedEvent } from '../gen/coordinator';
|
|
3
|
-
/**
|
|
4
|
-
* Event handler that watched the delivery of `call.accepted`.
|
|
5
|
-
* Once the event is received, the call is joined.
|
|
6
|
-
*/
|
|
7
|
-
export declare const watchCallAccepted: (call: Call) => (event: CallAcceptedEvent) => Promise<void>;
|
|
8
|
-
/**
|
|
9
|
-
* Event handler that watches delivery of `call.rejected` Websocket event.
|
|
10
|
-
* Once the event is received, the call is left.
|
|
11
|
-
*/
|
|
12
|
-
export declare const watchCallRejected: (call: Call) => (event: CallRejectedEvent) => Promise<void>;
|
|
13
2
|
/**
|
|
14
3
|
* Event handler that watches the delivery of `call.ended` Websocket event.
|
|
15
4
|
*/
|
|
@@ -5133,6 +5133,79 @@ export interface GetCallResponse {
|
|
|
5133
5133
|
*/
|
|
5134
5134
|
own_capabilities: Array<OwnCapability>;
|
|
5135
5135
|
}
|
|
5136
|
+
/**
|
|
5137
|
+
* The ring state of a call session: who accepted, rejected, or missed the ring.
|
|
5138
|
+
* @export
|
|
5139
|
+
* @interface GetCallRingStateResponse
|
|
5140
|
+
*/
|
|
5141
|
+
export interface GetCallRingStateResponse {
|
|
5142
|
+
/**
|
|
5143
|
+
* Users that accepted the call, mapped to when they accepted
|
|
5144
|
+
* @type {{ [key: string]: string; }}
|
|
5145
|
+
* @memberof GetCallRingStateResponse
|
|
5146
|
+
*/
|
|
5147
|
+
accepted_by: {
|
|
5148
|
+
[key: string]: string;
|
|
5149
|
+
};
|
|
5150
|
+
/**
|
|
5151
|
+
* The CID of the call
|
|
5152
|
+
* @type {string}
|
|
5153
|
+
* @memberof GetCallRingStateResponse
|
|
5154
|
+
*/
|
|
5155
|
+
call_cid: string;
|
|
5156
|
+
/**
|
|
5157
|
+
* When the call ended
|
|
5158
|
+
* @type {string}
|
|
5159
|
+
* @memberof GetCallRingStateResponse
|
|
5160
|
+
*/
|
|
5161
|
+
call_ended_at?: string;
|
|
5162
|
+
/**
|
|
5163
|
+
* The user that created the call, i.e. the caller
|
|
5164
|
+
* @type {string}
|
|
5165
|
+
* @memberof GetCallRingStateResponse
|
|
5166
|
+
*/
|
|
5167
|
+
created_by_user_id: string;
|
|
5168
|
+
/**
|
|
5169
|
+
* Duration of the request in milliseconds
|
|
5170
|
+
* @type {string}
|
|
5171
|
+
* @memberof GetCallRingStateResponse
|
|
5172
|
+
*/
|
|
5173
|
+
duration: string;
|
|
5174
|
+
/**
|
|
5175
|
+
* Users that missed the call, mapped to when they were marked as missed
|
|
5176
|
+
* @type {{ [key: string]: string; }}
|
|
5177
|
+
* @memberof GetCallRingStateResponse
|
|
5178
|
+
*/
|
|
5179
|
+
missed_by: {
|
|
5180
|
+
[key: string]: string;
|
|
5181
|
+
};
|
|
5182
|
+
/**
|
|
5183
|
+
* Users that rejected the call, mapped to when they rejected
|
|
5184
|
+
* @type {{ [key: string]: string; }}
|
|
5185
|
+
* @memberof GetCallRingStateResponse
|
|
5186
|
+
*/
|
|
5187
|
+
rejected_by: {
|
|
5188
|
+
[key: string]: string;
|
|
5189
|
+
};
|
|
5190
|
+
/**
|
|
5191
|
+
* When the call session ended
|
|
5192
|
+
* @type {string}
|
|
5193
|
+
* @memberof GetCallRingStateResponse
|
|
5194
|
+
*/
|
|
5195
|
+
session_ended_at?: string;
|
|
5196
|
+
/**
|
|
5197
|
+
* The call session this state belongs to, empty when the call has never rung
|
|
5198
|
+
* @type {string}
|
|
5199
|
+
* @memberof GetCallRingStateResponse
|
|
5200
|
+
*/
|
|
5201
|
+
session_id: string;
|
|
5202
|
+
/**
|
|
5203
|
+
* When the call session started
|
|
5204
|
+
* @type {string}
|
|
5205
|
+
* @memberof GetCallRingStateResponse
|
|
5206
|
+
*/
|
|
5207
|
+
session_started_at?: string;
|
|
5208
|
+
}
|
|
5136
5209
|
/**
|
|
5137
5210
|
* Basic response information
|
|
5138
5211
|
* @export
|
|
@@ -6,6 +6,12 @@ export type ClientEventStage = 'JoinInitiated' | 'CoordinatorWS' | 'MediaDeviceP
|
|
|
6
6
|
export type MediaPermissionState = 'INITIATED' | 'FAILED' | 'GRANTED' | 'NOT_INITIATED';
|
|
7
7
|
export type ReportedIceState = 'CONNECTED' | 'FAILED' | 'NOT_CONNECTED';
|
|
8
8
|
export type JoinReason = 'first-attempt' | 'network-available' | 'migration' | 'full-rejoin';
|
|
9
|
+
/**
|
|
10
|
+
* What triggered an automatic join, reported as `source` on the call's
|
|
11
|
+
* CoordinatorJoin events. `ring-ws` is a ring WebSocket event, `ring-poll-api`
|
|
12
|
+
* is the ring state poller.
|
|
13
|
+
*/
|
|
14
|
+
export type JoinSource = 'ring-ws' | 'ring-poll-api';
|
|
9
15
|
export type ClientEventStandardCode = 'CLIENT_ABORTED' | 'BACKEND_LEAVE' | 'REQUEST_TIMEOUT' | 'NETWORK_ERROR' | 'SFU_ERROR' | 'SFU_GO_AWAY' | 'ICE_CONNECTIVITY_FAILED' | 'DTLS_CONNECTIVITY_FAILED';
|
|
10
16
|
export type CallReportContext = {
|
|
11
17
|
callType: string;
|
|
@@ -27,6 +33,7 @@ export declare class ClientEventReporter {
|
|
|
27
33
|
private callContexts;
|
|
28
34
|
private joinAttemptIds;
|
|
29
35
|
private joinReasons;
|
|
36
|
+
private joinSources;
|
|
30
37
|
private coordinatorPairs;
|
|
31
38
|
private wsPairs;
|
|
32
39
|
private peerConnectionPairs;
|
|
@@ -50,7 +57,10 @@ export declare class ClientEventReporter {
|
|
|
50
57
|
registerCall: (cid: string, ctx: CallReportContext) => void;
|
|
51
58
|
unregisterCall: (cid: string) => void;
|
|
52
59
|
startCorrelation: (cid: string, joinReason: JoinReason) => void;
|
|
53
|
-
withJoinLifecycle: <T>(cid: string,
|
|
60
|
+
withJoinLifecycle: <T>(cid: string, options: {
|
|
61
|
+
joinReason: JoinReason;
|
|
62
|
+
joinSource?: JoinSource;
|
|
63
|
+
}, op: () => Promise<T>) => Promise<T>;
|
|
54
64
|
track: <T>(cid: string, stage: "CoordinatorJoin" | "WSJoin", op: () => Promise<T>) => Promise<T>;
|
|
55
65
|
reportFirstFrame: (cid: string, trackType: TrackType, trackId: string) => void;
|
|
56
66
|
captureWsError: (cid: string, opts: {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Call } from '../Call';
|
|
2
|
+
import { type RingStatePollingOptions } from '../coordinator/connection/types';
|
|
3
|
+
/**
|
|
4
|
+
* Polls the coordinator for the outcome of a ring the current user started.
|
|
5
|
+
*
|
|
6
|
+
* `call.accepted`, `call.rejected` and `call.missed` are delivered best-effort,
|
|
7
|
+
* with no store-and-forward, so a caller that drops one is left on a ringing
|
|
8
|
+
* screen while the callee is already in the call. After a quiet period this
|
|
9
|
+
* reads the ring state until a terminal outcome or the end of the ring window.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RingStatePoller {
|
|
12
|
+
private readonly logger;
|
|
13
|
+
private readonly call;
|
|
14
|
+
private readonly startAfterMs;
|
|
15
|
+
private readonly intervalMs;
|
|
16
|
+
private sessionId;
|
|
17
|
+
private deadlineAt;
|
|
18
|
+
private idleTimeoutId;
|
|
19
|
+
private intervalId;
|
|
20
|
+
private stopped;
|
|
21
|
+
private wasPolling;
|
|
22
|
+
private inFlight;
|
|
23
|
+
private unsubscribe;
|
|
24
|
+
constructor(call: Call, options?: RingStatePollingOptions);
|
|
25
|
+
/**
|
|
26
|
+
* Starts polling. Does nothing when the call has no session yet.
|
|
27
|
+
*/
|
|
28
|
+
start: () => void;
|
|
29
|
+
/**
|
|
30
|
+
* Pauses polling, keeping the captured session, the deadline and the event
|
|
31
|
+
* subscriptions. Resuming does not extend the ring window.
|
|
32
|
+
*/
|
|
33
|
+
pause: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Resumes a paused poller. Goes straight back to polling if it was already
|
|
36
|
+
* past the quiet period, so a pause does not buy the ring another one.
|
|
37
|
+
*/
|
|
38
|
+
resume: () => void;
|
|
39
|
+
/**
|
|
40
|
+
* Stops polling. The poller cannot be restarted.
|
|
41
|
+
*/
|
|
42
|
+
stop: () => void;
|
|
43
|
+
private armIdleWindow;
|
|
44
|
+
private runTick;
|
|
45
|
+
private tick;
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Call } from '../Call';
|
|
2
|
+
/**
|
|
3
|
+
* Drops a call that has been ringing for too long: the caller cancels after
|
|
4
|
+
* `auto_cancel_timeout_ms`, a callee after `incoming_call_timeout_ms`.
|
|
5
|
+
*
|
|
6
|
+
* Either timeout being `0` means the call rings until something else settles it.
|
|
7
|
+
*/
|
|
8
|
+
export declare class RingTimeout {
|
|
9
|
+
private readonly call;
|
|
10
|
+
private timeoutId;
|
|
11
|
+
private deadlineAt;
|
|
12
|
+
private stopped;
|
|
13
|
+
constructor(call: Call);
|
|
14
|
+
/**
|
|
15
|
+
* Schedules an auto-drop timeout based on the call settings.
|
|
16
|
+
* Applicable only for ringing calls.
|
|
17
|
+
*/
|
|
18
|
+
start: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Pauses the timeout while preserving its original deadline.
|
|
21
|
+
*/
|
|
22
|
+
pause: () => void;
|
|
23
|
+
/**
|
|
24
|
+
* Cancels a scheduled auto-drop timeout. It cannot be armed again.
|
|
25
|
+
*/
|
|
26
|
+
stop: () => void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Call } from '../Call';
|
|
2
|
+
import type { JoinSource } from '../reporting';
|
|
3
|
+
/**
|
|
4
|
+
* Decides what a ringing call should do next, based on the current call state.
|
|
5
|
+
*
|
|
6
|
+
* The `call.accepted`, `call.rejected` and `call.missed` handlers and the ring
|
|
7
|
+
* state poller both run this. They differ only in how the state got there: the
|
|
8
|
+
* handlers rely on `CallState.updateFromEvent`, which runs before them, and the
|
|
9
|
+
* poller applies the polled ring state itself.
|
|
10
|
+
*
|
|
11
|
+
* @param call the call to reconcile.
|
|
12
|
+
* @param joinSource which of the two triggered this run, reported on the
|
|
13
|
+
* caller's join: `ring-ws` for the event handlers, `ring-poll-api` for the
|
|
14
|
+
* poller.
|
|
15
|
+
* @returns whether the ring reached a terminal state. A failed join is not
|
|
16
|
+
* terminal: the caller should keep trying while the ring is open.
|
|
17
|
+
*/
|
|
18
|
+
export declare const reconcileRingState: (call: Call, joinSource: JoinSource) => Promise<boolean>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CallingState } from '../store';
|
|
2
|
+
import type { CallSessionResponse } from '../gen/coordinator';
|
|
3
|
+
export type OwnRingOutcome = {
|
|
4
|
+
/**
|
|
5
|
+
* Whether the current user accepted or rejected the ring, on this device or
|
|
6
|
+
* on another one. Either way the ring no longer needs to time out.
|
|
7
|
+
*/
|
|
8
|
+
settledByMe: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Set when this device should stop ringing and leave, carrying the reason to
|
|
11
|
+
* report to the native call UI.
|
|
12
|
+
*/
|
|
13
|
+
leaveReason?: 'answeredElsewhere' | 'rejected';
|
|
14
|
+
};
|
|
15
|
+
export type OwnRingOutcomeInput = {
|
|
16
|
+
/** The call session to read the accept and reject maps from. */
|
|
17
|
+
session: CallSessionResponse | undefined;
|
|
18
|
+
/** The connected user, or `undefined` when there is none. */
|
|
19
|
+
currentUserId: string | undefined;
|
|
20
|
+
/** The current calling state. */
|
|
21
|
+
callingState: CallingState;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Decides what a ringing call should do about the current user's own accept or
|
|
25
|
+
* reject, which may have happened on another device.
|
|
26
|
+
*
|
|
27
|
+
* Accepting on *this* device also lands in `accepted_by`, so an acceptance only
|
|
28
|
+
* means another device took the call when this one is still ringing.
|
|
29
|
+
*
|
|
30
|
+
* Only meaningful for a ringing call; the caller checks that.
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveOwnRingOutcome: ({ session, currentUserId, callingState, }: OwnRingOutcomeInput) => OwnRingOutcome;
|
|
@@ -37,6 +37,24 @@ export declare class Publisher extends BasePeerConnection {
|
|
|
37
37
|
* Adds a new transceiver carrying the given track to the peer connection.
|
|
38
38
|
*/
|
|
39
39
|
private addTransceiver;
|
|
40
|
+
/**
|
|
41
|
+
* Attaches the encryptor, applies sender parameters, then attaches the track.
|
|
42
|
+
*
|
|
43
|
+
* `encrypt` must run before the first await: Chrome short-circuits a sender
|
|
44
|
+
* whose encoded streams aren't created in the task that created it, and the
|
|
45
|
+
* track goes on last so the sender has no media until both steps succeed.
|
|
46
|
+
*/
|
|
47
|
+
private initEncryptedSender;
|
|
48
|
+
private setDegradationPreference;
|
|
49
|
+
/**
|
|
50
|
+
* Discards a sender whose E2EE initialization failed.
|
|
51
|
+
*
|
|
52
|
+
* A partially initialized sender may carry no transform, so publish() must
|
|
53
|
+
* not reuse it: retiring it from the cache is what keeps a later publish or
|
|
54
|
+
* ICE restart from putting cleartext on the wire. Cleanup cannot throw, so
|
|
55
|
+
* the initialization failure is what reaches the caller.
|
|
56
|
+
*/
|
|
57
|
+
private retireTransceiver;
|
|
40
58
|
/**
|
|
41
59
|
* Updates the transceiver with the given track and track type.
|
|
42
60
|
*/
|
|
@@ -14,6 +14,16 @@ export declare class TransceiverCache {
|
|
|
14
14
|
* Adds a transceiver to the cache.
|
|
15
15
|
*/
|
|
16
16
|
add: (bundle: PublishBundle) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Retires a failed sender from the reusable cache.
|
|
19
|
+
*
|
|
20
|
+
* A transceiver that never reached an m-section also leaves the creation
|
|
21
|
+
* history: once stopped, it is left out of every later offer, so counting
|
|
22
|
+
* it would shift the `mid` index of every transceiver added after it. One
|
|
23
|
+
* that is already associated keeps its slot, since its m-section survives
|
|
24
|
+
* as a rejected one.
|
|
25
|
+
*/
|
|
26
|
+
remove: (transceiver: RTCRtpTransceiver) => void;
|
|
17
27
|
/**
|
|
18
28
|
* Gets the transceiver for the given publish option.
|
|
19
29
|
*/
|
|
@@ -5,7 +5,16 @@
|
|
|
5
5
|
* attaching their own encoded transform in these two methods.
|
|
6
6
|
*/
|
|
7
7
|
export interface E2EEManager {
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Synchronously attach a transform that encrypts the sender's outgoing frames.
|
|
10
|
+
* Must support a sender without a track, and throw if attachment fails.
|
|
11
|
+
*
|
|
12
|
+
* `sender.track` is always null here: the track is attached only after this
|
|
13
|
+
* returns, so implementations must not read it. Use `codec` and `trackType`
|
|
14
|
+
* instead.
|
|
15
|
+
*
|
|
16
|
+
* `trackType` only groups perf stats, keeping a camera and screen share apart.
|
|
17
|
+
*/
|
|
9
18
|
encrypt(sender: RTCRtpSender, codec?: string, trackType?: string): void;
|
|
10
19
|
/** `trackType` only groups perf stats, keeping a peer's audio and video apart. */
|
|
11
20
|
decrypt(receiver: RTCRtpReceiver, userId: string, trackType?: string): void;
|
|
@@ -29,3 +29,9 @@ export declare const getSdkSignature: (clientDetails: ClientDetails) => {
|
|
|
29
29
|
};
|
|
30
30
|
export declare const getSdkName: (sdk: Sdk | undefined) => "stream-react" | "stream-react-native" | "stream-js";
|
|
31
31
|
export declare const getSdkVersion: (sdk: Sdk | undefined) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Returns the identifier the SFU receives in the `X-Stream-Client` header,
|
|
34
|
+
* e.g. `stream-video-react-v1.43.1`. Matches the format the coordinator
|
|
35
|
+
* already gets through the client's user agent.
|
|
36
|
+
*/
|
|
37
|
+
export declare const getStreamClientId: (sdk: Sdk | undefined) => string;
|
|
@@ -3,7 +3,7 @@ import type { Patch } from './rxUtils';
|
|
|
3
3
|
import { CallingState } from './CallingState';
|
|
4
4
|
import { type ClosedCaptionsSettings, type StreamVideoParticipant, type StreamVideoParticipantPatch, type StreamVideoParticipantPatches, type SubscriptionChanges, VideoTrackType } from '../types';
|
|
5
5
|
import { CallStatsReport } from '../stats';
|
|
6
|
-
import { CallClosedCaption, CallIngressResponse, CallResponse, CallSessionResponse, CallSettingsResponse, EgressResponse, MemberResponse, OwnCapability, ThumbnailResponse, UserResponse, VideoEvent } from '../gen/coordinator';
|
|
6
|
+
import { CallClosedCaption, CallIngressResponse, CallResponse, CallSessionResponse, CallSettingsResponse, GetCallRingStateResponse, EgressResponse, MemberResponse, OwnCapability, ThumbnailResponse, UserResponse, VideoEvent } from '../gen/coordinator';
|
|
7
7
|
import { ReconnectDetails } from '../gen/video/sfu/event/events';
|
|
8
8
|
import { CallGrants, CallState as SfuCallState, Pin, TrackType } from '../gen/video/sfu/models/models';
|
|
9
9
|
import { Comparator } from '../sorting';
|
|
@@ -615,6 +615,15 @@ export declare class CallState {
|
|
|
615
615
|
* @param call the call response from the server.
|
|
616
616
|
*/
|
|
617
617
|
updateFromCallResponse: (call: CallResponse) => void;
|
|
618
|
+
/**
|
|
619
|
+
* Merges a polled ring state into the current session. Only the ring fields
|
|
620
|
+
* are touched: the endpoint does not return the session roster.
|
|
621
|
+
*
|
|
622
|
+
* @internal
|
|
623
|
+
*
|
|
624
|
+
* @param ringState the ring state as returned by the coordinator.
|
|
625
|
+
*/
|
|
626
|
+
updateFromRingState: (ringState: GetCallRingStateResponse) => void;
|
|
618
627
|
/**
|
|
619
628
|
* Updates the call state with the data received from the SFU server.
|
|
620
629
|
*
|
package/dist/src/types.d.ts
CHANGED
|
@@ -375,14 +375,43 @@ type StreamRNVideoSDKEndCallReason =
|
|
|
375
375
|
/** Unknown or unspecified disconnect reason. */
|
|
376
376
|
| 'unknown';
|
|
377
377
|
type StreamRNVideoSDKCallingX = {
|
|
378
|
-
|
|
378
|
+
/**
|
|
379
|
+
* @param isCancelled - polled around the bridge's waits: registration is
|
|
380
|
+
* skipped, or undone, when it returns true. Supplied by the join attempt
|
|
381
|
+
* because the call's own state cannot distinguish a fresh join starting
|
|
382
|
+
* from `LEFT` from an abandoned one that reached `LEFT` while waiting.
|
|
383
|
+
*/
|
|
384
|
+
joinCall: (call: Call, activeCalls: Call[], isCancelled?: () => boolean) => Promise<void>;
|
|
379
385
|
endCall: (call: Call, reason?: StreamRNVideoSDKEndCallReason) => Promise<void>;
|
|
380
386
|
registerOutgoingCall: (call: Call) => Promise<void>;
|
|
381
387
|
wireAudioEngineSubscription: () => void;
|
|
382
388
|
unwireAudioEngineSubscription: () => void;
|
|
383
389
|
};
|
|
390
|
+
/**
|
|
391
|
+
* React Native's preparation and cleanup for a ringing call's join.
|
|
392
|
+
*
|
|
393
|
+
* A ringing call is joined by the SDK rather than by app code, so there is no
|
|
394
|
+
* point at which the app holds the call and can still set it up. These are that
|
|
395
|
+
* point, and the matching release.
|
|
396
|
+
*/
|
|
397
|
+
type StreamRNVideoSDKRingingCallLifecycle = {
|
|
398
|
+
/**
|
|
399
|
+
* Runs the app's pre-join setup and resolves once it is done, bounded by a
|
|
400
|
+
* deadline. Rejecting fails the join closed rather than joining with nothing
|
|
401
|
+
* installed.
|
|
402
|
+
*/
|
|
403
|
+
beforeJoin: (call: Call) => Promise<void>;
|
|
404
|
+
/**
|
|
405
|
+
* The join failed terminally. Ends the ringing flow and releases what the
|
|
406
|
+
* setup installed. Never rejects, so the original join error survives.
|
|
407
|
+
*/
|
|
408
|
+
onJoinFailed: (call: Call) => Promise<void>;
|
|
409
|
+
/** The call has ended; release whatever the pre-join hook installed. */
|
|
410
|
+
onLeave: (call: Call) => void;
|
|
411
|
+
};
|
|
384
412
|
export type StreamRNVideoSDKGlobals = {
|
|
385
413
|
callingX: StreamRNVideoSDKCallingX;
|
|
414
|
+
ringingCallLifecycle: StreamRNVideoSDKRingingCallLifecycle;
|
|
386
415
|
callManager: {
|
|
387
416
|
/**
|
|
388
417
|
* Sets up the in call manager.
|
package/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './src/helpers/sound-detector';
|
|
|
26
26
|
export * from './src/helpers/loopback';
|
|
27
27
|
export * from './src/helpers/MediaStreamRecorder';
|
|
28
28
|
export * from './src/helpers/participantUtils';
|
|
29
|
+
export * from './src/helpers/TypedEventEmitter';
|
|
29
30
|
export * from './src/rtc/e2ee/E2EEManager';
|
|
30
31
|
export * from './src/rtc/e2ee/EncryptionManager';
|
|
31
32
|
export * as Browsers from './src/helpers/browsers';
|