@stream-io/video-client 1.41.2 → 1.41.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.
- package/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +47 -21
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +47 -21
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +47 -21
- package/dist/index.es.js.map +1 -1
- package/dist/src/stats/SfuStatsReporter.d.ts +2 -1
- package/dist/src/stats/types.d.ts +10 -0
- package/package.json +1 -1
- package/src/Call.ts +5 -9
- package/src/stats/CallStateStatsReporter.ts +22 -0
- package/src/stats/SfuStatsReporter.ts +22 -14
- package/src/stats/types.ts +11 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.41.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.41.2...@stream-io/video-client-1.41.3) (2026-01-30)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **react:** improve logic for calculating the lower / upper threshold for video filter degradation ([#2094](https://github.com/GetStream/stream-video-js/issues/2094)) ([5cd2d5c](https://github.com/GetStream/stream-video-js/commit/5cd2d5cb34fc7bbdfaf9529eb9f8d33a40346cab))
|
|
10
|
+
- **stats:** adjust send stats frequency and include "leave reason" ([#2104](https://github.com/GetStream/stream-video-js/issues/2104)) ([0182832](https://github.com/GetStream/stream-video-js/commit/018283299bebe5d5078d4006ec86b6cd56884e77))
|
|
11
|
+
|
|
5
12
|
## [1.41.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.41.1...@stream-io/video-client-1.41.2) (2026-01-28)
|
|
6
13
|
|
|
7
14
|
- deduplicate RN compatibility assertions ([#2101](https://github.com/GetStream/stream-video-js/issues/2101)) ([5b9e6bc](https://github.com/GetStream/stream-video-js/commit/5b9e6bc227c55b067eea6345315bca015c8a7ee4))
|
package/dist/index.browser.es.js
CHANGED
|
@@ -6188,7 +6188,7 @@ const getSdkVersion = (sdk) => {
|
|
|
6188
6188
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
6189
6189
|
};
|
|
6190
6190
|
|
|
6191
|
-
const version = "1.41.
|
|
6191
|
+
const version = "1.41.3";
|
|
6192
6192
|
const [major, minor, patch] = version.split('.');
|
|
6193
6193
|
let sdkInfo = {
|
|
6194
6194
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -6511,6 +6511,16 @@ const createStatsReporter = ({ subscriber, publisher, state, datacenter, polling
|
|
|
6511
6511
|
stop,
|
|
6512
6512
|
};
|
|
6513
6513
|
};
|
|
6514
|
+
/**
|
|
6515
|
+
* Extracts camera statistics from a media source.
|
|
6516
|
+
*
|
|
6517
|
+
* @param mediaSource the media source stats to extract camera info from.
|
|
6518
|
+
*/
|
|
6519
|
+
const getCameraStats = (mediaSource) => ({
|
|
6520
|
+
frameRate: mediaSource.framesPerSecond,
|
|
6521
|
+
frameWidth: mediaSource.width,
|
|
6522
|
+
frameHeight: mediaSource.height,
|
|
6523
|
+
});
|
|
6514
6524
|
/**
|
|
6515
6525
|
* Transforms raw RTC stats into a slimmer and uniform across browsers format.
|
|
6516
6526
|
*
|
|
@@ -6536,6 +6546,7 @@ const transform = (report, opts) => {
|
|
|
6536
6546
|
}
|
|
6537
6547
|
let trackType;
|
|
6538
6548
|
let audioLevel;
|
|
6549
|
+
let camera;
|
|
6539
6550
|
let concealedSamples;
|
|
6540
6551
|
let concealmentEvents;
|
|
6541
6552
|
let packetsReceived;
|
|
@@ -6551,6 +6562,9 @@ const transform = (report, opts) => {
|
|
|
6551
6562
|
typeof mediaSource.audioLevel === 'number') {
|
|
6552
6563
|
audioLevel = mediaSource.audioLevel;
|
|
6553
6564
|
}
|
|
6565
|
+
if (trackKind === 'video') {
|
|
6566
|
+
camera = getCameraStats(mediaSource);
|
|
6567
|
+
}
|
|
6554
6568
|
}
|
|
6555
6569
|
}
|
|
6556
6570
|
else if (kind === 'subscriber' && trackKind === 'audio') {
|
|
@@ -6584,6 +6598,7 @@ const transform = (report, opts) => {
|
|
|
6584
6598
|
concealmentEvents,
|
|
6585
6599
|
packetsReceived,
|
|
6586
6600
|
packetsLost,
|
|
6601
|
+
camera,
|
|
6587
6602
|
};
|
|
6588
6603
|
});
|
|
6589
6604
|
return {
|
|
@@ -6603,6 +6618,7 @@ const getEmptyVideoStats = (stats) => {
|
|
|
6603
6618
|
highestFrameWidth: 0,
|
|
6604
6619
|
highestFrameHeight: 0,
|
|
6605
6620
|
highestFramesPerSecond: 0,
|
|
6621
|
+
camera: {},
|
|
6606
6622
|
codec: '',
|
|
6607
6623
|
codecPerTrackType: {},
|
|
6608
6624
|
timestamp: Date.now(),
|
|
@@ -6647,6 +6663,9 @@ const aggregate = (stats) => {
|
|
|
6647
6663
|
acc.highestFramesPerSecond = stream.framesPerSecond || 0;
|
|
6648
6664
|
maxArea = streamArea;
|
|
6649
6665
|
}
|
|
6666
|
+
if (stream.trackType === TrackType.VIDEO) {
|
|
6667
|
+
acc.camera = stream.camera;
|
|
6668
|
+
}
|
|
6650
6669
|
qualityLimitationReasons.add(stream.qualityLimitationReason || '');
|
|
6651
6670
|
return acc;
|
|
6652
6671
|
}, aggregatedStats);
|
|
@@ -6711,6 +6730,7 @@ const aggregateAudio = (stats) => {
|
|
|
6711
6730
|
class SfuStatsReporter {
|
|
6712
6731
|
constructor(sfuClient, { options, clientDetails, subscriber, publisher, microphone, camera, state, tracer, unifiedSessionId, }) {
|
|
6713
6732
|
this.logger = videoLoggerSystem.getLogger('SfuStatsReporter');
|
|
6733
|
+
this.reportCount = 0;
|
|
6714
6734
|
this.inputDevices = new Map();
|
|
6715
6735
|
this.observeDevice = (device, kind) => {
|
|
6716
6736
|
const { browserPermissionState$ } = device.state;
|
|
@@ -6812,17 +6832,31 @@ class SfuStatsReporter {
|
|
|
6812
6832
|
throw err;
|
|
6813
6833
|
}
|
|
6814
6834
|
};
|
|
6835
|
+
this.scheduleNextReport = () => {
|
|
6836
|
+
const intervals = [1500, 3000, 3000, 5000];
|
|
6837
|
+
if (this.reportCount < intervals.length) {
|
|
6838
|
+
this.timeoutId = setTimeout(() => {
|
|
6839
|
+
this.flush();
|
|
6840
|
+
this.reportCount++;
|
|
6841
|
+
this.scheduleNextReport();
|
|
6842
|
+
}, intervals[this.reportCount]);
|
|
6843
|
+
}
|
|
6844
|
+
else {
|
|
6845
|
+
clearInterval(this.intervalId);
|
|
6846
|
+
this.intervalId = setInterval(() => {
|
|
6847
|
+
this.flush();
|
|
6848
|
+
}, this.options.reporting_interval_ms);
|
|
6849
|
+
}
|
|
6850
|
+
};
|
|
6815
6851
|
this.start = () => {
|
|
6816
6852
|
if (this.options.reporting_interval_ms <= 0)
|
|
6817
6853
|
return;
|
|
6818
6854
|
this.observeDevice(this.microphone, 'mic');
|
|
6819
6855
|
this.observeDevice(this.camera, 'camera');
|
|
6856
|
+
this.reportCount = 0;
|
|
6820
6857
|
clearInterval(this.intervalId);
|
|
6821
|
-
this.
|
|
6822
|
-
|
|
6823
|
-
this.logger.warn('Failed to report stats', err);
|
|
6824
|
-
});
|
|
6825
|
-
}, this.options.reporting_interval_ms);
|
|
6858
|
+
clearTimeout(this.timeoutId);
|
|
6859
|
+
this.scheduleNextReport();
|
|
6826
6860
|
};
|
|
6827
6861
|
this.stop = () => {
|
|
6828
6862
|
this.unsubscribeDevicePermissionsSubscription?.();
|
|
@@ -6834,20 +6868,13 @@ class SfuStatsReporter {
|
|
|
6834
6868
|
this.intervalId = undefined;
|
|
6835
6869
|
clearTimeout(this.timeoutId);
|
|
6836
6870
|
this.timeoutId = undefined;
|
|
6871
|
+
this.reportCount = 0;
|
|
6837
6872
|
};
|
|
6838
6873
|
this.flush = () => {
|
|
6839
6874
|
this.run().catch((err) => {
|
|
6840
6875
|
this.logger.warn('Failed to flush report stats', err);
|
|
6841
6876
|
});
|
|
6842
6877
|
};
|
|
6843
|
-
this.scheduleOne = (timeout) => {
|
|
6844
|
-
clearTimeout(this.timeoutId);
|
|
6845
|
-
this.timeoutId = setTimeout(() => {
|
|
6846
|
-
this.run().catch((err) => {
|
|
6847
|
-
this.logger.warn('Failed to report stats', err);
|
|
6848
|
-
});
|
|
6849
|
-
}, timeout);
|
|
6850
|
-
};
|
|
6851
6878
|
this.sfuClient = sfuClient;
|
|
6852
6879
|
this.options = options;
|
|
6853
6880
|
this.subscriber = subscriber;
|
|
@@ -12447,6 +12474,8 @@ class Call {
|
|
|
12447
12474
|
}
|
|
12448
12475
|
this.statsReporter?.stop();
|
|
12449
12476
|
this.statsReporter = undefined;
|
|
12477
|
+
const leaveReason = message ?? reason ?? 'user is leaving the call';
|
|
12478
|
+
this.tracer.trace('call.leaveReason', leaveReason);
|
|
12450
12479
|
this.sfuStatsReporter?.flush();
|
|
12451
12480
|
this.sfuStatsReporter?.stop();
|
|
12452
12481
|
this.sfuStatsReporter = undefined;
|
|
@@ -12454,7 +12483,7 @@ class Call {
|
|
|
12454
12483
|
this.subscriber = undefined;
|
|
12455
12484
|
this.publisher?.dispose();
|
|
12456
12485
|
this.publisher = undefined;
|
|
12457
|
-
await this.sfuClient?.leaveAndClose(
|
|
12486
|
+
await this.sfuClient?.leaveAndClose(leaveReason);
|
|
12458
12487
|
this.sfuClient = undefined;
|
|
12459
12488
|
this.dynascaleManager.setSfuClient(undefined);
|
|
12460
12489
|
await this.dynascaleManager.dispose();
|
|
@@ -12596,6 +12625,7 @@ class Call {
|
|
|
12596
12625
|
* Unless you are implementing a custom "ringing" flow, you should not use this method.
|
|
12597
12626
|
*/
|
|
12598
12627
|
this.accept = async () => {
|
|
12628
|
+
this.tracer.trace('call.accept', '');
|
|
12599
12629
|
return this.streamClient.post(`${this.streamClientBasePath}/accept`);
|
|
12600
12630
|
};
|
|
12601
12631
|
/**
|
|
@@ -12608,6 +12638,7 @@ class Call {
|
|
|
12608
12638
|
* @param reason the reason for rejecting the call.
|
|
12609
12639
|
*/
|
|
12610
12640
|
this.reject = async (reason = 'decline') => {
|
|
12641
|
+
this.tracer.trace('call.reject', reason);
|
|
12611
12642
|
return this.streamClient.post(`${this.streamClientBasePath}/reject`, { reason: reason });
|
|
12612
12643
|
};
|
|
12613
12644
|
/**
|
|
@@ -13371,11 +13402,6 @@ class Call {
|
|
|
13371
13402
|
trackTypes.push(screenShareAudio);
|
|
13372
13403
|
}
|
|
13373
13404
|
}
|
|
13374
|
-
if (track.kind === 'video') {
|
|
13375
|
-
// schedules calibration report - the SFU will use the performance stats
|
|
13376
|
-
// to adjust the quality thresholds as early as possible
|
|
13377
|
-
this.sfuStatsReporter?.scheduleOne(3000);
|
|
13378
|
-
}
|
|
13379
13405
|
await this.updateLocalStreamState(mediaStream, ...trackTypes);
|
|
13380
13406
|
};
|
|
13381
13407
|
/**
|
|
@@ -15320,7 +15346,7 @@ class StreamClient {
|
|
|
15320
15346
|
this.getUserAgent = () => {
|
|
15321
15347
|
if (!this.cachedUserAgent) {
|
|
15322
15348
|
const { clientAppIdentifier = {} } = this.options;
|
|
15323
|
-
const { sdkName = 'js', sdkVersion = "1.41.
|
|
15349
|
+
const { sdkName = 'js', sdkVersion = "1.41.3", ...extras } = clientAppIdentifier;
|
|
15324
15350
|
this.cachedUserAgent = [
|
|
15325
15351
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
15326
15352
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|