@stream-io/video-client 1.37.3 → 1.38.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 +7 -0
- package/dist/index.browser.es.js +116 -13
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +116 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +116 -13
- package/dist/index.es.js.map +1 -1
- package/dist/src/helpers/humanize.d.ts +4 -0
- package/dist/src/stats/types.d.ts +32 -2
- package/index.ts +1 -0
- package/package.json +1 -1
- package/src/devices/DeviceManager.ts +0 -1
- package/src/helpers/__tests__/humanize.test.ts +41 -0
- package/src/helpers/humanize.ts +20 -0
- package/src/stats/CallStateStatsReporter.ts +111 -10
- package/src/stats/types.ts +33 -2
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from './src/devices';
|
|
|
13
13
|
export * from './src/store';
|
|
14
14
|
export * from './src/sorting';
|
|
15
15
|
export * from './src/helpers/client-details';
|
|
16
|
+
export * from './src/helpers/humanize';
|
|
16
17
|
export * from './src/helpers/DynascaleManager';
|
|
17
18
|
export * from './src/helpers/ViewportTracker';
|
|
18
19
|
export * from './src/helpers/sound-detector';
|
package/dist/index.es.js
CHANGED
|
@@ -6001,7 +6001,7 @@ const getSdkVersion = (sdk) => {
|
|
|
6001
6001
|
return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
|
|
6002
6002
|
};
|
|
6003
6003
|
|
|
6004
|
-
const version = "1.
|
|
6004
|
+
const version = "1.38.0";
|
|
6005
6005
|
const [major, minor, patch] = version.split('.');
|
|
6006
6006
|
let sdkInfo = {
|
|
6007
6007
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -6271,17 +6271,26 @@ const createStatsReporter = ({ subscriber, publisher, state, datacenter, polling
|
|
|
6271
6271
|
getRawStatsForTrack('subscriber'),
|
|
6272
6272
|
publisher ? getRawStatsForTrack('publisher') : undefined,
|
|
6273
6273
|
]);
|
|
6274
|
-
const process = (report, kind) =>
|
|
6275
|
-
|
|
6274
|
+
const process = (report, kind) => {
|
|
6275
|
+
const videoStats = aggregate(transform(report, { kind, trackKind: 'video', publisher }));
|
|
6276
|
+
const audioStats = aggregateAudio(transform(report, { kind, trackKind: 'audio', publisher }));
|
|
6277
|
+
return {
|
|
6278
|
+
videoStats,
|
|
6279
|
+
audioStats,
|
|
6280
|
+
};
|
|
6281
|
+
};
|
|
6282
|
+
const subscriberResult = subscriberRawStats
|
|
6276
6283
|
? process(subscriberRawStats, 'subscriber')
|
|
6277
|
-
:
|
|
6278
|
-
const
|
|
6284
|
+
: { videoStats: getEmptyVideoStats(), audioStats: getEmptyAudioStats() };
|
|
6285
|
+
const publisherResult = publisherRawStats
|
|
6279
6286
|
? process(publisherRawStats, 'publisher')
|
|
6280
|
-
:
|
|
6287
|
+
: { videoStats: getEmptyVideoStats(), audioStats: getEmptyAudioStats() };
|
|
6281
6288
|
state.setCallStatsReport({
|
|
6282
6289
|
datacenter,
|
|
6283
|
-
publisherStats,
|
|
6284
|
-
|
|
6290
|
+
publisherStats: publisherResult.videoStats,
|
|
6291
|
+
publisherAudioStats: publisherResult.audioStats,
|
|
6292
|
+
subscriberStats: subscriberResult.videoStats,
|
|
6293
|
+
subscriberAudioStats: subscriberResult.audioStats,
|
|
6285
6294
|
subscriberRawStats,
|
|
6286
6295
|
publisherRawStats,
|
|
6287
6296
|
participants: participantStats,
|
|
@@ -6339,6 +6348,11 @@ const transform = (report, opts) => {
|
|
|
6339
6348
|
roundTripTime = candidatePair?.currentRoundTripTime;
|
|
6340
6349
|
}
|
|
6341
6350
|
let trackType;
|
|
6351
|
+
let audioLevel;
|
|
6352
|
+
let concealedSamples;
|
|
6353
|
+
let concealmentEvents;
|
|
6354
|
+
let packetsReceived;
|
|
6355
|
+
let packetsLost;
|
|
6342
6356
|
if (kind === 'publisher' && publisher) {
|
|
6343
6357
|
const firefox = isFirefox();
|
|
6344
6358
|
const mediaSource = stats.find((s) => s.type === 'media-source' &&
|
|
@@ -6346,7 +6360,22 @@ const transform = (report, opts) => {
|
|
|
6346
6360
|
(firefox ? true : s.id === rtcStreamStats.mediaSourceId));
|
|
6347
6361
|
if (mediaSource) {
|
|
6348
6362
|
trackType = publisher.getTrackType(mediaSource.trackIdentifier);
|
|
6363
|
+
if (trackKind === 'audio' &&
|
|
6364
|
+
typeof mediaSource.audioLevel === 'number') {
|
|
6365
|
+
audioLevel = mediaSource.audioLevel;
|
|
6366
|
+
}
|
|
6367
|
+
}
|
|
6368
|
+
}
|
|
6369
|
+
else if (kind === 'subscriber' && trackKind === 'audio') {
|
|
6370
|
+
const inboundStats = rtcStreamStats;
|
|
6371
|
+
const inboundLevel = inboundStats.audioLevel;
|
|
6372
|
+
if (typeof inboundLevel === 'number') {
|
|
6373
|
+
audioLevel = inboundLevel;
|
|
6349
6374
|
}
|
|
6375
|
+
concealedSamples = inboundStats.concealedSamples;
|
|
6376
|
+
concealmentEvents = inboundStats.concealmentEvents;
|
|
6377
|
+
packetsReceived = inboundStats.packetsReceived;
|
|
6378
|
+
packetsLost = inboundStats.packetsLost;
|
|
6350
6379
|
}
|
|
6351
6380
|
return {
|
|
6352
6381
|
bytesSent: rtcStreamStats.bytesSent,
|
|
@@ -6363,6 +6392,11 @@ const transform = (report, opts) => {
|
|
|
6363
6392
|
rid: rtcStreamStats.rid,
|
|
6364
6393
|
ssrc: rtcStreamStats.ssrc,
|
|
6365
6394
|
trackType,
|
|
6395
|
+
audioLevel,
|
|
6396
|
+
concealedSamples,
|
|
6397
|
+
concealmentEvents,
|
|
6398
|
+
packetsReceived,
|
|
6399
|
+
packetsLost,
|
|
6366
6400
|
};
|
|
6367
6401
|
});
|
|
6368
6402
|
return {
|
|
@@ -6371,7 +6405,7 @@ const transform = (report, opts) => {
|
|
|
6371
6405
|
timestamp: Date.now(),
|
|
6372
6406
|
};
|
|
6373
6407
|
};
|
|
6374
|
-
const
|
|
6408
|
+
const getEmptyVideoStats = (stats) => {
|
|
6375
6409
|
return {
|
|
6376
6410
|
rawReport: stats ?? { streams: [], timestamp: Date.now() },
|
|
6377
6411
|
totalBytesSent: 0,
|
|
@@ -6387,13 +6421,28 @@ const getEmptyStats = (stats) => {
|
|
|
6387
6421
|
timestamp: Date.now(),
|
|
6388
6422
|
};
|
|
6389
6423
|
};
|
|
6424
|
+
const getEmptyAudioStats = () => {
|
|
6425
|
+
return {
|
|
6426
|
+
totalBytesSent: 0,
|
|
6427
|
+
totalBytesReceived: 0,
|
|
6428
|
+
averageJitterInMs: 0,
|
|
6429
|
+
averageRoundTripTimeInMs: 0,
|
|
6430
|
+
codec: '',
|
|
6431
|
+
codecPerTrackType: {},
|
|
6432
|
+
timestamp: Date.now(),
|
|
6433
|
+
totalConcealedSamples: 0,
|
|
6434
|
+
totalConcealmentEvents: 0,
|
|
6435
|
+
totalPacketsReceived: 0,
|
|
6436
|
+
totalPacketsLost: 0,
|
|
6437
|
+
};
|
|
6438
|
+
};
|
|
6390
6439
|
/**
|
|
6391
6440
|
* Aggregates generic stats.
|
|
6392
6441
|
*
|
|
6393
6442
|
* @param stats the stats to aggregate.
|
|
6394
6443
|
*/
|
|
6395
6444
|
const aggregate = (stats) => {
|
|
6396
|
-
const aggregatedStats =
|
|
6445
|
+
const aggregatedStats = getEmptyVideoStats(stats);
|
|
6397
6446
|
let maxArea = -1;
|
|
6398
6447
|
const area = (w, h) => w * h;
|
|
6399
6448
|
const qualityLimitationReasons = new Set();
|
|
@@ -6438,6 +6487,39 @@ const aggregate = (stats) => {
|
|
|
6438
6487
|
}
|
|
6439
6488
|
return report;
|
|
6440
6489
|
};
|
|
6490
|
+
/**
|
|
6491
|
+
* Aggregates audio stats from a stats report.
|
|
6492
|
+
*
|
|
6493
|
+
* @param stats the stats report containing audio streams.
|
|
6494
|
+
* @returns aggregated audio stats.
|
|
6495
|
+
*/
|
|
6496
|
+
const aggregateAudio = (stats) => {
|
|
6497
|
+
const streams = stats.streams;
|
|
6498
|
+
const audioStats = getEmptyAudioStats();
|
|
6499
|
+
const report = streams.reduce((acc, stream) => {
|
|
6500
|
+
acc.totalBytesSent += stream.bytesSent || 0;
|
|
6501
|
+
acc.totalBytesReceived += stream.bytesReceived || 0;
|
|
6502
|
+
acc.averageJitterInMs += stream.jitter || 0;
|
|
6503
|
+
acc.averageRoundTripTimeInMs += stream.currentRoundTripTime || 0;
|
|
6504
|
+
acc.totalConcealedSamples += stream.concealedSamples || 0;
|
|
6505
|
+
acc.totalConcealmentEvents += stream.concealmentEvents || 0;
|
|
6506
|
+
acc.totalPacketsReceived += stream.packetsReceived || 0;
|
|
6507
|
+
acc.totalPacketsLost += stream.packetsLost || 0;
|
|
6508
|
+
return acc;
|
|
6509
|
+
}, audioStats);
|
|
6510
|
+
if (streams.length > 0) {
|
|
6511
|
+
report.averageJitterInMs = Math.round((report.averageJitterInMs / streams.length) * 1000);
|
|
6512
|
+
report.averageRoundTripTimeInMs = Math.round((report.averageRoundTripTimeInMs / streams.length) * 1000);
|
|
6513
|
+
report.codec = streams[0].codec || '';
|
|
6514
|
+
report.codecPerTrackType = streams.reduce((acc, stream) => {
|
|
6515
|
+
if (stream.trackType) {
|
|
6516
|
+
acc[stream.trackType] = stream.codec || '';
|
|
6517
|
+
}
|
|
6518
|
+
return acc;
|
|
6519
|
+
}, {});
|
|
6520
|
+
}
|
|
6521
|
+
return report;
|
|
6522
|
+
};
|
|
6441
6523
|
|
|
6442
6524
|
class SfuStatsReporter {
|
|
6443
6525
|
constructor(sfuClient, { options, clientDetails, subscriber, publisher, microphone, camera, state, tracer, unifiedSessionId, }) {
|
|
@@ -10321,7 +10403,6 @@ class DeviceManager {
|
|
|
10321
10403
|
}
|
|
10322
10404
|
}
|
|
10323
10405
|
async applySettingsToStream() {
|
|
10324
|
-
console.log('applySettingsToStream ');
|
|
10325
10406
|
await withCancellation(this.statusChangeConcurrencyTag, async (signal) => {
|
|
10326
10407
|
if (this.enabled) {
|
|
10327
10408
|
try {
|
|
@@ -14917,7 +14998,7 @@ class StreamClient {
|
|
|
14917
14998
|
this.getUserAgent = () => {
|
|
14918
14999
|
if (!this.cachedUserAgent) {
|
|
14919
15000
|
const { clientAppIdentifier = {} } = this.options;
|
|
14920
|
-
const { sdkName = 'js', sdkVersion = "1.
|
|
15001
|
+
const { sdkName = 'js', sdkVersion = "1.38.0", ...extras } = clientAppIdentifier;
|
|
14921
15002
|
this.cachedUserAgent = [
|
|
14922
15003
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
14923
15004
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|
|
@@ -15509,5 +15590,27 @@ class StreamVideoClient {
|
|
|
15509
15590
|
}
|
|
15510
15591
|
StreamVideoClient._instances = new Map();
|
|
15511
15592
|
|
|
15512
|
-
|
|
15593
|
+
/**
|
|
15594
|
+
* Formats large numbers into a compact, human-friendly form: 1k, 1.5k, 2M, etc.
|
|
15595
|
+
*/
|
|
15596
|
+
const humanize = (n) => {
|
|
15597
|
+
if (n < 1000)
|
|
15598
|
+
return String(n);
|
|
15599
|
+
const units = [
|
|
15600
|
+
{ value: 1000000000, suffix: 'B' },
|
|
15601
|
+
{ value: 1000000, suffix: 'M' },
|
|
15602
|
+
{ value: 1000, suffix: 'k' },
|
|
15603
|
+
];
|
|
15604
|
+
for (const { value, suffix } of units) {
|
|
15605
|
+
if (n >= value) {
|
|
15606
|
+
const num = n / value;
|
|
15607
|
+
const precision = num < 100 ? 1 : 0; // show one decimal only for small leading numbers
|
|
15608
|
+
const formatted = num.toFixed(precision).replace(/\.0$/g, '');
|
|
15609
|
+
return `${formatted}${suffix}`;
|
|
15610
|
+
}
|
|
15611
|
+
}
|
|
15612
|
+
return String(n);
|
|
15613
|
+
};
|
|
15614
|
+
|
|
15615
|
+
export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DeviceManager, DeviceManagerState, DynascaleManager, ErrorFromResponse, FrameRecordingSettingsRequestModeEnum, FrameRecordingSettingsRequestQualityEnum, FrameRecordingSettingsResponseModeEnum, IngressAudioEncodingOptionsRequestChannelsEnum, IngressSourceRequestFpsEnum, IngressVideoLayerRequestCodecEnum, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RNSpeechDetector, RTMPBroadcastRequestQualityEnum, RTMPSettingsRequestQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StartClosedCaptionsRequestLanguageEnum, StartTranscriptionRequestLanguageEnum, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestClosedCaptionModeEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseClosedCaptionModeEnum, TranscriptionSettingsResponseLanguageEnum, TranscriptionSettingsResponseModeEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceState, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio, hasPausedTrack, hasScreenShare, hasScreenShareAudio, hasVideo, humanize, isPinned, livestreamOrAudioRoomSortPreset, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, resolveDeviceId, role, screenSharing, setDeviceInfo, setOSInfo, setPowerState, setSdkInfo, setThermalState, setWebRTCInfo, speakerLayoutSortPreset, speaking, videoLoggerSystem, withParticipantSource };
|
|
15513
15616
|
//# sourceMappingURL=index.es.js.map
|