@stream-io/video-client 1.4.7 → 1.5.0-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 +238 -0
- package/dist/index.browser.es.js +1977 -1477
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +1975 -1474
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1977 -1477
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +93 -9
- package/dist/src/StreamSfuClient.d.ts +72 -56
- package/dist/src/StreamVideoClient.d.ts +2 -2
- package/dist/src/coordinator/connection/client.d.ts +3 -4
- package/dist/src/coordinator/connection/types.d.ts +5 -1
- package/dist/src/devices/InputMediaDeviceManager.d.ts +4 -0
- package/dist/src/devices/MicrophoneManager.d.ts +1 -1
- package/dist/src/events/callEventHandlers.d.ts +1 -3
- package/dist/src/events/internal.d.ts +4 -0
- package/dist/src/gen/video/sfu/event/events.d.ts +106 -4
- package/dist/src/gen/video/sfu/models/models.d.ts +64 -65
- package/dist/src/helpers/ensureExhausted.d.ts +1 -0
- package/dist/src/helpers/withResolvers.d.ts +14 -0
- package/dist/src/logger.d.ts +1 -0
- package/dist/src/rpc/createClient.d.ts +2 -0
- package/dist/src/rpc/index.d.ts +1 -0
- package/dist/src/rpc/retryable.d.ts +23 -0
- package/dist/src/rtc/Dispatcher.d.ts +1 -1
- package/dist/src/rtc/IceTrickleBuffer.d.ts +0 -1
- package/dist/src/rtc/Publisher.d.ts +24 -25
- package/dist/src/rtc/Subscriber.d.ts +12 -11
- package/dist/src/rtc/helpers/rtcConfiguration.d.ts +2 -0
- package/dist/src/rtc/helpers/tracks.d.ts +3 -3
- package/dist/src/rtc/signal.d.ts +1 -1
- package/dist/src/store/CallState.d.ts +46 -2
- package/package.json +5 -5
- package/src/Call.ts +618 -563
- package/src/StreamSfuClient.ts +277 -246
- package/src/StreamVideoClient.ts +15 -16
- package/src/__tests__/Call.test.ts +145 -2
- package/src/__tests__/StreamVideoClient.api.test.ts +168 -0
- package/src/coordinator/connection/client.ts +25 -8
- package/src/coordinator/connection/connection.ts +2 -1
- package/src/coordinator/connection/types.ts +6 -0
- package/src/devices/BrowserPermission.ts +1 -1
- package/src/devices/CameraManager.ts +1 -1
- package/src/devices/InputMediaDeviceManager.ts +12 -3
- package/src/devices/MicrophoneManager.ts +3 -3
- package/src/devices/devices.ts +1 -1
- package/src/events/__tests__/mutes.test.ts +10 -13
- package/src/events/__tests__/participant.test.ts +75 -0
- package/src/events/callEventHandlers.ts +4 -7
- package/src/events/internal.ts +20 -3
- package/src/events/mutes.ts +5 -3
- package/src/events/participant.ts +48 -15
- package/src/gen/video/sfu/event/events.ts +451 -8
- package/src/gen/video/sfu/models/models.ts +211 -204
- package/src/helpers/ensureExhausted.ts +5 -0
- package/src/helpers/withResolvers.ts +43 -0
- package/src/logger.ts +3 -1
- package/src/rpc/__tests__/retryable.test.ts +72 -0
- package/src/rpc/createClient.ts +21 -0
- package/src/rpc/index.ts +1 -0
- package/src/rpc/retryable.ts +57 -0
- package/src/rtc/Dispatcher.ts +6 -2
- package/src/rtc/IceTrickleBuffer.ts +2 -2
- package/src/rtc/Publisher.ts +127 -163
- package/src/rtc/Subscriber.ts +94 -155
- package/src/rtc/__tests__/Publisher.test.ts +18 -95
- package/src/rtc/__tests__/Subscriber.test.ts +63 -99
- package/src/rtc/__tests__/videoLayers.test.ts +2 -2
- package/src/rtc/helpers/rtcConfiguration.ts +11 -0
- package/src/rtc/helpers/tracks.ts +27 -7
- package/src/rtc/signal.ts +3 -3
- package/src/rtc/videoLayers.ts +1 -10
- package/src/stats/SfuStatsReporter.ts +1 -0
- package/src/store/CallState.ts +111 -3
- package/src/store/__tests__/CallState.test.ts +58 -37
- package/dist/src/rtc/flows/join.d.ts +0 -20
- package/src/rtc/flows/join.ts +0 -65
|
@@ -286,49 +286,10 @@ export interface TrackInfo {
|
|
|
286
286
|
* @generated from protobuf field: bool red = 9;
|
|
287
287
|
*/
|
|
288
288
|
red: boolean;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* todo remove this
|
|
292
|
-
*
|
|
293
|
-
* @generated from protobuf message stream.video.sfu.models.Call
|
|
294
|
-
*/
|
|
295
|
-
export interface Call {
|
|
296
289
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
* @generated from protobuf field: string type = 1;
|
|
290
|
+
* @generated from protobuf field: bool muted = 10;
|
|
300
291
|
*/
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* the call id
|
|
304
|
-
*
|
|
305
|
-
* @generated from protobuf field: string id = 2;
|
|
306
|
-
*/
|
|
307
|
-
id: string;
|
|
308
|
-
/**
|
|
309
|
-
* the id of the user that created this call
|
|
310
|
-
*
|
|
311
|
-
* @generated from protobuf field: string created_by_user_id = 3;
|
|
312
|
-
*/
|
|
313
|
-
createdByUserId: string;
|
|
314
|
-
/**
|
|
315
|
-
* the id of the current host for this call
|
|
316
|
-
*
|
|
317
|
-
* @generated from protobuf field: string host_user_id = 4;
|
|
318
|
-
*/
|
|
319
|
-
hostUserId: string;
|
|
320
|
-
/**
|
|
321
|
-
* @generated from protobuf field: google.protobuf.Struct custom = 5;
|
|
322
|
-
*/
|
|
323
|
-
custom?: Struct;
|
|
324
|
-
/**
|
|
325
|
-
* @generated from protobuf field: google.protobuf.Timestamp created_at = 6;
|
|
326
|
-
*/
|
|
327
|
-
createdAt?: Timestamp;
|
|
328
|
-
/**
|
|
329
|
-
* @generated from protobuf field: google.protobuf.Timestamp updated_at = 7;
|
|
330
|
-
*/
|
|
331
|
-
updatedAt?: Timestamp;
|
|
292
|
+
muted: boolean;
|
|
332
293
|
}
|
|
333
294
|
/**
|
|
334
295
|
* @generated from protobuf message stream.video.sfu.models.Error
|
|
@@ -432,6 +393,47 @@ export interface Device {
|
|
|
432
393
|
*/
|
|
433
394
|
version: string;
|
|
434
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* @generated from protobuf message stream.video.sfu.models.Call
|
|
398
|
+
*/
|
|
399
|
+
export interface Call {
|
|
400
|
+
/**
|
|
401
|
+
* the call type
|
|
402
|
+
*
|
|
403
|
+
* @generated from protobuf field: string type = 1;
|
|
404
|
+
*/
|
|
405
|
+
type: string;
|
|
406
|
+
/**
|
|
407
|
+
* the call id
|
|
408
|
+
*
|
|
409
|
+
* @generated from protobuf field: string id = 2;
|
|
410
|
+
*/
|
|
411
|
+
id: string;
|
|
412
|
+
/**
|
|
413
|
+
* the id of the user that created this call
|
|
414
|
+
*
|
|
415
|
+
* @generated from protobuf field: string created_by_user_id = 3;
|
|
416
|
+
*/
|
|
417
|
+
createdByUserId: string;
|
|
418
|
+
/**
|
|
419
|
+
* the id of the current host for this call
|
|
420
|
+
*
|
|
421
|
+
* @generated from protobuf field: string host_user_id = 4;
|
|
422
|
+
*/
|
|
423
|
+
hostUserId: string;
|
|
424
|
+
/**
|
|
425
|
+
* @generated from protobuf field: google.protobuf.Struct custom = 5;
|
|
426
|
+
*/
|
|
427
|
+
custom?: Struct;
|
|
428
|
+
/**
|
|
429
|
+
* @generated from protobuf field: google.protobuf.Timestamp created_at = 6;
|
|
430
|
+
*/
|
|
431
|
+
createdAt?: Timestamp;
|
|
432
|
+
/**
|
|
433
|
+
* @generated from protobuf field: google.protobuf.Timestamp updated_at = 7;
|
|
434
|
+
*/
|
|
435
|
+
updatedAt?: Timestamp;
|
|
436
|
+
}
|
|
435
437
|
/**
|
|
436
438
|
* CallGrants represents the set of permissions given
|
|
437
439
|
* to the user for the current call.
|
|
@@ -741,6 +743,10 @@ export enum CallEndedReason {
|
|
|
741
743
|
* @generated from protobuf enum value: CALL_ENDED_REASON_KICKED = 3;
|
|
742
744
|
*/
|
|
743
745
|
KICKED = 3,
|
|
746
|
+
/**
|
|
747
|
+
* @generated from protobuf enum value: CALL_ENDED_REASON_SESSION_ENDED = 4;
|
|
748
|
+
*/
|
|
749
|
+
SESSION_ENDED = 4,
|
|
744
750
|
}
|
|
745
751
|
/**
|
|
746
752
|
* WebsocketReconnectStrategy defines the ws strategies available for handling reconnections.
|
|
@@ -753,7 +759,7 @@ export enum WebsocketReconnectStrategy {
|
|
|
753
759
|
*/
|
|
754
760
|
UNSPECIFIED = 0,
|
|
755
761
|
/**
|
|
756
|
-
* Sent after reaching the maximum reconnection attempts, leading to permanent disconnect.
|
|
762
|
+
* Sent after reaching the maximum reconnection attempts, or any other unrecoverable error leading to permanent disconnect.
|
|
757
763
|
*
|
|
758
764
|
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_DISCONNECT = 1;
|
|
759
765
|
*/
|
|
@@ -766,25 +772,18 @@ export enum WebsocketReconnectStrategy {
|
|
|
766
772
|
*/
|
|
767
773
|
FAST = 2,
|
|
768
774
|
/**
|
|
769
|
-
* SDK should
|
|
770
|
-
* ensuring a clean state for the reconnection.
|
|
771
|
-
*
|
|
772
|
-
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_CLEAN = 3;
|
|
773
|
-
*/
|
|
774
|
-
CLEAN = 3,
|
|
775
|
-
/**
|
|
776
|
-
* SDK should obtain new credentials from the coordinator, drops existing pc instances, and initializes
|
|
775
|
+
* SDK should obtain new credentials from the coordinator, drops existing pc instances, set a new session_id and initializes
|
|
777
776
|
* a completely new WebSocket connection, ensuring a comprehensive reset.
|
|
778
777
|
*
|
|
779
|
-
* @generated from protobuf enum value:
|
|
778
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_REJOIN = 3;
|
|
780
779
|
*/
|
|
781
|
-
|
|
780
|
+
REJOIN = 3,
|
|
782
781
|
/**
|
|
783
782
|
* SDK should migrate to a new SFU instance
|
|
784
783
|
*
|
|
785
|
-
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_MIGRATE =
|
|
784
|
+
* @generated from protobuf enum value: WEBSOCKET_RECONNECT_STRATEGY_MIGRATE = 4;
|
|
786
785
|
*/
|
|
787
|
-
MIGRATE =
|
|
786
|
+
MIGRATE = 4,
|
|
788
787
|
}
|
|
789
788
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
790
789
|
class CallState$Type extends MessageType<CallState> {
|
|
@@ -1838,6 +1837,7 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
|
|
|
1838
1837
|
{ no: 7, name: 'dtx', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ },
|
|
1839
1838
|
{ no: 8, name: 'stereo', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ },
|
|
1840
1839
|
{ no: 9, name: 'red', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ },
|
|
1840
|
+
{ no: 10, name: 'muted', kind: 'scalar', T: 8 /*ScalarType.BOOL*/ },
|
|
1841
1841
|
]);
|
|
1842
1842
|
}
|
|
1843
1843
|
create(value?: PartialMessage<TrackInfo>): TrackInfo {
|
|
@@ -1849,6 +1849,7 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
|
|
|
1849
1849
|
message.dtx = false;
|
|
1850
1850
|
message.stereo = false;
|
|
1851
1851
|
message.red = false;
|
|
1852
|
+
message.muted = false;
|
|
1852
1853
|
if (value !== undefined)
|
|
1853
1854
|
reflectionMergePartial<TrackInfo>(this, message, value);
|
|
1854
1855
|
return message;
|
|
@@ -1887,6 +1888,9 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
|
|
|
1887
1888
|
case /* bool red */ 9:
|
|
1888
1889
|
message.red = reader.bool();
|
|
1889
1890
|
break;
|
|
1891
|
+
case /* bool muted */ 10:
|
|
1892
|
+
message.muted = reader.bool();
|
|
1893
|
+
break;
|
|
1890
1894
|
default:
|
|
1891
1895
|
let u = options.readUnknownField;
|
|
1892
1896
|
if (u === 'throw')
|
|
@@ -1934,6 +1938,9 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
|
|
|
1934
1938
|
writer.tag(8, WireType.Varint).bool(message.stereo);
|
|
1935
1939
|
/* bool red = 9; */
|
|
1936
1940
|
if (message.red !== false) writer.tag(9, WireType.Varint).bool(message.red);
|
|
1941
|
+
/* bool muted = 10; */
|
|
1942
|
+
if (message.muted !== false)
|
|
1943
|
+
writer.tag(10, WireType.Varint).bool(message.muted);
|
|
1937
1944
|
let u = options.writeUnknownFields;
|
|
1938
1945
|
if (u !== false)
|
|
1939
1946
|
(u == true ? UnknownFieldHandler.onWrite : u)(
|
|
@@ -1949,156 +1956,6 @@ class TrackInfo$Type extends MessageType<TrackInfo> {
|
|
|
1949
1956
|
*/
|
|
1950
1957
|
export const TrackInfo = new TrackInfo$Type();
|
|
1951
1958
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1952
|
-
class Call$Type extends MessageType<Call> {
|
|
1953
|
-
constructor() {
|
|
1954
|
-
super('stream.video.sfu.models.Call', [
|
|
1955
|
-
{ no: 1, name: 'type', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
|
|
1956
|
-
{ no: 2, name: 'id', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
|
|
1957
|
-
{
|
|
1958
|
-
no: 3,
|
|
1959
|
-
name: 'created_by_user_id',
|
|
1960
|
-
kind: 'scalar',
|
|
1961
|
-
T: 9 /*ScalarType.STRING*/,
|
|
1962
|
-
},
|
|
1963
|
-
{
|
|
1964
|
-
no: 4,
|
|
1965
|
-
name: 'host_user_id',
|
|
1966
|
-
kind: 'scalar',
|
|
1967
|
-
T: 9 /*ScalarType.STRING*/,
|
|
1968
|
-
},
|
|
1969
|
-
{ no: 5, name: 'custom', kind: 'message', T: () => Struct },
|
|
1970
|
-
{ no: 6, name: 'created_at', kind: 'message', T: () => Timestamp },
|
|
1971
|
-
{ no: 7, name: 'updated_at', kind: 'message', T: () => Timestamp },
|
|
1972
|
-
]);
|
|
1973
|
-
}
|
|
1974
|
-
create(value?: PartialMessage<Call>): Call {
|
|
1975
|
-
const message = globalThis.Object.create(this.messagePrototype!);
|
|
1976
|
-
message.type = '';
|
|
1977
|
-
message.id = '';
|
|
1978
|
-
message.createdByUserId = '';
|
|
1979
|
-
message.hostUserId = '';
|
|
1980
|
-
if (value !== undefined) reflectionMergePartial<Call>(this, message, value);
|
|
1981
|
-
return message;
|
|
1982
|
-
}
|
|
1983
|
-
internalBinaryRead(
|
|
1984
|
-
reader: IBinaryReader,
|
|
1985
|
-
length: number,
|
|
1986
|
-
options: BinaryReadOptions,
|
|
1987
|
-
target?: Call,
|
|
1988
|
-
): Call {
|
|
1989
|
-
let message = target ?? this.create(),
|
|
1990
|
-
end = reader.pos + length;
|
|
1991
|
-
while (reader.pos < end) {
|
|
1992
|
-
let [fieldNo, wireType] = reader.tag();
|
|
1993
|
-
switch (fieldNo) {
|
|
1994
|
-
case /* string type */ 1:
|
|
1995
|
-
message.type = reader.string();
|
|
1996
|
-
break;
|
|
1997
|
-
case /* string id */ 2:
|
|
1998
|
-
message.id = reader.string();
|
|
1999
|
-
break;
|
|
2000
|
-
case /* string created_by_user_id */ 3:
|
|
2001
|
-
message.createdByUserId = reader.string();
|
|
2002
|
-
break;
|
|
2003
|
-
case /* string host_user_id */ 4:
|
|
2004
|
-
message.hostUserId = reader.string();
|
|
2005
|
-
break;
|
|
2006
|
-
case /* google.protobuf.Struct custom */ 5:
|
|
2007
|
-
message.custom = Struct.internalBinaryRead(
|
|
2008
|
-
reader,
|
|
2009
|
-
reader.uint32(),
|
|
2010
|
-
options,
|
|
2011
|
-
message.custom,
|
|
2012
|
-
);
|
|
2013
|
-
break;
|
|
2014
|
-
case /* google.protobuf.Timestamp created_at */ 6:
|
|
2015
|
-
message.createdAt = Timestamp.internalBinaryRead(
|
|
2016
|
-
reader,
|
|
2017
|
-
reader.uint32(),
|
|
2018
|
-
options,
|
|
2019
|
-
message.createdAt,
|
|
2020
|
-
);
|
|
2021
|
-
break;
|
|
2022
|
-
case /* google.protobuf.Timestamp updated_at */ 7:
|
|
2023
|
-
message.updatedAt = Timestamp.internalBinaryRead(
|
|
2024
|
-
reader,
|
|
2025
|
-
reader.uint32(),
|
|
2026
|
-
options,
|
|
2027
|
-
message.updatedAt,
|
|
2028
|
-
);
|
|
2029
|
-
break;
|
|
2030
|
-
default:
|
|
2031
|
-
let u = options.readUnknownField;
|
|
2032
|
-
if (u === 'throw')
|
|
2033
|
-
throw new globalThis.Error(
|
|
2034
|
-
`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`,
|
|
2035
|
-
);
|
|
2036
|
-
let d = reader.skip(wireType);
|
|
2037
|
-
if (u !== false)
|
|
2038
|
-
(u === true ? UnknownFieldHandler.onRead : u)(
|
|
2039
|
-
this.typeName,
|
|
2040
|
-
message,
|
|
2041
|
-
fieldNo,
|
|
2042
|
-
wireType,
|
|
2043
|
-
d,
|
|
2044
|
-
);
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
return message;
|
|
2048
|
-
}
|
|
2049
|
-
internalBinaryWrite(
|
|
2050
|
-
message: Call,
|
|
2051
|
-
writer: IBinaryWriter,
|
|
2052
|
-
options: BinaryWriteOptions,
|
|
2053
|
-
): IBinaryWriter {
|
|
2054
|
-
/* string type = 1; */
|
|
2055
|
-
if (message.type !== '')
|
|
2056
|
-
writer.tag(1, WireType.LengthDelimited).string(message.type);
|
|
2057
|
-
/* string id = 2; */
|
|
2058
|
-
if (message.id !== '')
|
|
2059
|
-
writer.tag(2, WireType.LengthDelimited).string(message.id);
|
|
2060
|
-
/* string created_by_user_id = 3; */
|
|
2061
|
-
if (message.createdByUserId !== '')
|
|
2062
|
-
writer.tag(3, WireType.LengthDelimited).string(message.createdByUserId);
|
|
2063
|
-
/* string host_user_id = 4; */
|
|
2064
|
-
if (message.hostUserId !== '')
|
|
2065
|
-
writer.tag(4, WireType.LengthDelimited).string(message.hostUserId);
|
|
2066
|
-
/* google.protobuf.Struct custom = 5; */
|
|
2067
|
-
if (message.custom)
|
|
2068
|
-
Struct.internalBinaryWrite(
|
|
2069
|
-
message.custom,
|
|
2070
|
-
writer.tag(5, WireType.LengthDelimited).fork(),
|
|
2071
|
-
options,
|
|
2072
|
-
).join();
|
|
2073
|
-
/* google.protobuf.Timestamp created_at = 6; */
|
|
2074
|
-
if (message.createdAt)
|
|
2075
|
-
Timestamp.internalBinaryWrite(
|
|
2076
|
-
message.createdAt,
|
|
2077
|
-
writer.tag(6, WireType.LengthDelimited).fork(),
|
|
2078
|
-
options,
|
|
2079
|
-
).join();
|
|
2080
|
-
/* google.protobuf.Timestamp updated_at = 7; */
|
|
2081
|
-
if (message.updatedAt)
|
|
2082
|
-
Timestamp.internalBinaryWrite(
|
|
2083
|
-
message.updatedAt,
|
|
2084
|
-
writer.tag(7, WireType.LengthDelimited).fork(),
|
|
2085
|
-
options,
|
|
2086
|
-
).join();
|
|
2087
|
-
let u = options.writeUnknownFields;
|
|
2088
|
-
if (u !== false)
|
|
2089
|
-
(u == true ? UnknownFieldHandler.onWrite : u)(
|
|
2090
|
-
this.typeName,
|
|
2091
|
-
message,
|
|
2092
|
-
writer,
|
|
2093
|
-
);
|
|
2094
|
-
return writer;
|
|
2095
|
-
}
|
|
2096
|
-
}
|
|
2097
|
-
/**
|
|
2098
|
-
* @generated MessageType for protobuf message stream.video.sfu.models.Call
|
|
2099
|
-
*/
|
|
2100
|
-
export const Call = new Call$Type();
|
|
2101
|
-
// @generated message type with reflection information, may provide speed optimized methods
|
|
2102
1959
|
class Error$Type extends MessageType<Error> {
|
|
2103
1960
|
constructor() {
|
|
2104
1961
|
super('stream.video.sfu.models.Error', [
|
|
@@ -2656,6 +2513,156 @@ class Device$Type extends MessageType<Device> {
|
|
|
2656
2513
|
*/
|
|
2657
2514
|
export const Device = new Device$Type();
|
|
2658
2515
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
2516
|
+
class Call$Type extends MessageType<Call> {
|
|
2517
|
+
constructor() {
|
|
2518
|
+
super('stream.video.sfu.models.Call', [
|
|
2519
|
+
{ no: 1, name: 'type', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
|
|
2520
|
+
{ no: 2, name: 'id', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
|
|
2521
|
+
{
|
|
2522
|
+
no: 3,
|
|
2523
|
+
name: 'created_by_user_id',
|
|
2524
|
+
kind: 'scalar',
|
|
2525
|
+
T: 9 /*ScalarType.STRING*/,
|
|
2526
|
+
},
|
|
2527
|
+
{
|
|
2528
|
+
no: 4,
|
|
2529
|
+
name: 'host_user_id',
|
|
2530
|
+
kind: 'scalar',
|
|
2531
|
+
T: 9 /*ScalarType.STRING*/,
|
|
2532
|
+
},
|
|
2533
|
+
{ no: 5, name: 'custom', kind: 'message', T: () => Struct },
|
|
2534
|
+
{ no: 6, name: 'created_at', kind: 'message', T: () => Timestamp },
|
|
2535
|
+
{ no: 7, name: 'updated_at', kind: 'message', T: () => Timestamp },
|
|
2536
|
+
]);
|
|
2537
|
+
}
|
|
2538
|
+
create(value?: PartialMessage<Call>): Call {
|
|
2539
|
+
const message = globalThis.Object.create(this.messagePrototype!);
|
|
2540
|
+
message.type = '';
|
|
2541
|
+
message.id = '';
|
|
2542
|
+
message.createdByUserId = '';
|
|
2543
|
+
message.hostUserId = '';
|
|
2544
|
+
if (value !== undefined) reflectionMergePartial<Call>(this, message, value);
|
|
2545
|
+
return message;
|
|
2546
|
+
}
|
|
2547
|
+
internalBinaryRead(
|
|
2548
|
+
reader: IBinaryReader,
|
|
2549
|
+
length: number,
|
|
2550
|
+
options: BinaryReadOptions,
|
|
2551
|
+
target?: Call,
|
|
2552
|
+
): Call {
|
|
2553
|
+
let message = target ?? this.create(),
|
|
2554
|
+
end = reader.pos + length;
|
|
2555
|
+
while (reader.pos < end) {
|
|
2556
|
+
let [fieldNo, wireType] = reader.tag();
|
|
2557
|
+
switch (fieldNo) {
|
|
2558
|
+
case /* string type */ 1:
|
|
2559
|
+
message.type = reader.string();
|
|
2560
|
+
break;
|
|
2561
|
+
case /* string id */ 2:
|
|
2562
|
+
message.id = reader.string();
|
|
2563
|
+
break;
|
|
2564
|
+
case /* string created_by_user_id */ 3:
|
|
2565
|
+
message.createdByUserId = reader.string();
|
|
2566
|
+
break;
|
|
2567
|
+
case /* string host_user_id */ 4:
|
|
2568
|
+
message.hostUserId = reader.string();
|
|
2569
|
+
break;
|
|
2570
|
+
case /* google.protobuf.Struct custom */ 5:
|
|
2571
|
+
message.custom = Struct.internalBinaryRead(
|
|
2572
|
+
reader,
|
|
2573
|
+
reader.uint32(),
|
|
2574
|
+
options,
|
|
2575
|
+
message.custom,
|
|
2576
|
+
);
|
|
2577
|
+
break;
|
|
2578
|
+
case /* google.protobuf.Timestamp created_at */ 6:
|
|
2579
|
+
message.createdAt = Timestamp.internalBinaryRead(
|
|
2580
|
+
reader,
|
|
2581
|
+
reader.uint32(),
|
|
2582
|
+
options,
|
|
2583
|
+
message.createdAt,
|
|
2584
|
+
);
|
|
2585
|
+
break;
|
|
2586
|
+
case /* google.protobuf.Timestamp updated_at */ 7:
|
|
2587
|
+
message.updatedAt = Timestamp.internalBinaryRead(
|
|
2588
|
+
reader,
|
|
2589
|
+
reader.uint32(),
|
|
2590
|
+
options,
|
|
2591
|
+
message.updatedAt,
|
|
2592
|
+
);
|
|
2593
|
+
break;
|
|
2594
|
+
default:
|
|
2595
|
+
let u = options.readUnknownField;
|
|
2596
|
+
if (u === 'throw')
|
|
2597
|
+
throw new globalThis.Error(
|
|
2598
|
+
`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`,
|
|
2599
|
+
);
|
|
2600
|
+
let d = reader.skip(wireType);
|
|
2601
|
+
if (u !== false)
|
|
2602
|
+
(u === true ? UnknownFieldHandler.onRead : u)(
|
|
2603
|
+
this.typeName,
|
|
2604
|
+
message,
|
|
2605
|
+
fieldNo,
|
|
2606
|
+
wireType,
|
|
2607
|
+
d,
|
|
2608
|
+
);
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
return message;
|
|
2612
|
+
}
|
|
2613
|
+
internalBinaryWrite(
|
|
2614
|
+
message: Call,
|
|
2615
|
+
writer: IBinaryWriter,
|
|
2616
|
+
options: BinaryWriteOptions,
|
|
2617
|
+
): IBinaryWriter {
|
|
2618
|
+
/* string type = 1; */
|
|
2619
|
+
if (message.type !== '')
|
|
2620
|
+
writer.tag(1, WireType.LengthDelimited).string(message.type);
|
|
2621
|
+
/* string id = 2; */
|
|
2622
|
+
if (message.id !== '')
|
|
2623
|
+
writer.tag(2, WireType.LengthDelimited).string(message.id);
|
|
2624
|
+
/* string created_by_user_id = 3; */
|
|
2625
|
+
if (message.createdByUserId !== '')
|
|
2626
|
+
writer.tag(3, WireType.LengthDelimited).string(message.createdByUserId);
|
|
2627
|
+
/* string host_user_id = 4; */
|
|
2628
|
+
if (message.hostUserId !== '')
|
|
2629
|
+
writer.tag(4, WireType.LengthDelimited).string(message.hostUserId);
|
|
2630
|
+
/* google.protobuf.Struct custom = 5; */
|
|
2631
|
+
if (message.custom)
|
|
2632
|
+
Struct.internalBinaryWrite(
|
|
2633
|
+
message.custom,
|
|
2634
|
+
writer.tag(5, WireType.LengthDelimited).fork(),
|
|
2635
|
+
options,
|
|
2636
|
+
).join();
|
|
2637
|
+
/* google.protobuf.Timestamp created_at = 6; */
|
|
2638
|
+
if (message.createdAt)
|
|
2639
|
+
Timestamp.internalBinaryWrite(
|
|
2640
|
+
message.createdAt,
|
|
2641
|
+
writer.tag(6, WireType.LengthDelimited).fork(),
|
|
2642
|
+
options,
|
|
2643
|
+
).join();
|
|
2644
|
+
/* google.protobuf.Timestamp updated_at = 7; */
|
|
2645
|
+
if (message.updatedAt)
|
|
2646
|
+
Timestamp.internalBinaryWrite(
|
|
2647
|
+
message.updatedAt,
|
|
2648
|
+
writer.tag(7, WireType.LengthDelimited).fork(),
|
|
2649
|
+
options,
|
|
2650
|
+
).join();
|
|
2651
|
+
let u = options.writeUnknownFields;
|
|
2652
|
+
if (u !== false)
|
|
2653
|
+
(u == true ? UnknownFieldHandler.onWrite : u)(
|
|
2654
|
+
this.typeName,
|
|
2655
|
+
message,
|
|
2656
|
+
writer,
|
|
2657
|
+
);
|
|
2658
|
+
return writer;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
/**
|
|
2662
|
+
* @generated MessageType for protobuf message stream.video.sfu.models.Call
|
|
2663
|
+
*/
|
|
2664
|
+
export const Call = new Call$Type();
|
|
2665
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
2659
2666
|
class CallGrants$Type extends MessageType<CallGrants> {
|
|
2660
2667
|
constructor() {
|
|
2661
2668
|
super('stream.video.sfu.models.CallGrants', [
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type PromiseWithResolvers<T> = {
|
|
2
|
+
promise: Promise<T>;
|
|
3
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
4
|
+
reject: (reason: any) => void;
|
|
5
|
+
isResolved: boolean;
|
|
6
|
+
isRejected: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new promise with resolvers.
|
|
11
|
+
*
|
|
12
|
+
* Based on:
|
|
13
|
+
* - https://github.com/tc39/proposal-promise-with-resolvers/blob/main/polyfills.js
|
|
14
|
+
*/
|
|
15
|
+
export const promiseWithResolvers = <T = void>(): PromiseWithResolvers<T> => {
|
|
16
|
+
let resolve: (value: T | PromiseLike<T>) => void;
|
|
17
|
+
let reject: (reason: any) => void;
|
|
18
|
+
const promise = new Promise<T>((_resolve, _reject) => {
|
|
19
|
+
resolve = _resolve;
|
|
20
|
+
reject = _reject;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
let isResolved = false;
|
|
24
|
+
let isRejected = false;
|
|
25
|
+
|
|
26
|
+
const resolver = (value: T | PromiseLike<T>) => {
|
|
27
|
+
isResolved = true;
|
|
28
|
+
resolve(value);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const rejecter = (reason: any) => {
|
|
32
|
+
isRejected = true;
|
|
33
|
+
reject(reason);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
promise,
|
|
38
|
+
resolve: resolver,
|
|
39
|
+
reject: rejecter,
|
|
40
|
+
isResolved,
|
|
41
|
+
isRejected,
|
|
42
|
+
};
|
|
43
|
+
};
|
package/src/logger.ts
CHANGED
|
@@ -57,9 +57,11 @@ export const setLogLevel = (l: LogLevel) => {
|
|
|
57
57
|
level = l;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
+
export const getLogLevel = (): LogLevel => level;
|
|
61
|
+
|
|
60
62
|
export const getLogger = (withTags?: string[]) => {
|
|
61
63
|
const loggerMethod = logger || logToConsole;
|
|
62
|
-
const tags = (withTags || []).join(':');
|
|
64
|
+
const tags = (withTags || []).filter(Boolean).join(':');
|
|
63
65
|
const result: Logger = (logLevel, message, ...args) => {
|
|
64
66
|
if (logLevels[logLevel] >= logLevels[level]) {
|
|
65
67
|
loggerMethod(logLevel, `[${tags}]: ${message}`, ...args);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { RpcError, UnaryCall } from '@protobuf-ts/runtime-rpc';
|
|
3
|
+
import { TwirpErrorCode } from '@protobuf-ts/twirp-transport';
|
|
4
|
+
import { retryable, SfuResponseWithError } from '../retryable';
|
|
5
|
+
|
|
6
|
+
interface TestResponseWithError extends SfuResponseWithError {
|
|
7
|
+
value: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe('retryable', () => {
|
|
11
|
+
it('retries the RPC when the SFU instructs to do so', async () => {
|
|
12
|
+
// @ts-expect-error incomplete unary call
|
|
13
|
+
const rpc = vi.fn<any[], UnaryCall<{}, TestResponseWithError>>(() => {
|
|
14
|
+
if (rpc.mock.calls.length <= 2) {
|
|
15
|
+
return { response: { error: { shouldRetry: true } } };
|
|
16
|
+
}
|
|
17
|
+
return { response: { value: 10 } };
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const result = await retryable(rpc);
|
|
21
|
+
expect(result).toBeDefined();
|
|
22
|
+
expect(result.response.value).toBe(10);
|
|
23
|
+
expect(rpc).toHaveBeenCalledTimes(3);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('retries when the RPC fails', async () => {
|
|
27
|
+
// @ts-expect-error incomplete unary call
|
|
28
|
+
const rpc = vi.fn<any[], UnaryCall<{}, TestResponseWithError>>(() => {
|
|
29
|
+
if (rpc.mock.calls.length === 1) throw new Error('failed');
|
|
30
|
+
return { response: { value: 10 } };
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const result = await retryable(rpc);
|
|
34
|
+
expect(result).toBeDefined();
|
|
35
|
+
expect(result.response.value).toBe(10);
|
|
36
|
+
expect(rpc).toHaveBeenCalledTimes(2);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('stops retrying when the RPC is rejected with cancellation error', async () => {
|
|
40
|
+
// @ts-expect-error incomplete unary call
|
|
41
|
+
const rpc = vi.fn<any[], UnaryCall<{}, TestResponseWithError>>(() => {
|
|
42
|
+
if (rpc.mock.calls.length <= 1) {
|
|
43
|
+
throw new Error('Generic error, should retry');
|
|
44
|
+
}
|
|
45
|
+
if (rpc.mock.calls.length === 2) {
|
|
46
|
+
throw new RpcError(
|
|
47
|
+
'Request aborted, should not retry',
|
|
48
|
+
TwirpErrorCode[TwirpErrorCode.cancelled],
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const result = retryable(rpc);
|
|
54
|
+
await expect(result).rejects.toThrow('Request aborted, should not retry');
|
|
55
|
+
expect(rpc).toHaveBeenCalledTimes(2);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('stops retrying when the aborted via signal', async () => {
|
|
59
|
+
const controller = new AbortController();
|
|
60
|
+
const rpc = vi.fn<any[], UnaryCall<{}, TestResponseWithError>>(() => {
|
|
61
|
+
if (rpc.mock.calls.length <= 1) {
|
|
62
|
+
throw new Error('Generic error, should retry');
|
|
63
|
+
}
|
|
64
|
+
controller.abort();
|
|
65
|
+
throw new Error('Request aborted, should not retry');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = retryable(rpc, controller.signal);
|
|
69
|
+
await expect(result).rejects.toThrow('Request aborted, should not retry');
|
|
70
|
+
expect(rpc).toHaveBeenCalledTimes(2);
|
|
71
|
+
});
|
|
72
|
+
});
|
package/src/rpc/createClient.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TwirpOptions,
|
|
11
11
|
} from '@protobuf-ts/twirp-transport';
|
|
12
12
|
import { SignalServerClient } from '../gen/video/sfu/signal_rpc/signal.client';
|
|
13
|
+
import { Logger, LogLevel } from '../coordinator/connection/types';
|
|
13
14
|
|
|
14
15
|
const defaultOptions: TwirpOptions = {
|
|
15
16
|
baseUrl: '',
|
|
@@ -36,6 +37,26 @@ export const withHeaders = (
|
|
|
36
37
|
};
|
|
37
38
|
};
|
|
38
39
|
|
|
40
|
+
export const withRequestLogger = (
|
|
41
|
+
logger: Logger,
|
|
42
|
+
level: LogLevel,
|
|
43
|
+
): RpcInterceptor => {
|
|
44
|
+
return {
|
|
45
|
+
interceptUnary: (
|
|
46
|
+
next: NextUnaryFn,
|
|
47
|
+
method: MethodInfo,
|
|
48
|
+
input: object,
|
|
49
|
+
options: RpcOptions,
|
|
50
|
+
): UnaryCall => {
|
|
51
|
+
logger(level, `Calling SFU RPC method ${method.name}`, {
|
|
52
|
+
input,
|
|
53
|
+
options,
|
|
54
|
+
});
|
|
55
|
+
return next(method, input, options);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
|
|
39
60
|
/**
|
|
40
61
|
* Creates new SignalServerClient instance.
|
|
41
62
|
*
|
package/src/rpc/index.ts
CHANGED