@stream-io/video-client 0.6.2 → 0.6.4

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 (39) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/index.browser.es.js +282 -29
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +283 -28
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +282 -29
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +1 -0
  9. package/dist/src/StreamSfuClient.d.ts +2 -1
  10. package/dist/src/StreamVideoClient.d.ts +1 -1
  11. package/dist/src/client-details.d.ts +10 -1
  12. package/dist/src/devices/InputMediaDeviceManager.d.ts +1 -1
  13. package/dist/src/devices/SpeakerManager.d.ts +4 -3
  14. package/dist/src/gen/coordinator/index.d.ts +19 -0
  15. package/dist/src/gen/video/sfu/signal_rpc/signal.client.d.ts +9 -1
  16. package/dist/src/gen/video/sfu/signal_rpc/signal.d.ts +58 -0
  17. package/dist/src/rtc/flows/join.d.ts +1 -0
  18. package/dist/src/stats/SfuStatsReporter.d.ts +25 -0
  19. package/dist/src/stats/index.d.ts +3 -0
  20. package/dist/src/stats/utils.d.ts +6 -0
  21. package/dist/src/store/CallState.d.ts +1 -1
  22. package/package.json +1 -1
  23. package/src/Call.ts +26 -9
  24. package/src/StreamSfuClient.ts +12 -0
  25. package/src/StreamVideoClient.ts +1 -1
  26. package/src/client-details.ts +18 -1
  27. package/src/devices/InputMediaDeviceManager.ts +4 -2
  28. package/src/devices/SpeakerManager.ts +18 -6
  29. package/src/gen/coordinator/index.ts +19 -0
  30. package/src/gen/video/sfu/signal_rpc/signal.client.ts +26 -0
  31. package/src/gen/video/sfu/signal_rpc/signal.ts +250 -0
  32. package/src/helpers/RNSpeechDetector.ts +1 -1
  33. package/src/rtc/flows/join.ts +4 -2
  34. package/src/stats/SfuStatsReporter.ts +88 -0
  35. package/src/stats/index.ts +3 -0
  36. package/src/stats/{state-store-stats-reporter.ts → stateStoreStatsReporter.ts} +1 -13
  37. package/src/stats/utils.ts +12 -0
  38. package/src/store/CallState.ts +1 -1
  39. /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.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-0.6.3...@stream-io/video-client-0.6.4) (2024-03-28)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **react-native:** improve error logging for speaker manager hook and improve usage of incall manager in SDK ([#1299](https://github.com/GetStream/stream-video-js/issues/1299)) ([9527c41](https://github.com/GetStream/stream-video-js/commit/9527c4176d4e46224ddec18e3fddfb404e0aaae5))
11
+
12
+ ### [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)
13
+
14
+
15
+ ### Features
16
+
17
+ * 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)
18
+
5
19
  ### [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)
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
@@ -8486,6 +8659,12 @@ class StreamSfuClient {
8486
8659
  sessionId: this.sessionId,
8487
8660
  }), this.logger);
8488
8661
  };
8662
+ this.sendStats = async (stats) => {
8663
+ return retryable(() => this.rpc.sendStats({
8664
+ ...stats,
8665
+ sessionId: this.sessionId,
8666
+ }), this.logger);
8667
+ };
8489
8668
  this.join = async (data) => {
8490
8669
  const joinRequest = JoinRequest.create({
8491
8670
  ...data,
@@ -9020,8 +9199,7 @@ const registerRingingCallEventHandlers = (call) => {
9020
9199
  * @param data the data for the call.
9021
9200
  */
9022
9201
  const join = async (httpClient, type, id, data) => {
9023
- const joinCallResponse = await doJoin(httpClient, type, id, data);
9024
- const { call, credentials, members, own_capabilities } = joinCallResponse;
9202
+ const { call, credentials, members, own_capabilities, stats_options } = await doJoin(httpClient, type, id, data);
9025
9203
  return {
9026
9204
  connectionConfig: toRtcConfiguration(credentials.ice_servers),
9027
9205
  sfuServer: credentials.server,
@@ -9029,6 +9207,7 @@ const join = async (httpClient, type, id, data) => {
9029
9207
  metadata: call,
9030
9208
  members,
9031
9209
  ownCapabilities: own_capabilities,
9210
+ statsOptions: stats_options,
9032
9211
  };
9033
9212
  };
9034
9213
  const doJoin = async (httpClient, type, id, data) => {
@@ -9052,6 +9231,19 @@ const toRtcConfiguration = (config) => {
9052
9231
  return rtcConfig;
9053
9232
  };
9054
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
+
9055
9247
  /**
9056
9248
  * Creates a new StatsReporter instance that collects metrics about the ongoing call and reports them to the state store
9057
9249
  */
@@ -9272,18 +9464,58 @@ const aggregate = (stats) => {
9272
9464
  }
9273
9465
  return report;
9274
9466
  };
9275
- /**
9276
- * Flatten the stats report into an array of stats objects.
9277
- *
9278
- * @param report the report to flatten.
9279
- */
9280
- const flatten$1 = (report) => {
9281
- const stats = [];
9282
- report.forEach((s) => {
9283
- stats.push(s);
9284
- });
9285
- return stats;
9286
- };
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
+ }
9287
9519
 
9288
9520
  const DEFAULT_THRESHOLD = 0.35;
9289
9521
  class ViewportTracker {
@@ -10153,12 +10385,12 @@ class InputMediaDeviceManager {
10153
10385
  /**
10154
10386
  * Selects a device.
10155
10387
  *
10156
- * Note: this method is not supported in React Native
10388
+ * Note: This method is not supported in React Native
10157
10389
  * @param deviceId the device id to select.
10158
10390
  */
10159
10391
  async select(deviceId) {
10160
10392
  if (isReactNative()) {
10161
- throw new Error('This method is not supported in React Native');
10393
+ throw new Error('This method is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for reference.');
10162
10394
  }
10163
10395
  if (deviceId === this.state.selectedDevice) {
10164
10396
  return;
@@ -11059,22 +11291,26 @@ class SpeakerManager {
11059
11291
  * Lists the available audio output devices
11060
11292
  *
11061
11293
  * Note: It prompts the user for a permission to use devices (if not already granted)
11294
+ * Note: This method is not supported in React Native
11062
11295
  *
11063
11296
  * @returns an Observable that will be updated if a device is connected or disconnected
11064
11297
  */
11065
11298
  listDevices() {
11299
+ if (isReactNative()) {
11300
+ throw new Error('This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details');
11301
+ }
11066
11302
  return getAudioOutputDevices();
11067
11303
  }
11068
11304
  /**
11069
11305
  * Select a device.
11070
11306
  *
11071
- * Note: this method is not supported in React Native
11307
+ * Note: This method is not supported in React Native
11072
11308
  *
11073
11309
  * @param deviceId empty string means the system default
11074
11310
  */
11075
11311
  select(deviceId) {
11076
11312
  if (isReactNative()) {
11077
- throw new Error('This feature is not supported in React Native');
11313
+ throw new Error('This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details');
11078
11314
  }
11079
11315
  this.state.setDevice(deviceId);
11080
11316
  }
@@ -11082,11 +11318,11 @@ class SpeakerManager {
11082
11318
  * Set the volume of the audio elements
11083
11319
  * @param volume a number between 0 and 1.
11084
11320
  *
11085
- * Note: this method is not supported in React Native
11321
+ * Note: This method is not supported in React Native
11086
11322
  */
11087
11323
  setVolume(volume) {
11088
11324
  if (isReactNative()) {
11089
- throw new Error('This feature is not supported in React Native');
11325
+ throw new Error('This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details');
11090
11326
  }
11091
11327
  if (volume && (volume < 0 || volume > 1)) {
11092
11328
  throw new Error('Volume must be between 0 and 1');
@@ -11096,14 +11332,14 @@ class SpeakerManager {
11096
11332
  /**
11097
11333
  * Set the volume of a participant.
11098
11334
  *
11099
- * Note: this method is not supported in React Native.
11335
+ * Note: This method is not supported in React Native.
11100
11336
  *
11101
11337
  * @param sessionId the participant's session id.
11102
11338
  * @param volume a number between 0 and 1. Set it to `undefined` to use the default volume.
11103
11339
  */
11104
11340
  setParticipantVolume(sessionId, volume) {
11105
11341
  if (isReactNative()) {
11106
- throw new Error('This feature is not supported in React Native');
11342
+ throw new Error('This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details');
11107
11343
  }
11108
11344
  if (volume && (volume < 0 || volume > 1)) {
11109
11345
  throw new Error('Volume must be between 0 and 1, or undefined');
@@ -11217,6 +11453,8 @@ class Call {
11217
11453
  }
11218
11454
  this.statsReporter?.stop();
11219
11455
  this.statsReporter = undefined;
11456
+ this.sfuStatsReporter?.stop();
11457
+ this.sfuStatsReporter = undefined;
11220
11458
  this.subscriber?.close();
11221
11459
  this.subscriber = undefined;
11222
11460
  this.publisher?.close();
@@ -11356,12 +11594,14 @@ class Call {
11356
11594
  let sfuServer;
11357
11595
  let sfuToken;
11358
11596
  let connectionConfig;
11597
+ let statsOptions;
11359
11598
  try {
11360
11599
  if (this.sfuClient?.isFastReconnecting) {
11361
11600
  // use previous SFU configuration and values
11362
11601
  connectionConfig = this.publisher?.connectionConfiguration;
11363
11602
  sfuServer = this.sfuClient.sfuServer;
11364
11603
  sfuToken = this.sfuClient.token;
11604
+ statsOptions = this.sfuStatsReporter?.options;
11365
11605
  }
11366
11606
  else {
11367
11607
  // full join flow - let the Coordinator pick a new SFU for us
@@ -11372,6 +11612,7 @@ class Call {
11372
11612
  connectionConfig = call.connectionConfig;
11373
11613
  sfuServer = call.sfuServer;
11374
11614
  sfuToken = call.token;
11615
+ statsOptions = call.statsOptions;
11375
11616
  }
11376
11617
  if (this.streamClient._hasConnectionID()) {
11377
11618
  this.watching = true;
@@ -11428,6 +11669,8 @@ class Call {
11428
11669
  this.publisher = undefined;
11429
11670
  this.statsReporter?.stop();
11430
11671
  this.statsReporter = undefined;
11672
+ this.sfuStatsReporter?.stop();
11673
+ this.sfuStatsReporter = undefined;
11431
11674
  // clean up current connection
11432
11675
  sfuClient.close(StreamSfuClient.NORMAL_CLOSURE, 'js-client: attempting full reconnect');
11433
11676
  }
@@ -11568,10 +11811,10 @@ class Call {
11568
11811
  connectionConfig,
11569
11812
  });
11570
11813
  }
11571
- const audioSettings = this.state.settings?.audio;
11572
- const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
11573
- const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
11574
11814
  if (!this.publisher) {
11815
+ const audioSettings = this.state.settings?.audio;
11816
+ const isDtxEnabled = !!audioSettings?.opus_dtx_enabled;
11817
+ const isRedEnabled = !!audioSettings?.redundant_coding_enabled;
11575
11818
  this.publisher = new Publisher({
11576
11819
  sfuClient,
11577
11820
  dispatcher: this.dispatcher,
@@ -11588,6 +11831,16 @@ class Call {
11588
11831
  state: this.state,
11589
11832
  });
11590
11833
  }
11834
+ const clientDetails = getClientDetails();
11835
+ if (!this.sfuStatsReporter && statsOptions) {
11836
+ this.sfuStatsReporter = new SfuStatsReporter(sfuClient, {
11837
+ clientDetails,
11838
+ options: statsOptions,
11839
+ subscriber: this.subscriber,
11840
+ publisher: this.publisher,
11841
+ });
11842
+ this.sfuStatsReporter.start();
11843
+ }
11591
11844
  try {
11592
11845
  // 1. wait for the signal server to be ready before sending "joinRequest"
11593
11846
  sfuClient.signalReady
@@ -11607,7 +11860,7 @@ class Call {
11607
11860
  : undefined;
11608
11861
  return sfuClient.join({
11609
11862
  subscriberSdp: sdp || '',
11610
- clientDetails: getClientDetails(),
11863
+ clientDetails,
11611
11864
  migration,
11612
11865
  fastReconnect: previousSfuClient?.isFastReconnecting ?? false,
11613
11866
  });
@@ -14105,7 +14358,7 @@ class StreamClient {
14105
14358
  });
14106
14359
  };
14107
14360
  this.getUserAgent = () => {
14108
- const version = "0.6.2" ;
14361
+ const version = "0.6.4" ;
14109
14362
  return (this.userAgent ||
14110
14363
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
14111
14364
  };
@@ -14316,7 +14569,7 @@ class StreamVideoClient {
14316
14569
  * Creates a new call.
14317
14570
  *
14318
14571
  * @param type the type of the call.
14319
- * @param id the id of the call, if not provided a unique random value is used
14572
+ * @param id the id of the call.
14320
14573
  */
14321
14574
  this.call = (type, id) => {
14322
14575
  return new Call({
@@ -14653,5 +14906,5 @@ class StreamVideoServerClient extends StreamVideoClient {
14653
14906
  }
14654
14907
  }
14655
14908
 
14656
- 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 };
14909
+ 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 };
14657
14910
  //# sourceMappingURL=index.browser.es.js.map