@stream-io/video-client 1.10.4 → 1.11.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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.11.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.5...@stream-io/video-client-1.11.0) (2024-11-13)
6
+
7
+
8
+ ### Features
9
+
10
+ * Connection timing ([#1574](https://github.com/GetStream/stream-video-js/issues/1574)) ([ce1dc9a](https://github.com/GetStream/stream-video-js/commit/ce1dc9a01fc5b0e60e3dac6653c27e99fd4b3ecb))
11
+
12
+ ## [1.10.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.4...@stream-io/video-client-1.10.5) (2024-11-07)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * ignore maxSimulcastLayers override for SVC codecs ([#1564](https://github.com/GetStream/stream-video-js/issues/1564)) ([48f8abe](https://github.com/GetStream/stream-video-js/commit/48f8abe5fd5b48c367a04696febd582573def828))
18
+
5
19
  ## [1.10.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.10.3...@stream-io/video-client-1.10.4) (2024-11-07)
6
20
 
7
21
 
@@ -164,6 +164,41 @@ const VideoSettingsResponseCameraFacingEnum = {
164
164
  class ErrorFromResponse extends Error {
165
165
  }
166
166
 
167
+ /* eslint-disable */
168
+ // @generated by protobuf-ts 2.9.4 with parameter long_type_string,client_generic,server_none,eslint_disable,optimize_code_size
169
+ // @generated from protobuf file "google/protobuf/struct.proto" (package "google.protobuf", syntax proto3)
170
+ // tslint:disable
171
+ //
172
+ // Protocol Buffers - Google's data interchange format
173
+ // Copyright 2008 Google Inc. All rights reserved.
174
+ // https://developers.google.com/protocol-buffers/
175
+ //
176
+ // Redistribution and use in source and binary forms, with or without
177
+ // modification, are permitted provided that the following conditions are
178
+ // met:
179
+ //
180
+ // * Redistributions of source code must retain the above copyright
181
+ // notice, this list of conditions and the following disclaimer.
182
+ // * Redistributions in binary form must reproduce the above
183
+ // copyright notice, this list of conditions and the following disclaimer
184
+ // in the documentation and/or other materials provided with the
185
+ // distribution.
186
+ // * Neither the name of Google Inc. nor the names of its
187
+ // contributors may be used to endorse or promote products derived from
188
+ // this software without specific prior written permission.
189
+ //
190
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
191
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
194
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
195
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
196
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
197
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
198
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
199
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
200
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
201
+ //
167
202
  /**
168
203
  * `NullValue` is a singleton enumeration to represent the null value for the
169
204
  * `Value` type union.
@@ -395,6 +430,41 @@ class ListValue$Type extends MessageType {
395
430
  */
396
431
  const ListValue = new ListValue$Type();
397
432
 
433
+ /* eslint-disable */
434
+ // @generated by protobuf-ts 2.9.4 with parameter long_type_string,client_generic,server_none,eslint_disable,optimize_code_size
435
+ // @generated from protobuf file "google/protobuf/timestamp.proto" (package "google.protobuf", syntax proto3)
436
+ // tslint:disable
437
+ //
438
+ // Protocol Buffers - Google's data interchange format
439
+ // Copyright 2008 Google Inc. All rights reserved.
440
+ // https://developers.google.com/protocol-buffers/
441
+ //
442
+ // Redistribution and use in source and binary forms, with or without
443
+ // modification, are permitted provided that the following conditions are
444
+ // met:
445
+ //
446
+ // * Redistributions of source code must retain the above copyright
447
+ // notice, this list of conditions and the following disclaimer.
448
+ // * Redistributions in binary form must reproduce the above
449
+ // copyright notice, this list of conditions and the following disclaimer
450
+ // in the documentation and/or other materials provided with the
451
+ // distribution.
452
+ // * Neither the name of Google Inc. nor the names of its
453
+ // contributors may be used to endorse or promote products derived from
454
+ // this software without specific prior written permission.
455
+ //
456
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
457
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
458
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
459
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
460
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
461
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
462
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
463
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
464
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
465
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
466
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
467
+ //
398
468
  // @generated message type with reflection information, may provide speed optimized methods
399
469
  class Timestamp$Type extends MessageType {
400
470
  constructor() {
@@ -1094,36 +1164,83 @@ class VideoLayer$Type extends MessageType {
1094
1164
  */
1095
1165
  const VideoLayer = new VideoLayer$Type();
1096
1166
  // @generated message type with reflection information, may provide speed optimized methods
1167
+ class PublishOptions$Type extends MessageType {
1168
+ constructor() {
1169
+ super('stream.video.sfu.models.PublishOptions', [
1170
+ {
1171
+ no: 1,
1172
+ name: 'codecs',
1173
+ kind: 'message',
1174
+ repeat: 1 /*RepeatType.PACKED*/,
1175
+ T: () => PublishOption,
1176
+ },
1177
+ ]);
1178
+ }
1179
+ }
1180
+ /**
1181
+ * @generated MessageType for protobuf message stream.video.sfu.models.PublishOptions
1182
+ */
1183
+ const PublishOptions = new PublishOptions$Type();
1184
+ // @generated message type with reflection information, may provide speed optimized methods
1185
+ class PublishOption$Type extends MessageType {
1186
+ constructor() {
1187
+ super('stream.video.sfu.models.PublishOption', [
1188
+ {
1189
+ no: 1,
1190
+ name: 'track_type',
1191
+ kind: 'enum',
1192
+ T: () => [
1193
+ 'stream.video.sfu.models.TrackType',
1194
+ TrackType,
1195
+ 'TRACK_TYPE_',
1196
+ ],
1197
+ },
1198
+ { no: 2, name: 'codec', kind: 'message', T: () => Codec },
1199
+ { no: 3, name: 'bitrate', kind: 'scalar', T: 5 /*ScalarType.INT32*/ },
1200
+ { no: 4, name: 'fps', kind: 'scalar', T: 5 /*ScalarType.INT32*/ },
1201
+ {
1202
+ no: 5,
1203
+ name: 'max_spatial_layers',
1204
+ kind: 'scalar',
1205
+ T: 5 /*ScalarType.INT32*/,
1206
+ },
1207
+ {
1208
+ no: 6,
1209
+ name: 'max_temporal_layers',
1210
+ kind: 'scalar',
1211
+ T: 5 /*ScalarType.INT32*/,
1212
+ },
1213
+ ]);
1214
+ }
1215
+ }
1216
+ /**
1217
+ * @generated MessageType for protobuf message stream.video.sfu.models.PublishOption
1218
+ */
1219
+ const PublishOption = new PublishOption$Type();
1220
+ // @generated message type with reflection information, may provide speed optimized methods
1097
1221
  class Codec$Type extends MessageType {
1098
1222
  constructor() {
1099
1223
  super('stream.video.sfu.models.Codec', [
1100
1224
  {
1101
- no: 1,
1225
+ no: 11,
1102
1226
  name: 'payload_type',
1103
1227
  kind: 'scalar',
1104
1228
  T: 13 /*ScalarType.UINT32*/,
1105
1229
  },
1106
- { no: 2, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
1107
- { no: 3, name: 'fmtp_line', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
1230
+ { no: 10, name: 'name', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
1108
1231
  {
1109
- no: 4,
1232
+ no: 14,
1110
1233
  name: 'clock_rate',
1111
1234
  kind: 'scalar',
1112
1235
  T: 13 /*ScalarType.UINT32*/,
1113
1236
  },
1114
1237
  {
1115
- no: 5,
1238
+ no: 13,
1116
1239
  name: 'encoding_parameters',
1117
1240
  kind: 'scalar',
1118
1241
  T: 9 /*ScalarType.STRING*/,
1119
1242
  },
1120
- {
1121
- no: 6,
1122
- name: 'feedbacks',
1123
- kind: 'scalar',
1124
- repeat: 2 /*RepeatType.UNPACKED*/,
1125
- T: 9 /*ScalarType.STRING*/,
1126
- },
1243
+ { no: 12, name: 'fmtp', kind: 'scalar', T: 9 /*ScalarType.STRING*/ },
1127
1244
  ]);
1128
1245
  }
1129
1246
  }
@@ -1454,6 +1571,8 @@ var models = /*#__PURE__*/Object.freeze({
1454
1571
  ParticipantCount: ParticipantCount,
1455
1572
  get PeerType () { return PeerType; },
1456
1573
  Pin: Pin,
1574
+ PublishOption: PublishOption,
1575
+ PublishOptions: PublishOptions,
1457
1576
  Sdk: Sdk,
1458
1577
  get SdkType () { return SdkType; },
1459
1578
  StreamQuality: StreamQuality,
@@ -1519,6 +1638,58 @@ class StopNoiseCancellationResponse$Type extends MessageType {
1519
1638
  */
1520
1639
  const StopNoiseCancellationResponse = new StopNoiseCancellationResponse$Type();
1521
1640
  // @generated message type with reflection information, may provide speed optimized methods
1641
+ class Reconnection$Type extends MessageType {
1642
+ constructor() {
1643
+ super('stream.video.sfu.signal.Reconnection', [
1644
+ {
1645
+ no: 1,
1646
+ name: 'time_seconds',
1647
+ kind: 'scalar',
1648
+ T: 2 /*ScalarType.FLOAT*/,
1649
+ },
1650
+ {
1651
+ no: 2,
1652
+ name: 'strategy',
1653
+ kind: 'enum',
1654
+ T: () => [
1655
+ 'stream.video.sfu.models.WebsocketReconnectStrategy',
1656
+ WebsocketReconnectStrategy,
1657
+ 'WEBSOCKET_RECONNECT_STRATEGY_',
1658
+ ],
1659
+ },
1660
+ ]);
1661
+ }
1662
+ }
1663
+ /**
1664
+ * @generated MessageType for protobuf message stream.video.sfu.signal.Reconnection
1665
+ */
1666
+ const Reconnection = new Reconnection$Type();
1667
+ // @generated message type with reflection information, may provide speed optimized methods
1668
+ class Telemetry$Type extends MessageType {
1669
+ constructor() {
1670
+ super('stream.video.sfu.signal.Telemetry', [
1671
+ {
1672
+ no: 1,
1673
+ name: 'connection_time_seconds',
1674
+ kind: 'scalar',
1675
+ oneof: 'data',
1676
+ T: 2 /*ScalarType.FLOAT*/,
1677
+ },
1678
+ {
1679
+ no: 2,
1680
+ name: 'reconnection',
1681
+ kind: 'message',
1682
+ oneof: 'data',
1683
+ T: () => Reconnection,
1684
+ },
1685
+ ]);
1686
+ }
1687
+ }
1688
+ /**
1689
+ * @generated MessageType for protobuf message stream.video.sfu.signal.Telemetry
1690
+ */
1691
+ const Telemetry = new Telemetry$Type();
1692
+ // @generated message type with reflection information, may provide speed optimized methods
1522
1693
  class SendStatsRequest$Type extends MessageType {
1523
1694
  constructor() {
1524
1695
  super('stream.video.sfu.signal.SendStatsRequest', [
@@ -1564,6 +1735,7 @@ class SendStatsRequest$Type extends MessageType {
1564
1735
  oneof: 'deviceState',
1565
1736
  T: () => AppleState,
1566
1737
  },
1738
+ { no: 11, name: 'telemetry', kind: 'message', T: () => Telemetry },
1567
1739
  ]);
1568
1740
  }
1569
1741
  }
@@ -2033,6 +2205,20 @@ class SfuEvent$Type extends MessageType {
2033
2205
  oneof: 'eventPayload',
2034
2206
  T: () => ParticipantMigrationComplete,
2035
2207
  },
2208
+ {
2209
+ no: 26,
2210
+ name: 'codec_negotiation_complete',
2211
+ kind: 'message',
2212
+ oneof: 'eventPayload',
2213
+ T: () => CodecNegotiationComplete,
2214
+ },
2215
+ {
2216
+ no: 27,
2217
+ name: 'change_publish_options',
2218
+ kind: 'message',
2219
+ oneof: 'eventPayload',
2220
+ T: () => ChangePublishOptions,
2221
+ },
2036
2222
  ]);
2037
2223
  }
2038
2224
  }
@@ -2041,6 +2227,33 @@ class SfuEvent$Type extends MessageType {
2041
2227
  */
2042
2228
  const SfuEvent = new SfuEvent$Type();
2043
2229
  // @generated message type with reflection information, may provide speed optimized methods
2230
+ class ChangePublishOptions$Type extends MessageType {
2231
+ constructor() {
2232
+ super('stream.video.sfu.event.ChangePublishOptions', [
2233
+ {
2234
+ no: 1,
2235
+ name: 'publish_option',
2236
+ kind: 'message',
2237
+ T: () => PublishOption,
2238
+ },
2239
+ ]);
2240
+ }
2241
+ }
2242
+ /**
2243
+ * @generated MessageType for protobuf message stream.video.sfu.event.ChangePublishOptions
2244
+ */
2245
+ const ChangePublishOptions = new ChangePublishOptions$Type();
2246
+ // @generated message type with reflection information, may provide speed optimized methods
2247
+ class CodecNegotiationComplete$Type extends MessageType {
2248
+ constructor() {
2249
+ super('stream.video.sfu.event.CodecNegotiationComplete', []);
2250
+ }
2251
+ }
2252
+ /**
2253
+ * @generated MessageType for protobuf message stream.video.sfu.event.CodecNegotiationComplete
2254
+ */
2255
+ const CodecNegotiationComplete = new CodecNegotiationComplete$Type();
2256
+ // @generated message type with reflection information, may provide speed optimized methods
2044
2257
  class ParticipantMigrationComplete$Type extends MessageType {
2045
2258
  constructor() {
2046
2259
  super('stream.video.sfu.event.ParticipantMigrationComplete', []);
@@ -2272,6 +2485,12 @@ class JoinRequest$Type extends MessageType {
2272
2485
  kind: 'scalar',
2273
2486
  T: 9 /*ScalarType.STRING*/,
2274
2487
  },
2488
+ {
2489
+ no: 8,
2490
+ name: 'publisher_sdp',
2491
+ kind: 'scalar',
2492
+ T: 9 /*ScalarType.STRING*/,
2493
+ },
2275
2494
  {
2276
2495
  no: 4,
2277
2496
  name: 'client_details',
@@ -2394,6 +2613,12 @@ class JoinResponse$Type extends MessageType {
2394
2613
  kind: 'scalar',
2395
2614
  T: 5 /*ScalarType.INT32*/,
2396
2615
  },
2616
+ {
2617
+ no: 4,
2618
+ name: 'publish_options',
2619
+ kind: 'message',
2620
+ T: () => PublishOptions,
2621
+ },
2397
2622
  ]);
2398
2623
  }
2399
2624
  }
@@ -2704,7 +2929,9 @@ var events = /*#__PURE__*/Object.freeze({
2704
2929
  AudioSender: AudioSender,
2705
2930
  CallEnded: CallEnded,
2706
2931
  CallGrantsUpdated: CallGrantsUpdated,
2932
+ ChangePublishOptions: ChangePublishOptions,
2707
2933
  ChangePublishQuality: ChangePublishQuality,
2934
+ CodecNegotiationComplete: CodecNegotiationComplete,
2708
2935
  ConnectionQualityChanged: ConnectionQualityChanged,
2709
2936
  ConnectionQualityInfo: ConnectionQualityInfo,
2710
2937
  DominantSpeakerChanged: DominantSpeakerChanged,
@@ -3108,7 +3335,7 @@ const retryable = async (rpc, signal) => {
3108
3335
  return result;
3109
3336
  };
3110
3337
 
3111
- const version = "1.10.4";
3338
+ const version = "1.11.0";
3112
3339
  const [major, minor, patch] = version.split('.');
3113
3340
  let sdkInfo = {
3114
3341
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -3357,6 +3584,8 @@ const sfuEventKinds = {
3357
3584
  callEnded: undefined,
3358
3585
  participantUpdated: undefined,
3359
3586
  participantMigrationComplete: undefined,
3587
+ codecNegotiationComplete: undefined,
3588
+ changePublishOptions: undefined,
3360
3589
  };
3361
3590
  const isSfuEvent = (eventName) => {
3362
3591
  return Object.prototype.hasOwnProperty.call(sfuEventKinds, eventName);
@@ -3541,7 +3770,8 @@ const findOptimalVideoLayers = (videoTrack, targetResolution = defaultTargetReso
3541
3770
  let downscaleFactor = 1;
3542
3771
  let bitrateFactor = 1;
3543
3772
  const svcCodec = isSvcCodec(codecInUse);
3544
- for (const rid of ['f', 'h', 'q'].slice(0, Math.min(3, maxSimulcastLayers))) {
3773
+ const totalLayers = svcCodec ? 3 : Math.min(3, maxSimulcastLayers);
3774
+ for (const rid of ['f', 'h', 'q'].slice(0, totalLayers)) {
3545
3775
  const layer = {
3546
3776
  active: true,
3547
3777
  rid,
@@ -7161,7 +7391,10 @@ class SfuStatsReporter {
7161
7391
  });
7162
7392
  });
7163
7393
  };
7164
- this.run = async () => {
7394
+ this.sendTelemetryData = async (telemetryData) => {
7395
+ return this.run(telemetryData);
7396
+ };
7397
+ this.run = async (telemetryData) => {
7165
7398
  const [subscriberStats, publisherStats] = await Promise.all([
7166
7399
  this.subscriber.getStats().then(flatten).then(JSON.stringify),
7167
7400
  this.publisher?.getStats().then(flatten).then(JSON.stringify) ?? '[]',
@@ -7175,6 +7408,7 @@ class SfuStatsReporter {
7175
7408
  audioDevices: this.inputDevices.get('mic'),
7176
7409
  videoDevices: this.inputDevices.get('camera'),
7177
7410
  deviceState: { oneofKind: undefined },
7411
+ telemetry: telemetryData,
7178
7412
  });
7179
7413
  };
7180
7414
  this.start = () => {
@@ -9802,6 +10036,7 @@ class Call {
9802
10036
  * @returns a promise which resolves once the call join-flow has finished.
9803
10037
  */
9804
10038
  this.join = async (data) => {
10039
+ const connectStartTime = Date.now();
9805
10040
  await this.setup();
9806
10041
  const callingState = this.state.callingState;
9807
10042
  if ([CallingState.JOINED, CallingState.JOINING].includes(callingState)) {
@@ -9858,6 +10093,7 @@ class Call {
9858
10093
  : undefined;
9859
10094
  const { callState, fastReconnectDeadlineSeconds } = await sfuClient.join({
9860
10095
  subscriberSdp: receivingCapabilitiesSdp,
10096
+ publisherSdp: '',
9861
10097
  clientDetails,
9862
10098
  fastReconnect: performingFastReconnect,
9863
10099
  reconnectDetails,
@@ -9889,6 +10125,15 @@ class Call {
9889
10125
  closePreviousInstances: !performingMigration,
9890
10126
  });
9891
10127
  }
10128
+ // make sure we only track connection timing if we are not calling this method as part of a reconnection flow
10129
+ if (!performingRejoin && !performingFastReconnect && !performingMigration) {
10130
+ this.sfuStatsReporter?.sendTelemetryData({
10131
+ data: {
10132
+ oneofKind: 'connectionTimeSeconds',
10133
+ connectionTimeSeconds: (Date.now() - connectStartTime) / 1000,
10134
+ },
10135
+ });
10136
+ }
9892
10137
  if (performingRejoin) {
9893
10138
  const strategy = WebsocketReconnectStrategy[this.reconnectStrategy];
9894
10139
  await previousSfuClient?.leaveAndClose(`Closing previous WS after reconnect with strategy: ${strategy}`);
@@ -10121,26 +10366,47 @@ class Call {
10121
10366
  * @internal
10122
10367
  */
10123
10368
  this.reconnectFast = async () => {
10369
+ let reconnectStartTime = Date.now();
10124
10370
  this.reconnectStrategy = WebsocketReconnectStrategy.FAST;
10125
10371
  this.state.setCallingState(CallingState.RECONNECTING);
10126
- return this.join(this.joinCallData);
10372
+ await this.join(this.joinCallData);
10373
+ this.sfuStatsReporter?.sendTelemetryData({
10374
+ data: {
10375
+ oneofKind: 'reconnection',
10376
+ reconnection: {
10377
+ timeSeconds: (Date.now() - reconnectStartTime) / 1000,
10378
+ strategy: WebsocketReconnectStrategy.FAST,
10379
+ },
10380
+ },
10381
+ });
10127
10382
  };
10128
10383
  /**
10129
10384
  * Initiates the reconnection flow with the "rejoin" strategy.
10130
10385
  * @internal
10131
10386
  */
10132
10387
  this.reconnectRejoin = async () => {
10388
+ let reconnectStartTime = Date.now();
10133
10389
  this.reconnectStrategy = WebsocketReconnectStrategy.REJOIN;
10134
10390
  this.state.setCallingState(CallingState.RECONNECTING);
10135
10391
  await this.join(this.joinCallData);
10136
10392
  await this.restorePublishedTracks();
10137
10393
  this.restoreSubscribedTracks();
10394
+ this.sfuStatsReporter?.sendTelemetryData({
10395
+ data: {
10396
+ oneofKind: 'reconnection',
10397
+ reconnection: {
10398
+ timeSeconds: (Date.now() - reconnectStartTime) / 1000,
10399
+ strategy: WebsocketReconnectStrategy.REJOIN,
10400
+ },
10401
+ },
10402
+ });
10138
10403
  };
10139
10404
  /**
10140
10405
  * Initiates the reconnection flow with the "migrate" strategy.
10141
10406
  * @internal
10142
10407
  */
10143
10408
  this.reconnectMigrate = async () => {
10409
+ let reconnectStartTime = Date.now();
10144
10410
  const currentSfuClient = this.sfuClient;
10145
10411
  if (!currentSfuClient) {
10146
10412
  throw new Error('Cannot migrate without an active SFU client');
@@ -10179,6 +10445,15 @@ class Call {
10179
10445
  // and close the previous SFU client, without specifying close code
10180
10446
  currentSfuClient.close();
10181
10447
  }
10448
+ this.sfuStatsReporter?.sendTelemetryData({
10449
+ data: {
10450
+ oneofKind: 'reconnection',
10451
+ reconnection: {
10452
+ timeSeconds: (Date.now() - reconnectStartTime) / 1000,
10453
+ strategy: WebsocketReconnectStrategy.MIGRATE,
10454
+ },
10455
+ },
10456
+ });
10182
10457
  };
10183
10458
  /**
10184
10459
  * Registers the various event handlers for reconnection.
@@ -12702,7 +12977,7 @@ class StreamClient {
12702
12977
  });
12703
12978
  };
12704
12979
  this.getUserAgent = () => {
12705
- const version = "1.10.4";
12980
+ const version = "1.11.0";
12706
12981
  return (this.userAgent ||
12707
12982
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
12708
12983
  };