@stream-io/video-client 0.6.1 → 0.6.3

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 (36) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.browser.es.js +289 -25
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +290 -24
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +289 -25
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +10 -1
  9. package/dist/src/StreamSfuClient.d.ts +2 -1
  10. package/dist/src/client-details.d.ts +10 -1
  11. package/dist/src/gen/coordinator/index.d.ts +307 -0
  12. package/dist/src/gen/video/sfu/signal_rpc/signal.client.d.ts +9 -1
  13. package/dist/src/gen/video/sfu/signal_rpc/signal.d.ts +58 -0
  14. package/dist/src/rtc/flows/join.d.ts +1 -0
  15. package/dist/src/stats/SfuStatsReporter.d.ts +25 -0
  16. package/dist/src/stats/index.d.ts +3 -0
  17. package/dist/src/stats/utils.d.ts +6 -0
  18. package/dist/src/store/CallState.d.ts +1 -1
  19. package/package.json +1 -1
  20. package/src/Call.ts +39 -9
  21. package/src/StreamSfuClient.ts +12 -0
  22. package/src/client-details.ts +21 -2
  23. package/src/coordinator/connection/location.ts +2 -2
  24. package/src/gen/coordinator/index.ts +303 -0
  25. package/src/gen/video/sfu/signal_rpc/signal.client.ts +26 -0
  26. package/src/gen/video/sfu/signal_rpc/signal.ts +250 -0
  27. package/src/helpers/RNSpeechDetector.ts +1 -1
  28. package/src/rtc/Publisher.ts +2 -1
  29. package/src/rtc/Subscriber.ts +2 -1
  30. package/src/rtc/flows/join.ts +4 -2
  31. package/src/stats/SfuStatsReporter.ts +88 -0
  32. package/src/stats/index.ts +3 -0
  33. package/src/stats/{state-store-stats-reporter.ts → stateStoreStatsReporter.ts} +1 -13
  34. package/src/stats/utils.ts +12 -0
  35. package/src/store/CallState.ts +1 -1
  36. /package/dist/src/stats/{state-store-stats-reporter.d.ts → stateStoreStatsReporter.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ### [0.6.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.6.2...@stream-io/video-client-0.6.3) (2024-03-25)
6
+
7
+
8
+ ### Features
9
+
10
+ * SFU stats reporting ([#1297](https://github.com/GetStream/stream-video-js/issues/1297)) ([f46e927](https://github.com/GetStream/stream-video-js/commit/f46e927cbd650bc9af64a01cd5ebcec6cf2cfda8)), closes [#1276](https://github.com/GetStream/stream-video-js/issues/1276)
11
+
12
+ ### [0.6.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.6.1...@stream-io/video-client-0.6.2) (2024-03-25)
13
+
14
+
15
+ ### Features
16
+
17
+ * **call:** Add getCallStats method ([#1296](https://github.com/GetStream/stream-video-js/issues/1296)) ([b64a19e](https://github.com/GetStream/stream-video-js/commit/b64a19ecd2fcc74f5f531397ed34732d55b0f815))
18
+
5
19
  ### [0.6.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.6.0...@stream-io/video-client-0.6.1) (2024-03-13)
6
20
 
7
21
 
@@ -2446,6 +2446,159 @@ var models = /*#__PURE__*/Object.freeze({
2446
2446
  // @generated from protobuf file "video/sfu/signal_rpc/signal.proto" (package "stream.video.sfu.signal", syntax proto3)
2447
2447
  // tslint:disable
2448
2448
  // @generated message type with reflection information, may provide speed optimized methods
2449
+ class SendStatsRequest$Type extends MessageType {
2450
+ constructor() {
2451
+ super('stream.video.sfu.signal.SendStatsRequest', [
2452
+ { no: 1, name: 'session_id', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
2453
+ {
2454
+ no: 2,
2455
+ name: 'subscriber_stats',
2456
+ kind: 'scalar',
2457
+ T: 9 /*ScalarType.STRING*/,
2458
+ },
2459
+ {
2460
+ no: 3,
2461
+ name: 'publisher_stats',
2462
+ kind: 'scalar',
2463
+ T: 9 /*ScalarType.STRING*/,
2464
+ },
2465
+ {
2466
+ no: 4,
2467
+ name: 'webrtc_version',
2468
+ kind: 'scalar',
2469
+ T: 9 /*ScalarType.STRING*/,
2470
+ },
2471
+ { no: 5, name: 'sdk', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
2472
+ {
2473
+ no: 6,
2474
+ name: 'sdk_version',
2475
+ kind: 'scalar',
2476
+ T: 9 /*ScalarType.STRING*/,
2477
+ },
2478
+ ]);
2479
+ }
2480
+ create(value) {
2481
+ const message = globalThis.Object.create(this.messagePrototype);
2482
+ message.sessionId = '';
2483
+ message.subscriberStats = '';
2484
+ message.publisherStats = '';
2485
+ message.webrtcVersion = '';
2486
+ message.sdk = '';
2487
+ message.sdkVersion = '';
2488
+ if (value !== undefined)
2489
+ reflectionMergePartial(this, message, value);
2490
+ return message;
2491
+ }
2492
+ internalBinaryRead(reader, length, options, target) {
2493
+ let message = target ?? this.create(), end = reader.pos + length;
2494
+ while (reader.pos < end) {
2495
+ let [fieldNo, wireType] = reader.tag();
2496
+ switch (fieldNo) {
2497
+ case /* string session_id */ 1:
2498
+ message.sessionId = reader.string();
2499
+ break;
2500
+ case /* string subscriber_stats */ 2:
2501
+ message.subscriberStats = reader.string();
2502
+ break;
2503
+ case /* string publisher_stats */ 3:
2504
+ message.publisherStats = reader.string();
2505
+ break;
2506
+ case /* string webrtc_version */ 4:
2507
+ message.webrtcVersion = reader.string();
2508
+ break;
2509
+ case /* string sdk */ 5:
2510
+ message.sdk = reader.string();
2511
+ break;
2512
+ case /* string sdk_version */ 6:
2513
+ message.sdkVersion = reader.string();
2514
+ break;
2515
+ default:
2516
+ let u = options.readUnknownField;
2517
+ if (u === 'throw')
2518
+ throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
2519
+ let d = reader.skip(wireType);
2520
+ if (u !== false)
2521
+ (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
2522
+ }
2523
+ }
2524
+ return message;
2525
+ }
2526
+ internalBinaryWrite(message, writer, options) {
2527
+ /* string session_id = 1; */
2528
+ if (message.sessionId !== '')
2529
+ writer.tag(1, WireType.LengthDelimited).string(message.sessionId);
2530
+ /* string subscriber_stats = 2; */
2531
+ if (message.subscriberStats !== '')
2532
+ writer.tag(2, WireType.LengthDelimited).string(message.subscriberStats);
2533
+ /* string publisher_stats = 3; */
2534
+ if (message.publisherStats !== '')
2535
+ writer.tag(3, WireType.LengthDelimited).string(message.publisherStats);
2536
+ /* string webrtc_version = 4; */
2537
+ if (message.webrtcVersion !== '')
2538
+ writer.tag(4, WireType.LengthDelimited).string(message.webrtcVersion);
2539
+ /* string sdk = 5; */
2540
+ if (message.sdk !== '')
2541
+ writer.tag(5, WireType.LengthDelimited).string(message.sdk);
2542
+ /* string sdk_version = 6; */
2543
+ if (message.sdkVersion !== '')
2544
+ writer.tag(6, WireType.LengthDelimited).string(message.sdkVersion);
2545
+ let u = options.writeUnknownFields;
2546
+ if (u !== false)
2547
+ (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
2548
+ return writer;
2549
+ }
2550
+ }
2551
+ /**
2552
+ * @generated MessageType for protobuf message stream.video.sfu.signal.SendStatsRequest
2553
+ */
2554
+ const SendStatsRequest = new SendStatsRequest$Type();
2555
+ // @generated message type with reflection information, may provide speed optimized methods
2556
+ class SendStatsResponse$Type extends MessageType {
2557
+ constructor() {
2558
+ super('stream.video.sfu.signal.SendStatsResponse', [
2559
+ { no: 1, name: 'error', kind: 'message', T: () => Error$2 },
2560
+ ]);
2561
+ }
2562
+ create(value) {
2563
+ const message = globalThis.Object.create(this.messagePrototype);
2564
+ if (value !== undefined)
2565
+ reflectionMergePartial(this, message, value);
2566
+ return message;
2567
+ }
2568
+ internalBinaryRead(reader, length, options, target) {
2569
+ let message = target ?? this.create(), end = reader.pos + length;
2570
+ while (reader.pos < end) {
2571
+ let [fieldNo, wireType] = reader.tag();
2572
+ switch (fieldNo) {
2573
+ case /* stream.video.sfu.models.Error error */ 1:
2574
+ message.error = Error$2.internalBinaryRead(reader, reader.uint32(), options, message.error);
2575
+ break;
2576
+ default:
2577
+ let u = options.readUnknownField;
2578
+ if (u === 'throw')
2579
+ throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
2580
+ let d = reader.skip(wireType);
2581
+ if (u !== false)
2582
+ (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
2583
+ }
2584
+ }
2585
+ return message;
2586
+ }
2587
+ internalBinaryWrite(message, writer, options) {
2588
+ /* stream.video.sfu.models.Error error = 1; */
2589
+ if (message.error)
2590
+ Error$2.internalBinaryWrite(message.error, writer.tag(1, WireType.LengthDelimited).fork(), options).join();
2591
+ let u = options.writeUnknownFields;
2592
+ if (u !== false)
2593
+ (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
2594
+ return writer;
2595
+ }
2596
+ }
2597
+ /**
2598
+ * @generated MessageType for protobuf message stream.video.sfu.signal.SendStatsResponse
2599
+ */
2600
+ const SendStatsResponse = new SendStatsResponse$Type();
2601
+ // @generated message type with reflection information, may provide speed optimized methods
2449
2602
  class ICERestartRequest$Type extends MessageType {
2450
2603
  constructor() {
2451
2604
  super('stream.video.sfu.signal.ICERestartRequest', [
@@ -3336,6 +3489,12 @@ const SignalServer = new ServiceType('stream.video.sfu.signal.SignalServer', [
3336
3489
  I: ICERestartRequest,
3337
3490
  O: ICERestartResponse,
3338
3491
  },
3492
+ {
3493
+ name: 'SendStats',
3494
+ options: {},
3495
+ I: SendStatsRequest,
3496
+ O: SendStatsResponse,
3497
+ },
3339
3498
  ]);
3340
3499
 
3341
3500
  /**
@@ -5631,6 +5790,13 @@ class SignalServerClient {
5631
5790
  const method = this.methods[5], opt = this._transport.mergeOptions(options);
5632
5791
  return stackIntercept('unary', this._transport, method, opt, input);
5633
5792
  }
5793
+ /**
5794
+ * @generated from protobuf rpc: SendStats(stream.video.sfu.signal.SendStatsRequest) returns (stream.video.sfu.signal.SendStatsResponse);
5795
+ */
5796
+ sendStats(input, options) {
5797
+ const method = this.methods[6], opt = this._transport.mergeOptions(options);
5798
+ return stackIntercept('unary', this._transport, method, opt, input);
5799
+ }
5634
5800
  }
5635
5801
 
5636
5802
  const defaultOptions = {
@@ -5885,6 +6051,7 @@ function getIceCandidate(candidate) {
5885
6051
  let sdkInfo;
5886
6052
  let osInfo;
5887
6053
  let deviceInfo;
6054
+ let webRtcInfo;
5888
6055
  const setSdkInfo = (info) => {
5889
6056
  sdkInfo = info;
5890
6057
  };
@@ -5903,6 +6070,12 @@ const setDeviceInfo = (info) => {
5903
6070
  const getDeviceInfo = () => {
5904
6071
  return deviceInfo;
5905
6072
  };
6073
+ const getWebRTCInfo = () => {
6074
+ return webRtcInfo;
6075
+ };
6076
+ const setWebRTCInfo = (info) => {
6077
+ webRtcInfo = info;
6078
+ };
5906
6079
  const getClientDetails = () => {
5907
6080
  if (isReactNative()) {
5908
6081
  // Since RN doesn't support web, sharing browser info is not required
@@ -5926,7 +6099,9 @@ const getClientDetails = () => {
5926
6099
  architecture: cpu.architecture || '',
5927
6100
  },
5928
6101
  device: {
5929
- name: `${device.vendor || ''} ${device.model || ''} ${device.type || ''}`,
6102
+ name: [device.vendor, device.model, device.type]
6103
+ .filter(Boolean)
6104
+ .join(' '),
5930
6105
  version: '',
5931
6106
  },
5932
6107
  };
@@ -7904,7 +8079,8 @@ class Publisher {
7904
8079
  this.onIceCandidateError = (e) => {
7905
8080
  const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
7906
8081
  `${e.errorCode}: ${e.errorText}`;
7907
- const logLevel = this.pc.iceConnectionState === 'connected' ? 'debug' : 'error';
8082
+ const iceState = this.pc.iceConnectionState;
8083
+ const logLevel = iceState === 'connected' || iceState === 'checking' ? 'debug' : 'warn';
7908
8084
  logger$3(logLevel, `ICE Candidate error`, errorMessage);
7909
8085
  };
7910
8086
  this.onIceConnectionStateChange = () => {
@@ -8224,7 +8400,8 @@ class Subscriber {
8224
8400
  this.onIceCandidateError = (e) => {
8225
8401
  const errorMessage = e instanceof RTCPeerConnectionIceErrorEvent &&
8226
8402
  `${e.errorCode}: ${e.errorText}`;
8227
- const logLevel = this.pc.iceConnectionState === 'connected' ? 'debug' : 'error';
8403
+ const iceState = this.pc.iceConnectionState;
8404
+ const logLevel = iceState === 'connected' || iceState === 'checking' ? 'debug' : 'warn';
8228
8405
  logger$2(logLevel, `ICE Candidate error`, errorMessage);
8229
8406
  };
8230
8407
  this.sfuClient = sfuClient;
@@ -8482,6 +8659,12 @@ class StreamSfuClient {
8482
8659
  sessionId: this.sessionId,
8483
8660
  }), this.logger);
8484
8661
  };
8662
+ this.sendStats = async (stats) => {
8663
+ return retryable(() => this.rpc.sendStats({
8664
+ ...stats,
8665
+ sessionId: this.sessionId,
8666
+ }), this.logger);
8667
+ };
8485
8668
  this.join = async (data) => {
8486
8669
  const joinRequest = JoinRequest.create({
8487
8670
  ...data,
@@ -9016,8 +9199,7 @@ const registerRingingCallEventHandlers = (call) => {
9016
9199
  * @param data the data for the call.
9017
9200
  */
9018
9201
  const join = async (httpClient, type, id, data) => {
9019
- const joinCallResponse = await doJoin(httpClient, type, id, data);
9020
- const { call, credentials, members, own_capabilities } = joinCallResponse;
9202
+ const { call, credentials, members, own_capabilities, stats_options } = await doJoin(httpClient, type, id, data);
9021
9203
  return {
9022
9204
  connectionConfig: toRtcConfiguration(credentials.ice_servers),
9023
9205
  sfuServer: credentials.server,
@@ -9025,6 +9207,7 @@ const join = async (httpClient, type, id, data) => {
9025
9207
  metadata: call,
9026
9208
  members,
9027
9209
  ownCapabilities: own_capabilities,
9210
+ statsOptions: stats_options,
9028
9211
  };
9029
9212
  };
9030
9213
  const doJoin = async (httpClient, type, id, data) => {
@@ -9048,6 +9231,19 @@ const toRtcConfiguration = (config) => {
9048
9231
  return rtcConfig;
9049
9232
  };
9050
9233
 
9234
+ /**
9235
+ * Flatten the stats report into an array of stats objects.
9236
+ *
9237
+ * @param report the report to flatten.
9238
+ */
9239
+ const flatten$1 = (report) => {
9240
+ const stats = [];
9241
+ report.forEach((s) => {
9242
+ stats.push(s);
9243
+ });
9244
+ return stats;
9245
+ };
9246
+
9051
9247
  /**
9052
9248
  * Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
9053
9249
  */
@@ -9268,18 +9464,58 @@ const aggregate = (stats) => {
9268
9464
  }
9269
9465
  return report;
9270
9466
  };
9271
- /**
9272
- * Flatten the stats report into an array of stats objects.
9273
- *
9274
- * @param report the report to flatten.
9275
- */
9276
- const flatten$1 = (report) => {
9277
- const stats = [];
9278
- report.forEach((s) => {
9279
- stats.push(s);
9280
- });
9281
- return stats;
9282
- };
9467
+
9468
+ class SfuStatsReporter {
9469
+ constructor(sfuClient, { options, clientDetails, subscriber, publisher }) {
9470
+ this.logger = getLogger(['SfuStatsReporter']);
9471
+ this.run = async () => {
9472
+ const [subscriberStats, publisherStats] = await Promise.all([
9473
+ this.subscriber.getStats().then(flatten$1).then(JSON.stringify),
9474
+ this.publisher.getStats().then(flatten$1).then(JSON.stringify),
9475
+ ]);
9476
+ await this.sfuClient.sendStats({
9477
+ sdk: this.sdkName,
9478
+ sdkVersion: this.sdkVersion,
9479
+ webrtcVersion: this.webRTCVersion,
9480
+ subscriberStats,
9481
+ publisherStats,
9482
+ });
9483
+ };
9484
+ this.start = () => {
9485
+ if (this.options.reporting_interval_ms <= 0)
9486
+ return;
9487
+ this.intervalId = setInterval(() => {
9488
+ this.run().catch((err) => {
9489
+ this.logger('warn', 'Failed to report stats', err);
9490
+ });
9491
+ }, this.options.reporting_interval_ms);
9492
+ };
9493
+ this.stop = () => {
9494
+ clearInterval(this.intervalId);
9495
+ this.intervalId = undefined;
9496
+ };
9497
+ this.sfuClient = sfuClient;
9498
+ this.options = options;
9499
+ this.subscriber = subscriber;
9500
+ this.publisher = publisher;
9501
+ const webRTCInfo = getWebRTCInfo();
9502
+ const { sdk, browser } = clientDetails;
9503
+ this.sdkName =
9504
+ sdk && sdk.type === SdkType.REACT
9505
+ ? 'stream-react'
9506
+ : sdk && sdk.type === SdkType.REACT_NATIVE
9507
+ ? 'stream-react-native'
9508
+ : 'stream-js';
9509
+ this.sdkVersion = sdk
9510
+ ? `${sdk.major}.${sdk.minor}.${sdk.patch}`
9511
+ : '0.0.0-development';
9512
+ // The WebRTC version if passed from the SDK, it is taken else the browser info is sent.
9513
+ this.webRTCVersion =
9514
+ webRTCInfo?.version ||
9515
+ `${browser?.name || ''}-${browser?.version || ''}` ||
9516
+ 'N/A';
9517
+ }
9518
+ }
9283
9519
 
9284
9520
  const DEFAULT_THRESHOLD = 0.35;
9285
9521
  class ViewportTracker {
@@ -11213,6 +11449,8 @@ class Call {
11213
11449
  }
11214
11450
  this.statsReporter?.stop();
11215
11451
  this.statsReporter = undefined;
11452
+ this.sfuStatsReporter?.stop();
11453
+ this.sfuStatsReporter = undefined;
11216
11454
  this.subscriber?.close();
11217
11455
  this.subscriber = undefined;
11218
11456
  this.publisher?.close();
@@ -11352,12 +11590,14 @@ class Call {
11352
11590
  let sfuServer;
11353
11591
  let sfuToken;
11354
11592
  let connectionConfig;
11593
+ let statsOptions;
11355
11594
  try {
11356
11595
  if (this.sfuClient?.isFastReconnecting) {
11357
11596
  // use previous SFU configuration and values
11358
11597
  connectionConfig = this.publisher?.connectionConfiguration;
11359
11598
  sfuServer = this.sfuClient.sfuServer;
11360
11599
  sfuToken = this.sfuClient.token;
11600
+ statsOptions = this.sfuStatsReporter?.options;
11361
11601
  }
11362
11602
  else {
11363
11603
  // full join flow - let the Coordinator pick a new SFU for us
@@ -11368,6 +11608,7 @@ class Call {
11368
11608
  connectionConfig = call.connectionConfig;
11369
11609
  sfuServer = call.sfuServer;
11370
11610
  sfuToken = call.token;
11611
+ statsOptions = call.statsOptions;
11371
11612
  }
11372
11613
  if (this.streamClient._hasConnectionID()) {
11373
11614
  this.watching = true;
@@ -11424,6 +11665,8 @@ class Call {
11424
11665
  this.publisher = undefined;
11425
11666
  this.statsReporter?.stop();
11426
11667
  this.statsReporter = undefined;
11668
+ this.sfuStatsReporter?.stop();
11669
+ this.sfuStatsReporter = undefined;
11427
11670
  // clean up current connection
11428
11671
  sfuClient.close(StreamSfuClient.NORMAL_CLOSURE, 'js-client: attempting full reconnect');
11429
11672
  }
@@ -11564,10 +11807,10 @@ class Call {
11564
11807
  connectionConfig,
11565
11808
  });
11566
11809
  }
11567
- const audioSettings = this.state.settings?.audio;
11568
- const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
11569
- const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
11570
11810
  if (!this.publisher) {
11811
+ const audioSettings = this.state.settings?.audio;
11812
+ const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
11813
+ const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
11571
11814
  this.publisher = new Publisher({
11572
11815
  sfuClient,
11573
11816
  dispatcher: this.dispatcher,
@@ -11584,6 +11827,16 @@ class Call {
11584
11827
  state: this.state,
11585
11828
  });
11586
11829
  }
11830
+ const clientDetails = getClientDetails();
11831
+ if (!this.sfuStatsReporter && statsOptions) {
11832
+ this.sfuStatsReporter = new SfuStatsReporter(sfuClient, {
11833
+ clientDetails,
11834
+ options: statsOptions,
11835
+ subscriber: this.subscriber,
11836
+ publisher: this.publisher,
11837
+ });
11838
+ this.sfuStatsReporter.start();
11839
+ }
11587
11840
  try {
11588
11841
  // 1. wait for the signal server to be ready before sending "joinRequest"
11589
11842
  sfuClient.signalReady
@@ -11603,7 +11856,7 @@ class Call {
11603
11856
  : undefined;
11604
11857
  return sfuClient.join({
11605
11858
  subscriberSdp: sdp || '',
11606
- clientDetails: getClientDetails(),
11859
+ clientDetails,
11607
11860
  migration,
11608
11861
  fastReconnect: previousSfuClient?.isFastReconnecting ?? false,
11609
11862
  });
@@ -12222,6 +12475,17 @@ class Call {
12222
12475
  }
12223
12476
  return this.streamClient.get(`${endpoint}/recordings`);
12224
12477
  };
12478
+ /**
12479
+ * Retrieve call statistics for a particular call session (historical).
12480
+ * Here `callSessionID` is mandatory.
12481
+ *
12482
+ * @param callSessionID the call session ID to retrieve statistics for.
12483
+ * @returns The call stats.
12484
+ */
12485
+ this.getCallStats = async (callSessionID) => {
12486
+ const endpoint = `${this.streamClientBasePath}/stats/${callSessionID}`;
12487
+ return this.streamClient.get(endpoint);
12488
+ };
12225
12489
  /**
12226
12490
  * Sends a custom event to all call participants.
12227
12491
  *
@@ -13634,7 +13898,7 @@ const getLocationHint = async (hintUrl = HINT_URL, timeout = 2000) => {
13634
13898
  const abortController = new AbortController();
13635
13899
  const timeoutId = setTimeout(() => abortController.abort(), timeout);
13636
13900
  try {
13637
- const response = await fetch(HINT_URL, {
13901
+ const response = await fetch(hintUrl, {
13638
13902
  method: 'HEAD',
13639
13903
  signal: abortController.signal,
13640
13904
  });
@@ -13643,7 +13907,7 @@ const getLocationHint = async (hintUrl = HINT_URL, timeout = 2000) => {
13643
13907
  return awsPop.substring(0, 3); // AMS1-P2 -> AMS
13644
13908
  }
13645
13909
  catch (e) {
13646
- logger('warn', `Failed to get location hint from ${HINT_URL}`, e);
13910
+ logger('warn', `Failed to get location hint from ${hintUrl}`, e);
13647
13911
  return 'ERR';
13648
13912
  }
13649
13913
  finally {
@@ -14090,7 +14354,7 @@ class StreamClient {
14090
14354
  });
14091
14355
  };
14092
14356
  this.getUserAgent = () => {
14093
- const version = "0.6.1" ;
14357
+ const version = "0.6.3" ;
14094
14358
  return (this.userAgent ||
14095
14359
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
14096
14360
  };
@@ -14638,5 +14902,5 @@ class StreamVideoServerClient extends StreamVideoClient {
14638
14902
  }
14639
14903
  }
14640
14904
 
14641
- export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsNameEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, speakerLayoutSortPreset, speaking };
14905
+ export { AudioSettingsDefaultDeviceEnum, AudioSettingsRequestDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsNameEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, OwnCapability, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoServerClient, StreamVideoWriteableStateStore, TranscriptionSettingsModeEnum, TranscriptionSettingsRequestModeEnum, VideoSettingsCameraFacingEnum, VideoSettingsRequestCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoDevices, getVideoStream, getWebRTCInfo, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setSdkInfo, setWebRTCInfo, speakerLayoutSortPreset, speaking };
14642
14906
  //# sourceMappingURL=index.browser.es.js.map