@stream-io/video-client 1.18.9 → 1.19.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.browser.es.js +2622 -2311
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +2622 -2310
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.es.js +2622 -2311
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/src/Call.d.ts +3 -0
  10. package/dist/src/StreamSfuClient.d.ts +9 -2
  11. package/dist/src/gen/coordinator/index.d.ts +266 -5
  12. package/dist/src/gen/google/protobuf/struct.d.ts +1 -3
  13. package/dist/src/gen/google/protobuf/timestamp.d.ts +1 -3
  14. package/dist/src/gen/video/sfu/event/events.d.ts +6 -0
  15. package/dist/src/gen/video/sfu/models/models.d.ts +46 -0
  16. package/dist/src/gen/video/sfu/signal_rpc/signal.d.ts +13 -1
  17. package/dist/src/rpc/createClient.d.ts +2 -0
  18. package/dist/src/rtc/BasePeerConnection.d.ts +10 -3
  19. package/dist/src/stats/index.d.ts +2 -0
  20. package/dist/src/stats/rtc/Tracer.d.ts +15 -0
  21. package/dist/src/stats/rtc/index.d.ts +2 -0
  22. package/dist/src/stats/rtc/mediaDevices.d.ts +2 -0
  23. package/dist/src/stats/rtc/pc.d.ts +2 -0
  24. package/dist/src/stats/rtc/types.d.ts +8 -0
  25. package/index.ts +4 -0
  26. package/package.json +1 -1
  27. package/src/Call.ts +54 -29
  28. package/src/StreamSfuClient.ts +22 -9
  29. package/src/gen/coordinator/index.ts +262 -5
  30. package/src/gen/google/protobuf/struct.ts +13 -8
  31. package/src/gen/google/protobuf/timestamp.ts +10 -8
  32. package/src/gen/video/sfu/event/events.ts +8 -1
  33. package/src/gen/video/sfu/models/models.ts +63 -1
  34. package/src/gen/video/sfu/signal_rpc/signal.client.ts +1 -1
  35. package/src/gen/video/sfu/signal_rpc/signal.ts +27 -1
  36. package/src/rpc/__tests__/createClient.test.ts +38 -0
  37. package/src/rpc/createClient.ts +30 -0
  38. package/src/rtc/BasePeerConnection.ts +22 -4
  39. package/src/rtc/Publisher.ts +3 -2
  40. package/src/rtc/Subscriber.ts +0 -2
  41. package/src/rtc/__tests__/Subscriber.test.ts +1 -0
  42. package/src/rtc/helpers/__tests__/rtcConfiguration.test.ts +1 -0
  43. package/src/rtc/helpers/rtcConfiguration.ts +1 -0
  44. package/src/stats/SfuStatsReporter.ts +36 -12
  45. package/src/stats/index.ts +2 -0
  46. package/src/stats/rtc/Tracer.ts +42 -0
  47. package/src/stats/rtc/index.ts +5 -0
  48. package/src/stats/rtc/mediaDevices.ts +42 -0
  49. package/src/stats/rtc/pc.ts +130 -0
  50. package/src/stats/rtc/types.ts +26 -0
  51. package/src/store/CallState.ts +10 -0
package/src/Call.ts CHANGED
@@ -115,7 +115,13 @@ import {
115
115
  TrackType,
116
116
  WebsocketReconnectStrategy,
117
117
  } from './gen/video/sfu/models/models';
118
- import { createStatsReporter, SfuStatsReporter, StatsReporter } from './stats';
118
+ import {
119
+ createStatsReporter,
120
+ getSdkSignature,
121
+ SfuStatsReporter,
122
+ StatsReporter,
123
+ } from './stats';
124
+ import { tracer as mediaStatsTracer } from './stats/rtc/mediaDevices';
119
125
  import { DynascaleManager } from './helpers/DynascaleManager';
120
126
  import { PermissionsContext } from './permissions';
121
127
  import { CallTypes } from './CallType';
@@ -137,7 +143,6 @@ import {
137
143
  ScreenShareManager,
138
144
  SpeakerManager,
139
145
  } from './devices';
140
- import { getSdkSignature } from './stats/utils';
141
146
  import { hasPending, withoutConcurrency } from './helpers/concurrency';
142
147
  import { ensureExhausted } from './helpers/ensureExhausted';
143
148
  import { pushToIfMissing } from './helpers/array';
@@ -236,6 +241,7 @@ export class Call {
236
241
  private readonly reconnectConcurrencyTag = Symbol('reconnectConcurrencyTag');
237
242
  private reconnectAttempts = 0;
238
243
  private reconnectStrategy = WebsocketReconnectStrategy.UNSPECIFIED;
244
+ private reconnectReason = '';
239
245
  private fastReconnectDeadlineSeconds: number = 0;
240
246
  private disconnectionTimeoutSeconds: number = 0;
241
247
  private lastOfflineTimestamp: number = 0;
@@ -898,14 +904,16 @@ export class Call {
898
904
  const sfuClient =
899
905
  performingRejoin || performingMigration || !isWsHealthy
900
906
  ? new StreamSfuClient({
901
- logTag: String(this.sfuClientTag++),
907
+ logTag: String(++this.sfuClientTag),
902
908
  dispatcher: this.dispatcher,
903
909
  credentials: this.credentials,
904
910
  streamClient: this.streamClient,
911
+ enableTracing: statsOptions.enable_rtc_stats,
905
912
  // a new session_id is necessary for the REJOIN strategy.
906
913
  // we use the previous session_id if available
907
914
  sessionId: performingRejoin ? undefined : previousSessionId,
908
- onSignalClose: () => this.handleSfuSignalClose(sfuClient),
915
+ onSignalClose: (reason) =>
916
+ this.handleSfuSignalClose(sfuClient, reason),
909
917
  })
910
918
  : previousSfuClient;
911
919
  this.sfuClient = sfuClient;
@@ -1024,6 +1032,7 @@ export class Call {
1024
1032
  delete this.joinCallData?.notify;
1025
1033
  // reset the reconnect strategy to unspecified after a successful reconnection
1026
1034
  this.reconnectStrategy = WebsocketReconnectStrategy.UNSPECIFIED;
1035
+ this.reconnectReason = '';
1027
1036
 
1028
1037
  this.logger('info', `Joined call ${this.cid}`);
1029
1038
  };
@@ -1047,6 +1056,7 @@ export class Call {
1047
1056
  reconnectAttempt: this.reconnectAttempts,
1048
1057
  fromSfuId: migratingFromSfuId || '',
1049
1058
  previousSessionId: performingRejoin ? previousSessionId || '' : '',
1059
+ reason: this.reconnectReason,
1050
1060
  };
1051
1061
  };
1052
1062
 
@@ -1155,6 +1165,7 @@ export class Call {
1155
1165
  publishOptions,
1156
1166
  closePreviousInstances,
1157
1167
  } = opts;
1168
+ const { enable_rtc_stats: enableTracing } = statsOptions;
1158
1169
  if (closePreviousInstances && this.subscriber) {
1159
1170
  this.subscriber.dispose();
1160
1171
  }
@@ -1164,14 +1175,17 @@ export class Call {
1164
1175
  state: this.state,
1165
1176
  connectionConfig,
1166
1177
  logTag: String(this.sfuClientTag),
1167
- onUnrecoverableError: () => {
1168
- this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
1169
- this.logger(
1170
- 'warn',
1171
- '[Reconnect] Error reconnecting after a subscriber error',
1172
- err,
1173
- );
1174
- });
1178
+ enableTracing,
1179
+ onUnrecoverableError: (reason) => {
1180
+ this.reconnect(WebsocketReconnectStrategy.REJOIN, reason).catch(
1181
+ (err) => {
1182
+ this.logger(
1183
+ 'warn',
1184
+ `[Reconnect] Error reconnecting after a subscriber error: ${reason}`,
1185
+ err,
1186
+ );
1187
+ },
1188
+ );
1175
1189
  },
1176
1190
  });
1177
1191
 
@@ -1189,18 +1203,22 @@ export class Call {
1189
1203
  connectionConfig,
1190
1204
  publishOptions,
1191
1205
  logTag: String(this.sfuClientTag),
1192
- onUnrecoverableError: () => {
1193
- this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
1194
- this.logger(
1195
- 'warn',
1196
- '[Reconnect] Error reconnecting after a publisher error',
1197
- err,
1198
- );
1199
- });
1206
+ enableTracing,
1207
+ onUnrecoverableError: (reason) => {
1208
+ this.reconnect(WebsocketReconnectStrategy.REJOIN, reason).catch(
1209
+ (err) => {
1210
+ this.logger(
1211
+ 'warn',
1212
+ `[Reconnect] Error reconnecting after a publisher error: ${reason}`,
1213
+ err,
1214
+ );
1215
+ },
1216
+ );
1200
1217
  },
1201
1218
  });
1202
1219
  }
1203
1220
 
1221
+ mediaStatsTracer.setEnabled(enableTracing);
1204
1222
  this.statsReporter?.stop();
1205
1223
  this.statsReporter = createStatsReporter({
1206
1224
  subscriber: this.subscriber,
@@ -1267,8 +1285,12 @@ export class Call {
1267
1285
  *
1268
1286
  * @internal
1269
1287
  * @param sfuClient the SFU client instance that was closed.
1288
+ * @param reason the reason for the closure.
1270
1289
  */
1271
- private handleSfuSignalClose = (sfuClient: StreamSfuClient) => {
1290
+ private handleSfuSignalClose = (
1291
+ sfuClient: StreamSfuClient,
1292
+ reason: string,
1293
+ ) => {
1272
1294
  this.logger('debug', '[Reconnect] SFU signal connection closed');
1273
1295
  const { callingState } = this.state;
1274
1296
  if (
@@ -1286,7 +1308,7 @@ export class Call {
1286
1308
  return;
1287
1309
  // normal close, no need to reconnect
1288
1310
  if (sfuClient.isLeaving) return;
1289
- this.reconnect(WebsocketReconnectStrategy.REJOIN).catch((err) => {
1311
+ this.reconnect(WebsocketReconnectStrategy.REJOIN, reason).catch((err) => {
1290
1312
  this.logger('warn', '[Reconnect] Error reconnecting', err);
1291
1313
  });
1292
1314
  };
@@ -1297,9 +1319,11 @@ export class Call {
1297
1319
  * @internal
1298
1320
  *
1299
1321
  * @param strategy the reconnection strategy to use.
1322
+ * @param reason the reason for the reconnection.
1300
1323
  */
1301
1324
  private reconnect = async (
1302
1325
  strategy: WebsocketReconnectStrategy,
1326
+ reason: string,
1303
1327
  ): Promise<void> => {
1304
1328
  if (
1305
1329
  this.state.callingState === CallingState.RECONNECTING ||
@@ -1315,6 +1339,7 @@ export class Call {
1315
1339
 
1316
1340
  const reconnectStartTime = Date.now();
1317
1341
  this.reconnectStrategy = strategy;
1342
+ this.reconnectReason = reason;
1318
1343
 
1319
1344
  do {
1320
1345
  if (
@@ -1475,7 +1500,7 @@ export class Call {
1475
1500
  currentPublisher?.dispose();
1476
1501
 
1477
1502
  // and close the previous SFU client, without specifying close code
1478
- currentSfuClient.close();
1503
+ currentSfuClient.close(StreamSfuClient.NORMAL_CLOSURE, 'Migrating away');
1479
1504
  }
1480
1505
  this.sfuStatsReporter?.sendReconnectionTime(
1481
1506
  WebsocketReconnectStrategy.MIGRATE,
@@ -1491,21 +1516,21 @@ export class Call {
1491
1516
  private registerReconnectHandlers = () => {
1492
1517
  // handles the legacy "goAway" event
1493
1518
  const unregisterGoAway = this.on('goAway', () => {
1494
- this.reconnect(WebsocketReconnectStrategy.MIGRATE).catch((err) => {
1495
- this.logger('warn', '[Reconnect] Error reconnecting', err);
1496
- });
1519
+ this.reconnect(WebsocketReconnectStrategy.MIGRATE, 'goAway').catch(
1520
+ (err) => this.logger('warn', '[Reconnect] Error reconnecting', err),
1521
+ );
1497
1522
  });
1498
1523
 
1499
1524
  // handles the "error" event, through which the SFU can request a reconnect
1500
1525
  const unregisterOnError = this.on('error', (e) => {
1501
- const { reconnectStrategy: strategy } = e;
1526
+ const { reconnectStrategy: strategy, error } = e;
1502
1527
  if (strategy === WebsocketReconnectStrategy.UNSPECIFIED) return;
1503
1528
  if (strategy === WebsocketReconnectStrategy.DISCONNECT) {
1504
1529
  this.leave({ reason: 'SFU instructed to disconnect' }).catch((err) => {
1505
1530
  this.logger('warn', `Can't leave call after disconnect request`, err);
1506
1531
  });
1507
1532
  } else {
1508
- this.reconnect(strategy).catch((err) => {
1533
+ this.reconnect(strategy, error?.message || 'SFU Error').catch((err) => {
1509
1534
  this.logger('warn', '[Reconnect] Error reconnecting', err);
1510
1535
  });
1511
1536
  }
@@ -1531,7 +1556,7 @@ export class Call {
1531
1556
  }
1532
1557
  }
1533
1558
 
1534
- this.reconnect(strategy).catch((err) => {
1559
+ this.reconnect(strategy, 'Going online').catch((err) => {
1535
1560
  this.logger(
1536
1561
  'warn',
1537
1562
  '[Reconnect] Error reconnecting after going online',
@@ -4,6 +4,7 @@ import {
4
4
  retryable,
5
5
  withHeaders,
6
6
  withRequestLogger,
7
+ withRequestTracer,
7
8
  } from './rpc';
8
9
  import {
9
10
  createWebSocketSignalChannel,
@@ -36,6 +37,7 @@ import {
36
37
  SafePromise,
37
38
  } from './helpers/promise';
38
39
  import { getTimers } from './timers';
40
+ import { Tracer, TraceSlice } from './stats';
39
41
 
40
42
  export type StreamSfuClientConstructor = {
41
43
  /**
@@ -67,12 +69,17 @@ export type StreamSfuClientConstructor = {
67
69
  /**
68
70
  * Callback for when the WebSocket connection is closed.
69
71
  */
70
- onSignalClose?: () => void;
72
+ onSignalClose?: (reason: string) => void;
71
73
 
72
74
  /**
73
75
  * The StreamClient instance to use for the connection.
74
76
  */
75
77
  streamClient: StreamClient;
78
+
79
+ /**
80
+ * Flag to enable tracing.
81
+ */
82
+ enableTracing: boolean;
76
83
  };
77
84
 
78
85
  /**
@@ -118,9 +125,10 @@ export class StreamSfuClient {
118
125
  private pingIntervalInMs = 10 * 1000;
119
126
  private unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
120
127
  private lastMessageTimestamp?: Date;
128
+ private readonly tracer?: Tracer;
121
129
  private readonly unsubscribeIceTrickle: () => void;
122
130
  private readonly unsubscribeNetworkChanged: () => void;
123
- private readonly onSignalClose: (() => void) | undefined;
131
+ private readonly onSignalClose: ((reason: string) => void) | undefined;
124
132
  private readonly logger: Logger;
125
133
  private readonly logTag: string;
126
134
  private readonly credentials: Credentials;
@@ -173,6 +181,7 @@ export class StreamSfuClient {
173
181
  joinResponseTimeout = 5000,
174
182
  onSignalClose,
175
183
  streamClient,
184
+ enableTracing,
176
185
  }: StreamSfuClientConstructor) {
177
186
  this.dispatcher = dispatcher;
178
187
  this.sessionId = sessionId || generateUUIDv4();
@@ -183,12 +192,12 @@ export class StreamSfuClient {
183
192
  this.joinResponseTimeout = joinResponseTimeout;
184
193
  this.logTag = logTag;
185
194
  this.logger = getLogger(['SfuClient', logTag]);
195
+ this.tracer = enableTracing ? new Tracer(logTag) : undefined;
186
196
  this.rpc = createSignalClient({
187
197
  baseUrl: server.url,
188
198
  interceptors: [
189
- withHeaders({
190
- Authorization: `Bearer ${token}`,
191
- }),
199
+ withHeaders({ Authorization: `Bearer ${token}` }),
200
+ this.tracer && withRequestTracer(this.tracer.trace),
192
201
  getLogLevel() === 'trace' && withRequestLogger(this.logger, 'trace'),
193
202
  ].filter((v) => !!v),
194
203
  });
@@ -237,8 +246,8 @@ export class StreamSfuClient {
237
246
 
238
247
  this.signalWs.addEventListener('open', onOpen);
239
248
 
240
- this.signalWs.addEventListener('close', () => {
241
- this.handleWebSocketClose();
249
+ this.signalWs.addEventListener('close', (e) => {
250
+ this.handleWebSocketClose(e);
242
251
  // Normally, this shouldn't have any effect, because WS should never emit 'close'
243
252
  // before emitting 'open'. However, strager things have happened, and we don't
244
253
  // want to leave signalReady in pending state.
@@ -271,11 +280,11 @@ export class StreamSfuClient {
271
280
  return this.joinResponseTask.promise;
272
281
  }
273
282
 
274
- private handleWebSocketClose = () => {
283
+ private handleWebSocketClose = (e: CloseEvent) => {
275
284
  this.signalWs.removeEventListener('close', this.handleWebSocketClose);
276
285
  getTimers().clearInterval(this.keepAliveInterval);
277
286
  clearTimeout(this.connectionCheckTimeout);
278
- this.onSignalClose?.();
287
+ this.onSignalClose?.(`${e.code} ${e.reason}`);
279
288
  };
280
289
 
281
290
  close = (code: number = StreamSfuClient.NORMAL_CLOSURE, reason?: string) => {
@@ -299,6 +308,10 @@ export class StreamSfuClient {
299
308
  this.iceTrickleBuffer.dispose();
300
309
  };
301
310
 
311
+ getTrace = (): TraceSlice | undefined => {
312
+ return this.tracer?.take();
313
+ };
314
+
302
315
  leaveAndClose = async (reason: string) => {
303
316
  await this.joinTask;
304
317
  try {
@@ -726,6 +726,178 @@ export interface CallEvent {
726
726
  */
727
727
  type: string;
728
728
  }
729
+ /**
730
+ * This event is sent when frame recording has failed
731
+ * @export
732
+ * @interface CallFrameRecordingFailedEvent
733
+ */
734
+ export interface CallFrameRecordingFailedEvent {
735
+ /**
736
+ *
737
+ * @type {CallResponse}
738
+ * @memberof CallFrameRecordingFailedEvent
739
+ */
740
+ call: CallResponse;
741
+ /**
742
+ *
743
+ * @type {string}
744
+ * @memberof CallFrameRecordingFailedEvent
745
+ */
746
+ call_cid: string;
747
+ /**
748
+ *
749
+ * @type {string}
750
+ * @memberof CallFrameRecordingFailedEvent
751
+ */
752
+ created_at: string;
753
+ /**
754
+ *
755
+ * @type {string}
756
+ * @memberof CallFrameRecordingFailedEvent
757
+ */
758
+ egress_id: string;
759
+ /**
760
+ * The type of event: "call.frame_recording_failed" in this case
761
+ * @type {string}
762
+ * @memberof CallFrameRecordingFailedEvent
763
+ */
764
+ type: string;
765
+ }
766
+ /**
767
+ * This event is sent when a frame is captured from a call
768
+ * @export
769
+ * @interface CallFrameRecordingFrameReadyEvent
770
+ */
771
+ export interface CallFrameRecordingFrameReadyEvent {
772
+ /**
773
+ *
774
+ * @type {string}
775
+ * @memberof CallFrameRecordingFrameReadyEvent
776
+ */
777
+ call_cid: string;
778
+ /**
779
+ * The time the frame was captured
780
+ * @type {string}
781
+ * @memberof CallFrameRecordingFrameReadyEvent
782
+ */
783
+ captured_at: string;
784
+ /**
785
+ *
786
+ * @type {string}
787
+ * @memberof CallFrameRecordingFrameReadyEvent
788
+ */
789
+ created_at: string;
790
+ /**
791
+ *
792
+ * @type {string}
793
+ * @memberof CallFrameRecordingFrameReadyEvent
794
+ */
795
+ egress_id: string;
796
+ /**
797
+ * Call session ID
798
+ * @type {string}
799
+ * @memberof CallFrameRecordingFrameReadyEvent
800
+ */
801
+ session_id: string;
802
+ /**
803
+ * The type of the track frame was captured from (TRACK_TYPE_VIDEO|TRACK_TYPE_SCREEN_SHARE)
804
+ * @type {string}
805
+ * @memberof CallFrameRecordingFrameReadyEvent
806
+ */
807
+ track_type: string;
808
+ /**
809
+ * The type of event: "call.frame_recording_ready" in this case
810
+ * @type {string}
811
+ * @memberof CallFrameRecordingFrameReadyEvent
812
+ */
813
+ type: string;
814
+ /**
815
+ * The URL of the frame
816
+ * @type {string}
817
+ * @memberof CallFrameRecordingFrameReadyEvent
818
+ */
819
+ url: string;
820
+ /**
821
+ * The users in the frame
822
+ * @type {{ [key: string]: UserResponse; }}
823
+ * @memberof CallFrameRecordingFrameReadyEvent
824
+ */
825
+ users: { [key: string]: UserResponse };
826
+ }
827
+ /**
828
+ * This event is sent when frame recording has started
829
+ * @export
830
+ * @interface CallFrameRecordingStartedEvent
831
+ */
832
+ export interface CallFrameRecordingStartedEvent {
833
+ /**
834
+ *
835
+ * @type {CallResponse}
836
+ * @memberof CallFrameRecordingStartedEvent
837
+ */
838
+ call: CallResponse;
839
+ /**
840
+ *
841
+ * @type {string}
842
+ * @memberof CallFrameRecordingStartedEvent
843
+ */
844
+ call_cid: string;
845
+ /**
846
+ *
847
+ * @type {string}
848
+ * @memberof CallFrameRecordingStartedEvent
849
+ */
850
+ created_at: string;
851
+ /**
852
+ *
853
+ * @type {string}
854
+ * @memberof CallFrameRecordingStartedEvent
855
+ */
856
+ egress_id: string;
857
+ /**
858
+ * The type of event: "call.frame_recording_started" in this case
859
+ * @type {string}
860
+ * @memberof CallFrameRecordingStartedEvent
861
+ */
862
+ type: string;
863
+ }
864
+ /**
865
+ * This event is sent when frame recording has stopped
866
+ * @export
867
+ * @interface CallFrameRecordingStoppedEvent
868
+ */
869
+ export interface CallFrameRecordingStoppedEvent {
870
+ /**
871
+ *
872
+ * @type {CallResponse}
873
+ * @memberof CallFrameRecordingStoppedEvent
874
+ */
875
+ call: CallResponse;
876
+ /**
877
+ *
878
+ * @type {string}
879
+ * @memberof CallFrameRecordingStoppedEvent
880
+ */
881
+ call_cid: string;
882
+ /**
883
+ *
884
+ * @type {string}
885
+ * @memberof CallFrameRecordingStoppedEvent
886
+ */
887
+ created_at: string;
888
+ /**
889
+ *
890
+ * @type {string}
891
+ * @memberof CallFrameRecordingStoppedEvent
892
+ */
893
+ egress_id: string;
894
+ /**
895
+ * The type of event: "call.frame_recording_stopped" in this case
896
+ * @type {string}
897
+ * @memberof CallFrameRecordingStoppedEvent
898
+ */
899
+ type: string;
900
+ }
729
901
  /**
730
902
  * This event is sent when HLS broadcasting has failed
731
903
  * @export
@@ -1221,6 +1393,12 @@ export interface CallRecording {
1221
1393
  * @memberof CallRecording
1222
1394
  */
1223
1395
  filename: string;
1396
+ /**
1397
+ *
1398
+ * @type {string}
1399
+ * @memberof CallRecording
1400
+ */
1401
+ session_id: string;
1224
1402
  /**
1225
1403
  *
1226
1404
  * @type {string}
@@ -1389,7 +1567,7 @@ export interface CallRejectedEvent {
1389
1567
  */
1390
1568
  created_at: string;
1391
1569
  /**
1392
- *
1570
+ * Provides information about why the call was rejected. You can provide any value, but the Stream API and SDKs use these default values: rejected, cancel, timeout and busy
1393
1571
  * @type {string}
1394
1572
  * @memberof CallRejectedEvent
1395
1573
  */
@@ -3286,6 +3464,12 @@ export interface EgressResponse {
3286
3464
  * @memberof EgressResponse
3287
3465
  */
3288
3466
  broadcasting: boolean;
3467
+ /**
3468
+ *
3469
+ * @type {FrameRecordingResponse}
3470
+ * @memberof EgressResponse
3471
+ */
3472
+ frame_recording?: FrameRecordingResponse;
3289
3473
  /**
3290
3474
  *
3291
3475
  * @type {EgressHLSResponse}
@@ -3312,6 +3496,38 @@ export interface EndCallResponse {
3312
3496
  */
3313
3497
  duration: string;
3314
3498
  }
3499
+ /**
3500
+ *
3501
+ * @export
3502
+ * @interface FPSStats
3503
+ */
3504
+ export interface FPSStats {
3505
+ /**
3506
+ *
3507
+ * @type {number}
3508
+ * @memberof FPSStats
3509
+ */
3510
+ average_fps: number;
3511
+ /**
3512
+ *
3513
+ * @type {number}
3514
+ * @memberof FPSStats
3515
+ */
3516
+ tracked: number;
3517
+ }
3518
+ /**
3519
+ *
3520
+ * @export
3521
+ * @interface FrameRecordingResponse
3522
+ */
3523
+ export interface FrameRecordingResponse {
3524
+ /**
3525
+ *
3526
+ * @type {string}
3527
+ * @memberof FrameRecordingResponse
3528
+ */
3529
+ status: string;
3530
+ }
3315
3531
  /**
3316
3532
  *
3317
3533
  * @export
@@ -3335,7 +3551,7 @@ export interface FrameRecordingSettingsRequest {
3335
3551
  * @type {string}
3336
3552
  * @memberof FrameRecordingSettingsRequest
3337
3553
  */
3338
- quality?: string;
3554
+ quality?: FrameRecordingSettingsRequestQualityEnum;
3339
3555
  }
3340
3556
 
3341
3557
  /**
@@ -3349,6 +3565,19 @@ export const FrameRecordingSettingsRequestModeEnum = {
3349
3565
  export type FrameRecordingSettingsRequestModeEnum =
3350
3566
  (typeof FrameRecordingSettingsRequestModeEnum)[keyof typeof FrameRecordingSettingsRequestModeEnum];
3351
3567
 
3568
+ /**
3569
+ * @export
3570
+ */
3571
+ export const FrameRecordingSettingsRequestQualityEnum = {
3572
+ _360P: '360p',
3573
+ _480P: '480p',
3574
+ _720P: '720p',
3575
+ _1080P: '1080p',
3576
+ _1440P: '1440p',
3577
+ } as const;
3578
+ export type FrameRecordingSettingsRequestQualityEnum =
3579
+ (typeof FrameRecordingSettingsRequestQualityEnum)[keyof typeof FrameRecordingSettingsRequestQualityEnum];
3580
+
3352
3581
  /**
3353
3582
  *
3354
3583
  * @export
@@ -3558,6 +3787,12 @@ export interface GetCallStatsResponse {
3558
3787
  * @memberof GetCallStatsResponse
3559
3788
  */
3560
3789
  duration: string;
3790
+ /**
3791
+ *
3792
+ * @type {boolean}
3793
+ * @memberof GetCallStatsResponse
3794
+ */
3795
+ is_truncated_report: boolean;
3561
3796
  /**
3562
3797
  *
3563
3798
  * @type {TimeStats}
@@ -5381,19 +5616,19 @@ export interface Response {
5381
5616
  */
5382
5617
  export interface RingSettingsRequest {
5383
5618
  /**
5384
- *
5619
+ * When none of the callees accept a ring call in this time a rejection will be sent by the caller with reason 'timeout' by the SDKs
5385
5620
  * @type {number}
5386
5621
  * @memberof RingSettingsRequest
5387
5622
  */
5388
5623
  auto_cancel_timeout_ms: number;
5389
5624
  /**
5390
- *
5625
+ * When a callee is online but doesn't answer a ring call in this time a rejection will be sent with reason 'timeout' by the SDKs
5391
5626
  * @type {number}
5392
5627
  * @memberof RingSettingsRequest
5393
5628
  */
5394
5629
  incoming_call_timeout_ms: number;
5395
5630
  /**
5396
- *
5631
+ * When a callee doesn't accept or reject a ring call in this time a missed call event will be sent
5397
5632
  * @type {number}
5398
5633
  * @memberof RingSettingsRequest
5399
5634
  */
@@ -5850,6 +6085,12 @@ export interface StartTranscriptionResponse {
5850
6085
  * @interface StatsOptions
5851
6086
  */
5852
6087
  export interface StatsOptions {
6088
+ /**
6089
+ *
6090
+ * @type {boolean}
6091
+ * @memberof StatsOptions
6092
+ */
6093
+ enable_rtc_stats: boolean;
5853
6094
  /**
5854
6095
  *
5855
6096
  * @type {number}
@@ -6972,6 +7213,12 @@ export interface UserSessionStats {
6972
7213
  * @memberof UserSessionStats
6973
7214
  */
6974
7215
  distance_to_sfu_kilometers?: number;
7216
+ /**
7217
+ *
7218
+ * @type {FPSStats}
7219
+ * @memberof UserSessionStats
7220
+ */
7221
+ fps?: FPSStats;
6975
7222
  /**
6976
7223
  *
6977
7224
  * @type {number}
@@ -7245,6 +7492,12 @@ export interface UserSessionStats {
7245
7492
  * @interface UserStats
7246
7493
  */
7247
7494
  export interface UserStats {
7495
+ /**
7496
+ *
7497
+ * @type {string}
7498
+ * @memberof UserStats
7499
+ */
7500
+ feedback?: string;
7248
7501
  /**
7249
7502
  *
7250
7503
  * @type {UserInfoResponse}
@@ -7341,6 +7594,10 @@ export type VideoEvent =
7341
7594
  | ({ type: 'call.created' } & CallCreatedEvent)
7342
7595
  | ({ type: 'call.deleted' } & CallDeletedEvent)
7343
7596
  | ({ type: 'call.ended' } & CallEndedEvent)
7597
+ | ({ type: 'call.frame_recording_failed' } & CallFrameRecordingFailedEvent)
7598
+ | ({ type: 'call.frame_recording_ready' } & CallFrameRecordingFrameReadyEvent)
7599
+ | ({ type: 'call.frame_recording_started' } & CallFrameRecordingStartedEvent)
7600
+ | ({ type: 'call.frame_recording_stopped' } & CallFrameRecordingStoppedEvent)
7344
7601
  | ({ type: 'call.hls_broadcasting_failed' } & CallHLSBroadcastingFailedEvent)
7345
7602
  | ({
7346
7603
  type: 'call.hls_broadcasting_started';