@stream-io/video-client 1.48.0 → 1.50.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 +25 -0
- package/dist/index.browser.es.js +1497 -677
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +1497 -677
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1497 -677
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +77 -4
- package/dist/src/StreamSfuClient.d.ts +8 -1
- package/dist/src/coordinator/connection/client.d.ts +1 -1
- package/dist/src/coordinator/connection/connection.d.ts +31 -25
- package/dist/src/coordinator/connection/types.d.ts +14 -0
- package/dist/src/coordinator/connection/utils.d.ts +1 -0
- package/dist/src/devices/DeviceManager.d.ts +3 -0
- package/dist/src/devices/DeviceManagerState.d.ts +13 -1
- package/dist/src/gen/video/sfu/event/events.d.ts +5 -1
- package/dist/src/gen/video/sfu/models/models.d.ts +34 -0
- package/dist/src/helpers/AudioBindingsWatchdog.d.ts +3 -3
- package/dist/src/helpers/BlockedAudioTracker.d.ts +30 -0
- package/dist/src/helpers/DynascaleManager.d.ts +8 -86
- package/dist/src/helpers/MediaPlaybackWatchdog.d.ts +32 -0
- package/dist/src/helpers/SlidingWindowRateLimiter.d.ts +28 -0
- package/dist/src/helpers/TrackSubscriptionManager.d.ts +114 -0
- package/dist/src/helpers/ViewportTracker.d.ts +11 -17
- package/dist/src/helpers/browsers.d.ts +13 -0
- package/dist/src/helpers/concurrency.d.ts +6 -4
- package/dist/src/rtc/BasePeerConnection.d.ts +11 -2
- package/dist/src/rtc/Publisher.d.ts +17 -0
- package/dist/src/rtc/Subscriber.d.ts +1 -0
- package/dist/src/rtc/helpers/degradationPreference.d.ts +2 -0
- package/dist/src/rtc/index.d.ts +1 -0
- package/dist/src/rtc/types.d.ts +33 -1
- package/dist/src/stats/rtc/types.d.ts +1 -1
- package/dist/src/store/rxUtils.d.ts +9 -0
- package/dist/src/types.d.ts +18 -0
- package/package.json +2 -2
- package/src/Call.ts +268 -40
- package/src/StreamSfuClient.ts +75 -12
- package/src/__tests__/Call.lifecycle.test.ts +67 -0
- package/src/__tests__/Call.publishing.test.ts +103 -0
- package/src/__tests__/StreamSfuClient.test.ts +275 -0
- package/src/coordinator/connection/__tests__/connection.test.ts +482 -0
- package/src/coordinator/connection/client.ts +1 -1
- package/src/coordinator/connection/connection.ts +149 -96
- package/src/coordinator/connection/types.ts +15 -0
- package/src/coordinator/connection/utils.ts +15 -0
- package/src/devices/DeviceManager.ts +92 -32
- package/src/devices/DeviceManagerState.ts +20 -1
- package/src/devices/__tests__/DeviceManager.test.ts +283 -0
- package/src/devices/__tests__/ScreenShareManager.test.ts +0 -2
- package/src/devices/__tests__/mocks.ts +2 -0
- package/src/devices/devices.ts +2 -1
- package/src/gen/video/sfu/event/events.ts +15 -0
- package/src/gen/video/sfu/models/models.ts +44 -0
- package/src/helpers/AudioBindingsWatchdog.ts +10 -7
- package/src/helpers/BlockedAudioTracker.ts +74 -0
- package/src/helpers/DynascaleManager.ts +46 -337
- package/src/helpers/MediaPlaybackWatchdog.ts +121 -0
- package/src/helpers/SlidingWindowRateLimiter.ts +49 -0
- package/src/helpers/TrackSubscriptionManager.ts +243 -0
- package/src/helpers/ViewportTracker.ts +74 -19
- package/src/helpers/__tests__/BlockedAudioTracker.test.ts +114 -0
- package/src/helpers/__tests__/DynascaleManager.test.ts +175 -122
- package/src/helpers/__tests__/MediaPlaybackWatchdog.test.ts +180 -0
- package/src/helpers/__tests__/SlidingWindowRateLimiter.test.ts +43 -0
- package/src/helpers/__tests__/TrackSubscriptionManager.test.ts +310 -0
- package/src/helpers/__tests__/ViewportTracker.test.ts +83 -0
- package/src/helpers/__tests__/browsers.test.ts +85 -1
- package/src/helpers/browsers.ts +24 -0
- package/src/helpers/concurrency.ts +9 -10
- package/src/rpc/retryable.ts +0 -1
- package/src/rtc/BasePeerConnection.ts +96 -6
- package/src/rtc/Publisher.ts +49 -2
- package/src/rtc/Subscriber.ts +42 -14
- package/src/rtc/__tests__/Call.reconnect.test.ts +761 -0
- package/src/rtc/__tests__/Publisher.test.ts +332 -10
- package/src/rtc/__tests__/Subscriber.test.ts +202 -1
- package/src/rtc/__tests__/mocks/webrtc.mocks.ts +13 -2
- package/src/rtc/helpers/__tests__/degradationPreference.test.ts +23 -0
- package/src/rtc/helpers/degradationPreference.ts +22 -0
- package/src/rtc/index.ts +1 -0
- package/src/rtc/types.ts +38 -1
- package/src/stats/rtc/types.ts +1 -0
- package/src/store/__tests__/rxUtils.test.ts +276 -0
- package/src/store/rxUtils.ts +19 -0
- package/src/types.ts +19 -0
package/dist/src/Call.d.ts
CHANGED
|
@@ -5,7 +5,11 @@ import type { AcceptCallResponse, BlockUserResponse, CallRingEvent, CallSettings
|
|
|
5
5
|
import { AudioTrackType, CallConstructor, CallLeaveOptions, CallRecordingType, ClientPublishOptions, ClosedCaptionsSettings, JoinCallData, StartCallRecordingFnType, TrackMuteType, VideoTrackType } from './types';
|
|
6
6
|
import { ClientCapability, TrackType, VideoDimension } from './gen/video/sfu/models/models';
|
|
7
7
|
import { Tracer } from './stats';
|
|
8
|
+
import { AudioBindingsWatchdog } from './helpers/AudioBindingsWatchdog';
|
|
9
|
+
import { BlockedAudioTracker } from './helpers/BlockedAudioTracker';
|
|
10
|
+
import { TrackSubscriptionManager } from './helpers/TrackSubscriptionManager';
|
|
8
11
|
import { DynascaleManager } from './helpers/DynascaleManager';
|
|
12
|
+
import { ViewportTracker } from './helpers/ViewportTracker';
|
|
9
13
|
import { PermissionsContext } from './permissions';
|
|
10
14
|
import { StreamClient } from './coordinator/connection/client';
|
|
11
15
|
import { AllCallEvents, CallEventListener, RejectReason } from './coordinator/connection/types';
|
|
@@ -55,7 +59,28 @@ export declare class Call {
|
|
|
55
59
|
/**
|
|
56
60
|
* The DynascaleManager instance.
|
|
57
61
|
*/
|
|
58
|
-
readonly dynascaleManager: DynascaleManager;
|
|
62
|
+
readonly dynascaleManager: DynascaleManager | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Tracks viewport visibility for participant video elements.
|
|
65
|
+
* Available only in DOM environments.
|
|
66
|
+
*/
|
|
67
|
+
readonly viewportTracker: ViewportTracker | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Owns the SFU-side video-subscription state (per-session and global overrides).
|
|
70
|
+
*/
|
|
71
|
+
readonly trackSubscriptionManager: TrackSubscriptionManager;
|
|
72
|
+
/**
|
|
73
|
+
* Warns periodically when a remote participant is publishing audio, but no
|
|
74
|
+
* `<audio>` element has been bound for them.
|
|
75
|
+
*/
|
|
76
|
+
readonly audioBindingsWatchdog: AudioBindingsWatchdog | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Tracks audio elements blocked by the browser's autoplay policy.
|
|
79
|
+
* Subscribe to `blockedAudioTracker.autoplayBlocked$` to react to the
|
|
80
|
+
* blocked state, and call {@link Call.resumeAudio} inside a user gesture
|
|
81
|
+
* to retry playback.
|
|
82
|
+
*/
|
|
83
|
+
readonly blockedAudioTracker: BlockedAudioTracker;
|
|
59
84
|
subscriber?: Subscriber;
|
|
60
85
|
publisher?: Publisher;
|
|
61
86
|
/**
|
|
@@ -92,6 +117,11 @@ export declare class Call {
|
|
|
92
117
|
private disconnectionTimeoutSeconds;
|
|
93
118
|
private lastOfflineTimestamp;
|
|
94
119
|
private networkAvailableTask;
|
|
120
|
+
private readonly rejoinRateLimiter;
|
|
121
|
+
private maxIceFailuresWithoutConnect;
|
|
122
|
+
private iceFailuresWithoutConnect;
|
|
123
|
+
private maxConsecutiveNegotiationFailures;
|
|
124
|
+
private consecutiveNegotiationFailures;
|
|
95
125
|
private trackPublishOrder;
|
|
96
126
|
private joinResponseTimeout?;
|
|
97
127
|
private rpcRequestTimeout?;
|
|
@@ -298,7 +328,9 @@ export declare class Call {
|
|
|
298
328
|
* @internal
|
|
299
329
|
*
|
|
300
330
|
* @param strategy the reconnection strategy to use.
|
|
301
|
-
* @param reason the reason for the reconnection.
|
|
331
|
+
* @param reason the reason for the reconnection. Pass a `ReconnectReason.*`
|
|
332
|
+
* constant when the SDK should react to it (e.g.
|
|
333
|
+
* `ICE_NEVER_CONNECTED` increments the unsupported-network counter).
|
|
302
334
|
*/
|
|
303
335
|
private reconnect;
|
|
304
336
|
/**
|
|
@@ -369,6 +401,16 @@ export declare class Call {
|
|
|
369
401
|
* @param trackTypes the track types to update the call state with.
|
|
370
402
|
*/
|
|
371
403
|
private updateLocalStreamState;
|
|
404
|
+
/**
|
|
405
|
+
* Re-arms the encoder for a currently published track type. Useful for
|
|
406
|
+
* working around WebKit's stalled sender bug after an iOS audio session
|
|
407
|
+
* interruption (Siri, PSTN call).
|
|
408
|
+
*
|
|
409
|
+
* @internal
|
|
410
|
+
*
|
|
411
|
+
* @param trackType the track type to refresh.
|
|
412
|
+
*/
|
|
413
|
+
refreshPublishedTrack: (trackType: TrackType) => Promise<void>;
|
|
372
414
|
/**
|
|
373
415
|
* Updates the preferred publishing options
|
|
374
416
|
*
|
|
@@ -770,13 +812,13 @@ export declare class Call {
|
|
|
770
812
|
* @param sessionId the session id.
|
|
771
813
|
* @param trackType the video mode.
|
|
772
814
|
*/
|
|
773
|
-
trackElementVisibility: <T extends HTMLElement>(element: T, sessionId: string, trackType: VideoTrackType) => () => void;
|
|
815
|
+
trackElementVisibility: <T extends HTMLElement>(element: T, sessionId: string, trackType: VideoTrackType) => (() => void) | undefined;
|
|
774
816
|
/**
|
|
775
817
|
* Sets the viewport element to track bound video elements for visibility.
|
|
776
818
|
*
|
|
777
819
|
* @param element the viewport element.
|
|
778
820
|
*/
|
|
779
|
-
setViewport: <T extends HTMLElement>(element: T) => () => void;
|
|
821
|
+
setViewport: <T extends HTMLElement>(element: T) => (() => void) | undefined;
|
|
780
822
|
/**
|
|
781
823
|
* Binds a DOM <video> element to the given session id.
|
|
782
824
|
* This method will make sure that the video element will play
|
|
@@ -806,6 +848,10 @@ export declare class Call {
|
|
|
806
848
|
bindAudioElement: (audioElement: HTMLAudioElement, sessionId: string, trackType?: AudioTrackType) => (() => void) | undefined;
|
|
807
849
|
/**
|
|
808
850
|
* Plays all audio elements blocked by the browser's autoplay policy.
|
|
851
|
+
* Must be called from within a user gesture (e.g., click handler).
|
|
852
|
+
*
|
|
853
|
+
* Subscribe to `call.blockedAudioTracker.autoplayBlocked$` to know when a
|
|
854
|
+
* gesture is required.
|
|
809
855
|
*/
|
|
810
856
|
resumeAudio: () => Promise<void>;
|
|
811
857
|
/**
|
|
@@ -839,6 +885,33 @@ export declare class Call {
|
|
|
839
885
|
* @param timeoutSeconds Timeout in seconds, or 0 to keep reconnecting indefinetely
|
|
840
886
|
*/
|
|
841
887
|
setDisconnectionTimeout: (timeoutSeconds: number) => void;
|
|
888
|
+
/**
|
|
889
|
+
* Configures the rolling-window limit for REJOIN/MIGRATE attempts. Once
|
|
890
|
+
* `maxAttempts` rejoins have been registered inside `windowSeconds`, the
|
|
891
|
+
* SDK stops retrying and transitions the call to `LEFT` with the
|
|
892
|
+
* `rejoin_attempt_limit_exceeded` leave message.
|
|
893
|
+
*
|
|
894
|
+
* Defaults: 10 attempts per 120 seconds (aligned with the Swift SDK).
|
|
895
|
+
* Both arguments are clamped to a minimum of 1.
|
|
896
|
+
*/
|
|
897
|
+
setRejoinAttemptLimit: (maxAttempts: number, windowSeconds: number) => void;
|
|
898
|
+
/**
|
|
899
|
+
* Configures how many peer-connection failures where ICE never reached
|
|
900
|
+
* `connected`/`completed` are tolerated before the SDK concludes that the
|
|
901
|
+
* current network cannot support WebRTC and transitions the call to
|
|
902
|
+
* `LEFT` with the `webrtc_unsupported_network` leave message.
|
|
903
|
+
*
|
|
904
|
+
* Default: 2. Clamped to a minimum of 1.
|
|
905
|
+
*/
|
|
906
|
+
setMaxIceFailuresWithoutConnect: (n: number) => void;
|
|
907
|
+
/**
|
|
908
|
+
* Configures how many consecutive SDP `NegotiationError`s are tolerated
|
|
909
|
+
* before the SDK stops retrying and transitions the call to `LEFT` with
|
|
910
|
+
* the `repeated_negotiation_failures` leave message.
|
|
911
|
+
*
|
|
912
|
+
* Default: 3. Clamped to a minimum of 1.
|
|
913
|
+
*/
|
|
914
|
+
setMaxConsecutiveNegotiationFailures: (n: number) => void;
|
|
842
915
|
/**
|
|
843
916
|
* Enables the provided client capabilities.
|
|
844
917
|
*/
|
|
@@ -107,7 +107,8 @@ export declare class StreamSfuClient {
|
|
|
107
107
|
private networkAvailableTask;
|
|
108
108
|
/**
|
|
109
109
|
* Promise that resolves when the JoinResponse is received.
|
|
110
|
-
* Rejects after a certain threshold if the response is not received
|
|
110
|
+
* Rejects after a certain threshold if the response is not received,
|
|
111
|
+
* or when the SFU client is disposed before a join completes.
|
|
111
112
|
*/
|
|
112
113
|
private joinResponseTask;
|
|
113
114
|
/**
|
|
@@ -140,6 +141,12 @@ export declare class StreamSfuClient {
|
|
|
140
141
|
* The close code used when the client fails to join the call (on the SFU).
|
|
141
142
|
*/
|
|
142
143
|
static JOIN_FAILED: number;
|
|
144
|
+
/**
|
|
145
|
+
* Best-effort grace period in `leaveAndClose` for an in-flight join to
|
|
146
|
+
* complete before we give up and close without sending `leaveCallRequest`.
|
|
147
|
+
* Bounded so a stuck join can never hang the leave path.
|
|
148
|
+
*/
|
|
149
|
+
static LEAVE_NOTIFY_GRACE_MS: number;
|
|
143
150
|
/**
|
|
144
151
|
* Constructs a new SFU client.
|
|
145
152
|
*/
|
|
@@ -113,7 +113,7 @@ export declare class StreamClient {
|
|
|
113
113
|
*/
|
|
114
114
|
_setupConnectionIdPromise: () => void;
|
|
115
115
|
get connectionIdPromise(): Promise<string | undefined> | undefined;
|
|
116
|
-
get
|
|
116
|
+
get isConnectionIdPromisePending(): boolean;
|
|
117
117
|
get wsPromise(): Promise<ConnectedEvent | undefined> | undefined;
|
|
118
118
|
_logApiRequest: (type: string, url: string, data: unknown, config: AxiosRequestConfig & {
|
|
119
119
|
config?: AxiosRequestConfig & {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StreamClient } from './client';
|
|
2
|
-
import type { UR } from './types';
|
|
2
|
+
import type { UR, WSConnectionError } from './types';
|
|
3
3
|
import type { LogLevel } from '@stream-io/logger';
|
|
4
4
|
import type { ConnectedEvent } from '../../gen/coordinator';
|
|
5
5
|
/**
|
|
@@ -20,43 +20,48 @@ import type { ConnectedEvent } from '../../gen/coordinator';
|
|
|
20
20
|
* - if the servers fails to publish a message to the client, the WS connection is destroyed
|
|
21
21
|
*/
|
|
22
22
|
export declare class StableWSConnection {
|
|
23
|
+
client: StreamClient;
|
|
24
|
+
ws?: WebSocket;
|
|
25
|
+
/** Incremented when a new WS connection is made */
|
|
26
|
+
wsID: number;
|
|
27
|
+
/** We only make 1 attempt to reconnect at the same time.. */
|
|
28
|
+
isConnecting: boolean;
|
|
29
|
+
/** To avoid reconnect if client is disconnected */
|
|
30
|
+
isDisconnected: boolean;
|
|
31
|
+
/** Boolean that indicates if we have a working connection to the server */
|
|
32
|
+
isHealthy: boolean;
|
|
23
33
|
connectionID?: string;
|
|
24
34
|
private connectionOpenSafe?;
|
|
35
|
+
resolveConnectionOpen?: (value: ConnectedEvent) => void;
|
|
36
|
+
rejectConnectionOpen?: (reason?: WSConnectionError) => void;
|
|
37
|
+
/** Boolean that indicates if the connection promise is resolved */
|
|
38
|
+
isConnectionOpenResolved?: boolean;
|
|
39
|
+
/** consecutive failures influence the duration of the timeout */
|
|
25
40
|
consecutiveFailures: number;
|
|
41
|
+
/** keep track of the total number of failures */
|
|
42
|
+
totalFailures: number;
|
|
43
|
+
/** Send a health check message every 25 seconds */
|
|
26
44
|
pingInterval: number;
|
|
27
45
|
healthCheckTimeoutRef?: number;
|
|
28
|
-
isConnecting: boolean;
|
|
29
|
-
isDisconnected: boolean;
|
|
30
|
-
isHealthy: boolean;
|
|
31
|
-
isConnectionOpenResolved?: boolean;
|
|
32
|
-
lastEvent: Date | null;
|
|
33
46
|
connectionCheckTimeout: number;
|
|
34
47
|
connectionCheckTimeoutRef?: NodeJS.Timeout;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
isWSFailure?: boolean;
|
|
38
|
-
StatusCode?: string | number;
|
|
39
|
-
}) => void;
|
|
40
|
-
resolveConnectionOpen?: (value: ConnectedEvent) => void;
|
|
41
|
-
totalFailures: number;
|
|
42
|
-
ws?: WebSocket;
|
|
43
|
-
wsID: number;
|
|
44
|
-
client: StreamClient;
|
|
48
|
+
/** Store the last event time for health checks */
|
|
49
|
+
lastEvent: Date | null;
|
|
45
50
|
constructor(client: StreamClient);
|
|
46
|
-
_log: (msg: string, extra?: UR, level?: LogLevel) => void;
|
|
51
|
+
_log: (msg: string, extra?: UR | Error, level?: LogLevel) => void;
|
|
47
52
|
setClient: (client: StreamClient) => void;
|
|
48
53
|
/**
|
|
49
54
|
* connect - Connect to the WS URL
|
|
50
55
|
* the default 15s timeout allows between 2~3 tries
|
|
51
|
-
* @return
|
|
56
|
+
* @return Promise that completes once the first health check message is received
|
|
52
57
|
*/
|
|
53
|
-
connect(timeout?: number)
|
|
58
|
+
connect: (timeout?: number) => Promise<ConnectedEvent | undefined>;
|
|
54
59
|
/**
|
|
55
60
|
* _waitForHealthy polls the promise connection to see if its resolved until it times out
|
|
56
61
|
* the default 15s timeout allows between 2~3 tries
|
|
57
62
|
* @param timeout duration(ms)
|
|
58
63
|
*/
|
|
59
|
-
_waitForHealthy(timeout?: number)
|
|
64
|
+
_waitForHealthy: (timeout?: number) => Promise<ConnectedEvent | undefined>;
|
|
60
65
|
/**
|
|
61
66
|
* Builds and returns the url for websocket.
|
|
62
67
|
* @private
|
|
@@ -65,15 +70,17 @@ export declare class StableWSConnection {
|
|
|
65
70
|
_buildUrl: () => string;
|
|
66
71
|
/**
|
|
67
72
|
* disconnect - Disconnect the connection and doesn't recover...
|
|
68
|
-
*
|
|
69
73
|
*/
|
|
70
|
-
disconnect(timeout?: number)
|
|
74
|
+
disconnect: (timeout?: number) => Promise<void>;
|
|
71
75
|
/**
|
|
72
76
|
* _connect - Connect to the WS endpoint
|
|
73
77
|
*
|
|
74
|
-
* @
|
|
78
|
+
* @param timeoutMs handshake watchdog deadline in ms. Defaults to
|
|
79
|
+
* `client.defaultWSTimeout` when not provided. Top-level `connect(timeout)`
|
|
80
|
+
* passes its own timeout through so caller-supplied deadlines are honored.
|
|
81
|
+
* @return Promise that completes once the first health check message is received
|
|
75
82
|
*/
|
|
76
|
-
_connect()
|
|
83
|
+
_connect: (timeoutMs?: number) => Promise<ConnectedEvent | undefined>;
|
|
77
84
|
/**
|
|
78
85
|
* _reconnect - Retry the connection to WS endpoint
|
|
79
86
|
*
|
|
@@ -90,7 +97,6 @@ export declare class StableWSConnection {
|
|
|
90
97
|
* onlineStatusChanged - this function is called when the browser connects or disconnects from the internet.
|
|
91
98
|
*
|
|
92
99
|
* @param {Event} event Event with type online or offline
|
|
93
|
-
*
|
|
94
100
|
*/
|
|
95
101
|
onlineStatusChanged: (event: Event) => void;
|
|
96
102
|
onopen: (wsID: number) => void;
|
|
@@ -36,6 +36,20 @@ export type APIErrorResponse = {
|
|
|
36
36
|
details?: ErrorResponseDetails;
|
|
37
37
|
unrecoverable?: boolean;
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* A standard `Error` augmented with the metadata that the coordinator
|
|
41
|
+
* WebSocket connection layer attaches to rejection causes.
|
|
42
|
+
* `isWSFailure: true` marks transient/retriable failures; absent or `false`
|
|
43
|
+
* indicates a permanent failure that should not be retried.
|
|
44
|
+
*/
|
|
45
|
+
export type WSConnectionError = Error & {
|
|
46
|
+
code?: string | number;
|
|
47
|
+
isWSFailure?: boolean;
|
|
48
|
+
StatusCode?: string | number;
|
|
49
|
+
reason?: string;
|
|
50
|
+
wasClean?: boolean;
|
|
51
|
+
target?: EventTarget | null;
|
|
52
|
+
};
|
|
39
53
|
export declare class ErrorFromResponse<T> extends Error {
|
|
40
54
|
code: number | null;
|
|
41
55
|
status: number;
|
|
@@ -2,6 +2,7 @@ import type { AxiosResponse } from 'axios';
|
|
|
2
2
|
import type { APIErrorResponse } from './types';
|
|
3
3
|
import type { ConnectionErrorEvent } from '../../gen/coordinator';
|
|
4
4
|
export declare const sleep: (m: number) => Promise<unknown>;
|
|
5
|
+
export declare const timeboxed: <T extends Promise<unknown>[]>(promises: [...T], ms: number) => Promise<{ [K in keyof T]: Awaited<T[K]>; }>;
|
|
5
6
|
export declare function isFunction<T>(value: Function | T): value is Function;
|
|
6
7
|
/**
|
|
7
8
|
* A map of known error codes.
|
|
@@ -16,6 +16,7 @@ export declare abstract class DeviceManager<S extends DeviceManagerState<C>, C =
|
|
|
16
16
|
protected readonly call: Call;
|
|
17
17
|
protected readonly trackType: TrackType;
|
|
18
18
|
protected subscriptions: (() => void)[];
|
|
19
|
+
protected currentStreamCleanups: (() => void)[];
|
|
19
20
|
protected devicePersistence: Required<DevicePersistenceOptions>;
|
|
20
21
|
protected areSubscriptionsSetUp: boolean;
|
|
21
22
|
private isTrackStoppedDueToTrackEnd;
|
|
@@ -89,6 +90,7 @@ export declare abstract class DeviceManager<S extends DeviceManagerState<C>, C =
|
|
|
89
90
|
* @internal
|
|
90
91
|
*/
|
|
91
92
|
dispose: () => void;
|
|
93
|
+
private runCurrentStreamCleanups;
|
|
92
94
|
protected applySettingsToStream(): Promise<void>;
|
|
93
95
|
protected abstract getDevices(): Observable<MediaDeviceInfo[]>;
|
|
94
96
|
protected abstract getStream(constraints: C): Promise<MediaStream>;
|
|
@@ -101,6 +103,7 @@ export declare abstract class DeviceManager<S extends DeviceManagerState<C>, C =
|
|
|
101
103
|
private stopTracks;
|
|
102
104
|
private muteLocalStream;
|
|
103
105
|
protected unmuteStream(): Promise<void>;
|
|
106
|
+
private setLocalInterrupted;
|
|
104
107
|
private get mediaDeviceKind();
|
|
105
108
|
private handleDisconnectedOrReplacedDevices;
|
|
106
109
|
protected findDevice(devices: MediaDeviceInfo[], deviceId: string): MediaDeviceInfo | undefined;
|
|
@@ -6,6 +6,7 @@ export declare abstract class DeviceManagerState<C = MediaTrackConstraints> {
|
|
|
6
6
|
protected statusSubject: BehaviorSubject<InputDeviceStatus>;
|
|
7
7
|
protected optimisticStatusSubject: BehaviorSubject<InputDeviceStatus>;
|
|
8
8
|
protected mediaStreamSubject: BehaviorSubject<MediaStream | undefined>;
|
|
9
|
+
protected rootMediaStreamSubject: BehaviorSubject<MediaStream | undefined>;
|
|
9
10
|
protected selectedDeviceSubject: BehaviorSubject<string | undefined>;
|
|
10
11
|
protected defaultConstraintsSubject: BehaviorSubject<C | undefined>;
|
|
11
12
|
/**
|
|
@@ -14,9 +15,14 @@ export declare abstract class DeviceManagerState<C = MediaTrackConstraints> {
|
|
|
14
15
|
prevStatus: InputDeviceStatus;
|
|
15
16
|
/**
|
|
16
17
|
* An Observable that emits the current media stream, or `undefined` if the device is currently disabled.
|
|
17
|
-
*
|
|
18
18
|
*/
|
|
19
19
|
mediaStream$: Observable<MediaStream | undefined>;
|
|
20
|
+
/**
|
|
21
|
+
* An Observable that emits the raw device media stream (before any filters are applied),
|
|
22
|
+
* or `undefined` if the device is currently disabled. When no filters are active, this
|
|
23
|
+
* emits the same stream as `mediaStream$`.
|
|
24
|
+
*/
|
|
25
|
+
rootMediaStream$: Observable<MediaStream | undefined>;
|
|
20
26
|
/**
|
|
21
27
|
* An Observable that emits the currently selected device
|
|
22
28
|
*/
|
|
@@ -73,6 +79,12 @@ export declare abstract class DeviceManagerState<C = MediaTrackConstraints> {
|
|
|
73
79
|
* The current media stream, or `undefined` if the device is currently disabled.
|
|
74
80
|
*/
|
|
75
81
|
get mediaStream(): MediaStream | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* The raw device media stream (before any filters are applied), or `undefined`
|
|
84
|
+
* if the device is currently disabled. When no filters are active, this is the
|
|
85
|
+
* same as `mediaStream`.
|
|
86
|
+
*/
|
|
87
|
+
get rootMediaStream(): MediaStream | undefined;
|
|
76
88
|
/**
|
|
77
89
|
* @internal
|
|
78
90
|
* @param status
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MessageType } from '@protobuf-ts/runtime';
|
|
2
|
-
import { CallEndedReason, CallGrants, CallState, ClientCapability, ClientDetails, Codec, ConnectionQuality, Error as Error$, GoAwayReason, ICETrickle as ICETrickle$, Participant, ParticipantCount, ParticipantSource, PeerType, Pin, PublishOption, SubscribeOption, TrackInfo, TrackType, TrackUnpublishReason, WebsocketReconnectStrategy } from '../models/models';
|
|
2
|
+
import { CallEndedReason, CallGrants, CallState, ClientCapability, ClientDetails, Codec, ConnectionQuality, DegradationPreference, Error as Error$, GoAwayReason, ICETrickle as ICETrickle$, Participant, ParticipantCount, ParticipantSource, PeerType, Pin, PublishOption, SubscribeOption, TrackInfo, TrackType, TrackUnpublishReason, WebsocketReconnectStrategy } from '../models/models';
|
|
3
3
|
import { TrackSubscriptionDetails } from '../signal_rpc/signal';
|
|
4
4
|
/**
|
|
5
5
|
* SFUEvent is a message that is sent from the SFU to the client.
|
|
@@ -785,6 +785,10 @@ export interface VideoSender {
|
|
|
785
785
|
* @generated from protobuf field: int32 publish_option_id = 5;
|
|
786
786
|
*/
|
|
787
787
|
publishOptionId: number;
|
|
788
|
+
/**
|
|
789
|
+
* @generated from protobuf field: stream.video.sfu.models.DegradationPreference degradation_preference = 6;
|
|
790
|
+
*/
|
|
791
|
+
degradationPreference: DegradationPreference;
|
|
788
792
|
}
|
|
789
793
|
/**
|
|
790
794
|
* sent to users when they need to change the quality of their video
|
|
@@ -303,6 +303,12 @@ export interface PublishOption {
|
|
|
303
303
|
* @generated from protobuf field: repeated stream.video.sfu.models.AudioBitrate audio_bitrate_profiles = 10;
|
|
304
304
|
*/
|
|
305
305
|
audioBitrateProfiles: AudioBitrate[];
|
|
306
|
+
/**
|
|
307
|
+
* The degradation preference for video encoding.
|
|
308
|
+
*
|
|
309
|
+
* @generated from protobuf field: stream.video.sfu.models.DegradationPreference degradation_preference = 11;
|
|
310
|
+
*/
|
|
311
|
+
degradationPreference: DegradationPreference;
|
|
306
312
|
}
|
|
307
313
|
/**
|
|
308
314
|
* @generated from protobuf message stream.video.sfu.models.Codec
|
|
@@ -1168,6 +1174,34 @@ export declare enum ClientCapability {
|
|
|
1168
1174
|
*/
|
|
1169
1175
|
SUBSCRIBER_VIDEO_PAUSE = 1
|
|
1170
1176
|
}
|
|
1177
|
+
/**
|
|
1178
|
+
* DegradationPreference represents the RTCDegradationPreference from WebRTC.
|
|
1179
|
+
* See https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/setParameters#degradationpreference
|
|
1180
|
+
*
|
|
1181
|
+
* @generated from protobuf enum stream.video.sfu.models.DegradationPreference
|
|
1182
|
+
*/
|
|
1183
|
+
export declare enum DegradationPreference {
|
|
1184
|
+
/**
|
|
1185
|
+
* @generated from protobuf enum value: DEGRADATION_PREFERENCE_UNSPECIFIED = 0;
|
|
1186
|
+
*/
|
|
1187
|
+
UNSPECIFIED = 0,
|
|
1188
|
+
/**
|
|
1189
|
+
* @generated from protobuf enum value: DEGRADATION_PREFERENCE_BALANCED = 1;
|
|
1190
|
+
*/
|
|
1191
|
+
BALANCED = 1,
|
|
1192
|
+
/**
|
|
1193
|
+
* @generated from protobuf enum value: DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE = 2;
|
|
1194
|
+
*/
|
|
1195
|
+
MAINTAIN_FRAMERATE = 2,
|
|
1196
|
+
/**
|
|
1197
|
+
* @generated from protobuf enum value: DEGRADATION_PREFERENCE_MAINTAIN_RESOLUTION = 3;
|
|
1198
|
+
*/
|
|
1199
|
+
MAINTAIN_RESOLUTION = 3,
|
|
1200
|
+
/**
|
|
1201
|
+
* @generated from protobuf enum value: DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE_AND_RESOLUTION = 4;
|
|
1202
|
+
*/
|
|
1203
|
+
MAINTAIN_FRAMERATE_AND_RESOLUTION = 4
|
|
1204
|
+
}
|
|
1171
1205
|
declare class CallState$Type extends MessageType<CallState> {
|
|
1172
1206
|
constructor();
|
|
1173
1207
|
}
|
|
@@ -6,19 +6,19 @@ import { Tracer } from '../stats';
|
|
|
6
6
|
* remote participants whose audio streams have no bound element.
|
|
7
7
|
*/
|
|
8
8
|
export declare class AudioBindingsWatchdog {
|
|
9
|
-
private state;
|
|
10
|
-
private tracer;
|
|
11
9
|
private bindings;
|
|
12
10
|
private enabled;
|
|
13
11
|
private watchdogInterval?;
|
|
14
12
|
private readonly unsubscribeCallingState;
|
|
15
13
|
private logger;
|
|
14
|
+
private readonly state;
|
|
15
|
+
private readonly tracer;
|
|
16
16
|
constructor(state: CallState, tracer: Tracer);
|
|
17
17
|
/**
|
|
18
18
|
* Registers an audio element binding for the given session and track type.
|
|
19
19
|
* Warns if a different element is already bound to the same key.
|
|
20
20
|
*/
|
|
21
|
-
register: (
|
|
21
|
+
register: (element: HTMLAudioElement, sessionId: string, trackType: AudioTrackType) => void;
|
|
22
22
|
/**
|
|
23
23
|
* Removes the audio element binding for the given session and track type.
|
|
24
24
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Tracer } from '../stats';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks audio elements that the browser's autoplay policy has blocked.
|
|
4
|
+
*/
|
|
5
|
+
export declare class BlockedAudioTracker {
|
|
6
|
+
private logger;
|
|
7
|
+
private tracer;
|
|
8
|
+
private blockedElementsSubject;
|
|
9
|
+
/**
|
|
10
|
+
* Whether the browser's autoplay policy is blocking audio playback.
|
|
11
|
+
* Will be `true` when at least one audio element is currently blocked.
|
|
12
|
+
* Use {@link resumeAudio} within a user gesture to unblock.
|
|
13
|
+
*/
|
|
14
|
+
autoplayBlocked$: import("rxjs").Observable<boolean>;
|
|
15
|
+
constructor(tracer: Tracer);
|
|
16
|
+
/**
|
|
17
|
+
* Registers an audio element as blocked by the browser's autoplay policy.
|
|
18
|
+
*/
|
|
19
|
+
markBlocked: (audioElement: HTMLAudioElement, blocked: boolean) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Returns whether the given audio element is currently flagged as blocked
|
|
22
|
+
* by the browser's autoplay policy.
|
|
23
|
+
*/
|
|
24
|
+
isBlocked: (audioElement: HTMLAudioElement) => boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Plays all audio elements blocked by the browser's autoplay policy.
|
|
27
|
+
* Must be called from within a user gesture (e.g., click handler).
|
|
28
|
+
*/
|
|
29
|
+
resumeAudio: () => Promise<void>;
|
|
30
|
+
}
|
|
@@ -1,102 +1,32 @@
|
|
|
1
|
-
import { AudioTrackType,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { AudioBindingsWatchdog } from './AudioBindingsWatchdog';
|
|
5
|
-
import type { TrackSubscriptionDetails } from '../gen/video/sfu/signal_rpc/signal';
|
|
1
|
+
import { AudioTrackType, VideoTrackType } from '../types';
|
|
2
|
+
import type { BlockedAudioTracker } from './BlockedAudioTracker';
|
|
3
|
+
import type { TrackSubscriptionManager } from './TrackSubscriptionManager';
|
|
6
4
|
import { CallState } from '../store';
|
|
7
|
-
import type { StreamSfuClient } from '../StreamSfuClient';
|
|
8
5
|
import { SpeakerManager } from '../devices';
|
|
9
6
|
import { Tracer } from '../stats';
|
|
10
|
-
type VideoTrackSubscriptionOverride = {
|
|
11
|
-
enabled: true;
|
|
12
|
-
dimension: VideoDimension;
|
|
13
|
-
} | {
|
|
14
|
-
enabled: false;
|
|
15
|
-
};
|
|
16
|
-
declare const globalOverrideKey: unique symbol;
|
|
17
|
-
interface VideoTrackSubscriptionOverrides {
|
|
18
|
-
[sessionId: string]: VideoTrackSubscriptionOverride | undefined;
|
|
19
|
-
[globalOverrideKey]?: VideoTrackSubscriptionOverride;
|
|
20
|
-
}
|
|
21
7
|
/**
|
|
22
8
|
* A manager class that handles dynascale related tasks like:
|
|
23
9
|
*
|
|
24
10
|
* - binding video elements to session ids
|
|
25
11
|
* - binding audio elements to session ids
|
|
26
|
-
* - tracking element visibility
|
|
27
|
-
* - updating subscriptions based on viewport visibility
|
|
28
|
-
* - updating subscriptions based on video element dimensions
|
|
29
|
-
* - updating subscriptions based on published tracks
|
|
30
12
|
*/
|
|
31
13
|
export declare class DynascaleManager {
|
|
32
|
-
/**
|
|
33
|
-
* The viewport tracker instance.
|
|
34
|
-
*/
|
|
35
|
-
readonly viewportTracker: ViewportTracker;
|
|
36
14
|
private logger;
|
|
37
15
|
private callState;
|
|
38
16
|
private speaker;
|
|
39
|
-
private tracer;
|
|
17
|
+
private readonly tracer;
|
|
40
18
|
private useWebAudio;
|
|
41
19
|
private audioContext;
|
|
42
|
-
private
|
|
43
|
-
private
|
|
44
|
-
readonly audioBindingsWatchdog: AudioBindingsWatchdog | undefined;
|
|
45
|
-
/**
|
|
46
|
-
* Audio elements that were blocked by the browser's autoplay policy.
|
|
47
|
-
* These can be retried by calling `resumeAudio()` from a user gesture.
|
|
48
|
-
*/
|
|
49
|
-
private blockedAudioElementsSubject;
|
|
50
|
-
/**
|
|
51
|
-
* Whether the browser's autoplay policy is blocking audio playback.
|
|
52
|
-
* Will be `true` when the browser blocks autoplay (e.g., no prior user interaction).
|
|
53
|
-
* Use `resumeAudio()` within a user gesture to unblock.
|
|
54
|
-
*/
|
|
55
|
-
autoplayBlocked$: import("rxjs").Observable<boolean>;
|
|
56
|
-
private addBlockedAudioElement;
|
|
57
|
-
private removeBlockedAudioElement;
|
|
58
|
-
private videoTrackSubscriptionOverridesSubject;
|
|
59
|
-
videoTrackSubscriptionOverrides$: import("rxjs").Observable<VideoTrackSubscriptionOverrides>;
|
|
60
|
-
incomingVideoSettings$: import("rxjs").Observable<{
|
|
61
|
-
enabled: boolean;
|
|
62
|
-
preferredResolution: VideoDimension | undefined;
|
|
63
|
-
participants: {
|
|
64
|
-
[k: string]: {
|
|
65
|
-
enabled: boolean;
|
|
66
|
-
preferredResolution: VideoDimension | undefined;
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
isParticipantVideoEnabled: (sessionId: string) => boolean;
|
|
70
|
-
}>;
|
|
20
|
+
private trackSubscriptionManager;
|
|
21
|
+
private blockedAudioTracker;
|
|
71
22
|
/**
|
|
72
23
|
* Creates a new DynascaleManager instance.
|
|
73
24
|
*/
|
|
74
|
-
constructor(callState: CallState, speaker: SpeakerManager, tracer: Tracer);
|
|
25
|
+
constructor(callState: CallState, speaker: SpeakerManager, tracer: Tracer, trackSubscriptionManager: TrackSubscriptionManager, blockedAudioTracker: BlockedAudioTracker);
|
|
75
26
|
/**
|
|
76
|
-
*
|
|
27
|
+
* Closes the audio context if it was created.
|
|
77
28
|
*/
|
|
78
29
|
dispose: () => Promise<void>;
|
|
79
|
-
setSfuClient(sfuClient: StreamSfuClient | undefined): void;
|
|
80
|
-
get trackSubscriptions(): TrackSubscriptionDetails[];
|
|
81
|
-
get videoTrackSubscriptionOverrides(): VideoTrackSubscriptionOverrides;
|
|
82
|
-
setVideoTrackSubscriptionOverrides: (override: VideoTrackSubscriptionOverride | undefined, sessionIds?: string[]) => VideoTrackSubscriptionOverrides;
|
|
83
|
-
applyTrackSubscriptions: (debounceType?: DebounceType) => void;
|
|
84
|
-
/**
|
|
85
|
-
* Will begin tracking the given element for visibility changes within the
|
|
86
|
-
* configured viewport element (`call.setViewport`).
|
|
87
|
-
*
|
|
88
|
-
* @param element the element to track.
|
|
89
|
-
* @param sessionId the session id.
|
|
90
|
-
* @param trackType the kind of video.
|
|
91
|
-
* @returns Untrack.
|
|
92
|
-
*/
|
|
93
|
-
trackElementVisibility: <T extends HTMLElement>(element: T, sessionId: string, trackType: VideoTrackType) => () => void;
|
|
94
|
-
/**
|
|
95
|
-
* Sets the viewport element to track bound video elements for visibility.
|
|
96
|
-
*
|
|
97
|
-
* @param element the viewport element.
|
|
98
|
-
*/
|
|
99
|
-
setViewport: <T extends HTMLElement>(element: T) => () => void;
|
|
100
30
|
/**
|
|
101
31
|
* Sets whether to use WebAudio API for audio playback.
|
|
102
32
|
* Must be set before joining the call.
|
|
@@ -134,14 +64,6 @@ export declare class DynascaleManager {
|
|
|
134
64
|
* @returns a cleanup function that will unbind the audio element.
|
|
135
65
|
*/
|
|
136
66
|
bindAudioElement: (audioElement: HTMLAudioElement, sessionId: string, trackType: AudioTrackType) => (() => void) | undefined;
|
|
137
|
-
/**
|
|
138
|
-
* Plays all audio elements blocked by the browser's autoplay policy.
|
|
139
|
-
* Must be called from within a user gesture (e.g., click handler).
|
|
140
|
-
*
|
|
141
|
-
* @returns a promise that resolves when all blocked elements have been retried.
|
|
142
|
-
*/
|
|
143
|
-
resumeAudio: () => Promise<void>;
|
|
144
67
|
private getOrCreateAudioContext;
|
|
145
68
|
private resumeAudioContext;
|
|
146
69
|
}
|
|
147
|
-
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Tracer } from '../stats';
|
|
2
|
+
type MediaKind = 'audio' | 'video';
|
|
3
|
+
export type MediaPlaybackWatchdogOptions = {
|
|
4
|
+
element: HTMLMediaElement;
|
|
5
|
+
kind: MediaKind;
|
|
6
|
+
tracer: Tracer;
|
|
7
|
+
isBlocked?: () => boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Watches a single audio or video element and attempts to recover playback
|
|
11
|
+
* after the element transitions to a paused or suspended state unexpectedly.
|
|
12
|
+
*/
|
|
13
|
+
export declare class MediaPlaybackWatchdog {
|
|
14
|
+
private logger;
|
|
15
|
+
private readonly kind;
|
|
16
|
+
private readonly isBlocked;
|
|
17
|
+
private element;
|
|
18
|
+
private tracer;
|
|
19
|
+
private controller;
|
|
20
|
+
private pendingTimer;
|
|
21
|
+
private attempt;
|
|
22
|
+
private disposed;
|
|
23
|
+
constructor(opts: MediaPlaybackWatchdogOptions);
|
|
24
|
+
private attach;
|
|
25
|
+
dispose: () => void;
|
|
26
|
+
private onPlaying;
|
|
27
|
+
private onPauseOrSuspend;
|
|
28
|
+
private scheduleRecovery;
|
|
29
|
+
private computeSkipReason;
|
|
30
|
+
private attemptPlay;
|
|
31
|
+
}
|
|
32
|
+
export {};
|