@voltkit-rtc/client 0.6.0 → 0.6.1
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 +8 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +9 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/stats.d.ts +16 -2
- package/dist/cjs/stats.d.ts.map +1 -1
- package/dist/cjs/stats.js +53 -5
- package/dist/cjs/stats.js.map +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +9 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/stats.d.ts +16 -2
- package/dist/esm/stats.d.ts.map +1 -1
- package/dist/esm/stats.js +53 -5
- package/dist/esm/stats.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +10 -6
- package/src/stats.ts +51 -6
package/dist/esm/stats.js
CHANGED
|
@@ -9,6 +9,10 @@ const oneDecimal = (value) => Math.round(value * 10) / 10;
|
|
|
9
9
|
*/
|
|
10
10
|
export function bitrateSince(baseline, key, bytes, timestamp) {
|
|
11
11
|
const previous = baseline.get(key);
|
|
12
|
+
// Concurrent getStats calls can complete out of order. Do not rewind the
|
|
13
|
+
// baseline and inflate the next reading (or overwrite it with a duplicate).
|
|
14
|
+
if (previous && timestamp <= previous.timestamp)
|
|
15
|
+
return 0;
|
|
12
16
|
baseline.set(key, { bytes, timestamp });
|
|
13
17
|
if (!previous)
|
|
14
18
|
return 0;
|
|
@@ -64,9 +68,13 @@ export function parseSendStats(report, options) {
|
|
|
64
68
|
byId.set(entry.id, entry);
|
|
65
69
|
}
|
|
66
70
|
const outbound = entries.filter((e) => e.type === 'outbound-rtp' && isVideo(e));
|
|
71
|
+
const keys = new Set();
|
|
67
72
|
const layers = outbound.map((entry) => {
|
|
68
73
|
const rid = optStr(entry.rid);
|
|
69
|
-
|
|
74
|
+
// A RID is a layer label, not a unique RTP stream. Reusing it with a new
|
|
75
|
+
// SSRC must start a fresh byte counter, even when the new count is higher.
|
|
76
|
+
const key = `${options.keyPrefix}${JSON.stringify([rid, entry.ssrc, entry.id])}`;
|
|
77
|
+
keys.add(key);
|
|
70
78
|
const bitrate = bitrateSince(options.baseline, key, num(entry.bytesSent), num(entry.timestamp));
|
|
71
79
|
const fps = oneDecimal(num(entry.framesPerSecond));
|
|
72
80
|
const reason = optStr(entry.qualityLimitationReason);
|
|
@@ -81,6 +89,7 @@ export function parseSendStats(report, options) {
|
|
|
81
89
|
entry,
|
|
82
90
|
};
|
|
83
91
|
});
|
|
92
|
+
pruneBaseline(options.baseline, (key) => !key.startsWith(options.keyPrefix) || keys.has(key));
|
|
84
93
|
layers.sort(layerOrder);
|
|
85
94
|
// The biggest layer going out is what the best-connected viewer gets. With
|
|
86
95
|
// nothing going out (paused, or the very first frames), the biggest there is.
|
|
@@ -88,6 +97,9 @@ export function parseSendStats(report, options) {
|
|
|
88
97
|
const top = pool.reduce((best, l) => (!best || area(l) > area(best) ? l : best), undefined);
|
|
89
98
|
const codec = codecOf(byId, top?.entry) ?? outbound.map((e) => codecOf(byId, e)).find(Boolean);
|
|
90
99
|
const available = availableOutgoing(entries, byId);
|
|
100
|
+
const source = typeof top?.entry.mediaSourceId === 'string' ? byId.get(top.entry.mediaSourceId) : undefined;
|
|
101
|
+
const encoder = optStr(top?.entry.encoderImplementation);
|
|
102
|
+
const efficient = top?.entry.powerEfficientEncoder;
|
|
91
103
|
return {
|
|
92
104
|
...(codec !== undefined ? { codec } : {}),
|
|
93
105
|
quality: options.quality,
|
|
@@ -97,6 +109,12 @@ export function parseSendStats(report, options) {
|
|
|
97
109
|
bitrate: top?.bitrate ?? 0,
|
|
98
110
|
...(top?.qualityLimitation !== undefined ? { qualityLimitation: top.qualityLimitation } : {}),
|
|
99
111
|
...(available !== undefined ? { availableOutgoingBitrate: available } : {}),
|
|
112
|
+
...(source?.type === 'media-source' && isVideo(source) ? { source: {
|
|
113
|
+
width: num(source.width), height: num(source.height),
|
|
114
|
+
...(optNum(source.framesPerSecond) !== undefined ? { fps: oneDecimal(num(source.framesPerSecond)) } : {}),
|
|
115
|
+
} } : {}),
|
|
116
|
+
...(encoder !== undefined ? { encoderImplementation: encoder } : {}),
|
|
117
|
+
...(typeof efficient === 'boolean' ? { powerEfficientEncoder: efficient } : {}),
|
|
100
118
|
layers: layers.map(({ entry: _entry, ...layer }) => layer),
|
|
101
119
|
};
|
|
102
120
|
}
|
|
@@ -174,14 +192,29 @@ export class VideoLimitWatch {
|
|
|
174
192
|
sample;
|
|
175
193
|
report;
|
|
176
194
|
intervalMs;
|
|
195
|
+
onSuspend;
|
|
177
196
|
timer = null;
|
|
178
197
|
tracker = initialLimitTracker();
|
|
179
198
|
sampling = false;
|
|
180
199
|
baseline = new Map();
|
|
181
|
-
|
|
200
|
+
generation = 0;
|
|
201
|
+
visibilityDocument;
|
|
202
|
+
warmup = 0;
|
|
203
|
+
visibilityChanged = () => {
|
|
204
|
+
this.generation++;
|
|
205
|
+
this.baseline = new Map();
|
|
206
|
+
const was = this.tracker.reported;
|
|
207
|
+
this.tracker = initialLimitTracker();
|
|
208
|
+
this.warmup = 2;
|
|
209
|
+
this.onSuspend();
|
|
210
|
+
if (was && was !== 'none')
|
|
211
|
+
this.report({ reason: 'none', width: 0, height: 0, fps: 0, bitrate: 0 });
|
|
212
|
+
};
|
|
213
|
+
constructor(sample, report, intervalMs = LIMIT_SAMPLE_MS, onSuspend = () => { }) {
|
|
182
214
|
this.sample = sample;
|
|
183
215
|
this.report = report;
|
|
184
216
|
this.intervalMs = intervalMs;
|
|
217
|
+
this.onSuspend = onSuspend;
|
|
185
218
|
}
|
|
186
219
|
get running() {
|
|
187
220
|
return this.timer !== null;
|
|
@@ -189,11 +222,18 @@ export class VideoLimitWatch {
|
|
|
189
222
|
/** Start or stop sampling. Safe to call as often as anything changes. */
|
|
190
223
|
set(wanted) {
|
|
191
224
|
if (wanted && !this.timer) {
|
|
225
|
+
this.visibilityDocument = typeof document !== 'undefined' ? document : undefined;
|
|
226
|
+
this.visibilityDocument?.addEventListener('visibilitychange', this.visibilityChanged);
|
|
227
|
+
if (this.visibilityDocument?.visibilityState === 'hidden')
|
|
228
|
+
this.visibilityChanged();
|
|
192
229
|
this.timer = setInterval(() => void this.tick(), this.intervalMs);
|
|
193
230
|
}
|
|
194
231
|
else if (!wanted && this.timer) {
|
|
195
232
|
clearInterval(this.timer);
|
|
196
233
|
this.timer = null;
|
|
234
|
+
this.generation++;
|
|
235
|
+
this.visibilityDocument?.removeEventListener('visibilitychange', this.visibilityChanged);
|
|
236
|
+
this.visibilityDocument = undefined;
|
|
197
237
|
}
|
|
198
238
|
}
|
|
199
239
|
/**
|
|
@@ -204,17 +244,25 @@ export class VideoLimitWatch {
|
|
|
204
244
|
this.set(false);
|
|
205
245
|
const was = this.tracker.reported;
|
|
206
246
|
this.tracker = initialLimitTracker();
|
|
207
|
-
this.baseline
|
|
247
|
+
this.baseline = new Map();
|
|
208
248
|
return was && was !== 'none' ? { reason: 'none', width: 0, height: 0, fps: 0, bitrate: 0 } : null;
|
|
209
249
|
}
|
|
210
250
|
async tick() {
|
|
211
251
|
// A slow getStats must not pile samples up behind it.
|
|
212
252
|
if (this.sampling)
|
|
213
253
|
return;
|
|
254
|
+
if (this.visibilityDocument?.visibilityState === 'hidden')
|
|
255
|
+
return;
|
|
256
|
+
if (this.warmup > 0) {
|
|
257
|
+
this.warmup--;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const generation = this.generation;
|
|
261
|
+
const isCurrent = () => this.timer !== null && generation === this.generation && this.visibilityDocument?.visibilityState !== 'hidden';
|
|
214
262
|
this.sampling = true;
|
|
215
263
|
try {
|
|
216
|
-
const stats = await this.sample(this.baseline);
|
|
217
|
-
if (!stats || !
|
|
264
|
+
const stats = await this.sample(this.baseline, isCurrent);
|
|
265
|
+
if (!stats || !isCurrent())
|
|
218
266
|
return;
|
|
219
267
|
const { tracker, report } = trackLimit(this.tracker, limitReasonOf(stats.layers));
|
|
220
268
|
this.tracker = tracker;
|
package/dist/esm/stats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/stats.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/stats.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -379,8 +379,10 @@ export class StreamClient {
|
|
|
379
379
|
private readonly sendStatsBaseline: StatsBaseline = new Map();
|
|
380
380
|
private readonly recvStatsBaseline: StatsBaseline = new Map();
|
|
381
381
|
private readonly limitWatch = new VideoLimitWatch(
|
|
382
|
-
(baseline) => this.sampleCamera(baseline),
|
|
382
|
+
(baseline, isCurrent) => this.sampleCamera(baseline, isCurrent),
|
|
383
383
|
(event) => this.emit('videoLimited', event),
|
|
384
|
+
undefined,
|
|
385
|
+
() => { this.frameRateLowSamples = 0; this.frameRateWarmupSamples = 2; },
|
|
384
386
|
);
|
|
385
387
|
|
|
386
388
|
constructor(private readonly wsUrl: string, token: string) {
|
|
@@ -984,7 +986,7 @@ export class StreamClient {
|
|
|
984
986
|
const current = this.cameraProducer();
|
|
985
987
|
const track = current?.track;
|
|
986
988
|
if (!current || !track || track.readyState !== 'live') return;
|
|
987
|
-
try { await track.applyConstraints?.({ frameRate: { ideal: frameRate, max: frameRate } }); }
|
|
989
|
+
try { await track.applyConstraints?.({ ...track.getConstraints?.(), frameRate: { ideal: frameRate, max: frameRate } }); }
|
|
988
990
|
catch { /* Existing capture settings decide whether 60 fps is possible. */ }
|
|
989
991
|
await this.reproduceCamera(current, track);
|
|
990
992
|
});
|
|
@@ -1522,8 +1524,10 @@ export class StreamClient {
|
|
|
1522
1524
|
return 60;
|
|
1523
1525
|
}
|
|
1524
1526
|
|
|
1525
|
-
private async sampleCamera(baseline: StatsBaseline): Promise<VideoSendStats | null> {
|
|
1527
|
+
private async sampleCamera(baseline: StatsBaseline, isCurrent: () => boolean): Promise<VideoSendStats | null> {
|
|
1528
|
+
const sampledProducer = this.cameraProducer();
|
|
1526
1529
|
const stats = await this.collectVideoStats(baseline);
|
|
1530
|
+
if (!isCurrent() || sampledProducer !== this.cameraProducer()) return null;
|
|
1527
1531
|
if (this.cameraFrameRate !== 60 || this.frameRateFallback || !stats) return stats;
|
|
1528
1532
|
if (this.cameraProducer()?.paused) return stats;
|
|
1529
1533
|
// The lower simulcast copies intentionally run at 30 fps. During the
|
|
@@ -1534,11 +1538,11 @@ export class StreamClient {
|
|
|
1534
1538
|
const limited = stats.layers.some((layer) => layer.active && (layer.qualityLimitation === 'cpu' || layer.qualityLimitation === 'bandwidth'));
|
|
1535
1539
|
this.frameRateLowSamples = limited && stats.fps > 0 && stats.fps < 50 ? this.frameRateLowSamples + 1 : 0;
|
|
1536
1540
|
if (this.frameRateLowSamples >= 3) {
|
|
1537
|
-
this.frameRateFallback = true;
|
|
1538
1541
|
void this.cameraTask(async () => {
|
|
1539
1542
|
const producer = this.cameraProducer();
|
|
1540
|
-
if (!producer?.track || producer.closed) return;
|
|
1541
|
-
|
|
1543
|
+
if (!isCurrent() || producer !== sampledProducer || this.frameRateFallback || !producer?.track || producer.closed) return;
|
|
1544
|
+
this.frameRateFallback = true;
|
|
1545
|
+
await producer.track.applyConstraints?.({ ...producer.track.getConstraints?.(), frameRate: { ideal: 30, max: 30 } }).catch(() => undefined);
|
|
1542
1546
|
await this.reproduceCamera(producer, producer.track);
|
|
1543
1547
|
this.emit('error', new RpcError('frame-rate-fallback', 'this device or upload cannot sustain 60 fps; publishing at 30 fps'));
|
|
1544
1548
|
}).catch((error) => this.emit('error', error as Error));
|
package/src/stats.ts
CHANGED
|
@@ -38,6 +38,11 @@ export interface VideoSendStats {
|
|
|
38
38
|
qualityLimitation?: string;
|
|
39
39
|
/** The browser's estimate of the upload it can use, in bits per second. */
|
|
40
40
|
availableOutgoingBitrate?: number;
|
|
41
|
+
/** Input to the RTP sender, when reported. May be a canvas rather than the physical camera. */
|
|
42
|
+
source?: { width: number; height: number; fps?: number };
|
|
43
|
+
/** Browser-reported encoder details; absent when not exposed. H264 alone does not imply hardware encoding. */
|
|
44
|
+
encoderImplementation?: string;
|
|
45
|
+
powerEfficientEncoder?: boolean;
|
|
41
46
|
/** Every layer, smallest first. */
|
|
42
47
|
layers: VideoLayerStats[];
|
|
43
48
|
}
|
|
@@ -77,6 +82,9 @@ const oneDecimal = (value: number): number => Math.round(value * 10) / 10;
|
|
|
77
82
|
*/
|
|
78
83
|
export function bitrateSince(baseline: StatsBaseline, key: string, bytes: number, timestamp: number): number {
|
|
79
84
|
const previous = baseline.get(key);
|
|
85
|
+
// Concurrent getStats calls can complete out of order. Do not rewind the
|
|
86
|
+
// baseline and inflate the next reading (or overwrite it with a duplicate).
|
|
87
|
+
if (previous && timestamp <= previous.timestamp) return 0;
|
|
80
88
|
baseline.set(key, { bytes, timestamp });
|
|
81
89
|
if (!previous) return 0;
|
|
82
90
|
const seconds = (timestamp - previous.timestamp) / 1000;
|
|
@@ -137,10 +145,14 @@ export function parseSendStats(
|
|
|
137
145
|
if (typeof entry.id === 'string') byId.set(entry.id, entry);
|
|
138
146
|
}
|
|
139
147
|
const outbound = entries.filter((e) => e.type === 'outbound-rtp' && isVideo(e));
|
|
148
|
+
const keys = new Set<string>();
|
|
140
149
|
|
|
141
150
|
const layers = outbound.map((entry): VideoLayerStats & { entry: StatsEntry } => {
|
|
142
151
|
const rid = optStr(entry.rid);
|
|
143
|
-
|
|
152
|
+
// A RID is a layer label, not a unique RTP stream. Reusing it with a new
|
|
153
|
+
// SSRC must start a fresh byte counter, even when the new count is higher.
|
|
154
|
+
const key = `${options.keyPrefix}${JSON.stringify([rid, entry.ssrc, entry.id])}`;
|
|
155
|
+
keys.add(key);
|
|
144
156
|
const bitrate = bitrateSince(options.baseline, key, num(entry.bytesSent), num(entry.timestamp));
|
|
145
157
|
const fps = oneDecimal(num(entry.framesPerSecond));
|
|
146
158
|
const reason = optStr(entry.qualityLimitationReason);
|
|
@@ -155,6 +167,7 @@ export function parseSendStats(
|
|
|
155
167
|
entry,
|
|
156
168
|
};
|
|
157
169
|
});
|
|
170
|
+
pruneBaseline(options.baseline, (key) => !key.startsWith(options.keyPrefix) || keys.has(key));
|
|
158
171
|
layers.sort(layerOrder);
|
|
159
172
|
|
|
160
173
|
// The biggest layer going out is what the best-connected viewer gets. With
|
|
@@ -163,6 +176,9 @@ export function parseSendStats(
|
|
|
163
176
|
const top = pool.reduce<(typeof layers)[number] | undefined>((best, l) => (!best || area(l) > area(best) ? l : best), undefined);
|
|
164
177
|
const codec = codecOf(byId, top?.entry) ?? outbound.map((e) => codecOf(byId, e)).find(Boolean);
|
|
165
178
|
const available = availableOutgoing(entries, byId);
|
|
179
|
+
const source = typeof top?.entry.mediaSourceId === 'string' ? byId.get(top.entry.mediaSourceId) : undefined;
|
|
180
|
+
const encoder = optStr(top?.entry.encoderImplementation);
|
|
181
|
+
const efficient = top?.entry.powerEfficientEncoder;
|
|
166
182
|
|
|
167
183
|
return {
|
|
168
184
|
...(codec !== undefined ? { codec } : {}),
|
|
@@ -173,6 +189,12 @@ export function parseSendStats(
|
|
|
173
189
|
bitrate: top?.bitrate ?? 0,
|
|
174
190
|
...(top?.qualityLimitation !== undefined ? { qualityLimitation: top.qualityLimitation } : {}),
|
|
175
191
|
...(available !== undefined ? { availableOutgoingBitrate: available } : {}),
|
|
192
|
+
...(source?.type === 'media-source' && isVideo(source) ? { source: {
|
|
193
|
+
width: num(source.width), height: num(source.height),
|
|
194
|
+
...(optNum(source.framesPerSecond) !== undefined ? { fps: oneDecimal(num(source.framesPerSecond)) } : {}),
|
|
195
|
+
} } : {}),
|
|
196
|
+
...(encoder !== undefined ? { encoderImplementation: encoder } : {}),
|
|
197
|
+
...(typeof efficient === 'boolean' ? { powerEfficientEncoder: efficient } : {}),
|
|
176
198
|
layers: layers.map(({ entry: _entry, ...layer }) => layer),
|
|
177
199
|
};
|
|
178
200
|
}
|
|
@@ -275,12 +297,25 @@ export class VideoLimitWatch {
|
|
|
275
297
|
private timer: ReturnType<typeof setInterval> | null = null;
|
|
276
298
|
private tracker = initialLimitTracker();
|
|
277
299
|
private sampling = false;
|
|
278
|
-
private
|
|
300
|
+
private baseline: StatsBaseline = new Map();
|
|
301
|
+
private generation = 0;
|
|
302
|
+
private visibilityDocument: Document | undefined;
|
|
303
|
+
private warmup = 0;
|
|
304
|
+
private readonly visibilityChanged = () => {
|
|
305
|
+
this.generation++;
|
|
306
|
+
this.baseline = new Map();
|
|
307
|
+
const was = this.tracker.reported;
|
|
308
|
+
this.tracker = initialLimitTracker();
|
|
309
|
+
this.warmup = 2;
|
|
310
|
+
this.onSuspend();
|
|
311
|
+
if (was && was !== 'none') this.report({ reason: 'none', width: 0, height: 0, fps: 0, bitrate: 0 });
|
|
312
|
+
};
|
|
279
313
|
|
|
280
314
|
constructor(
|
|
281
|
-
private readonly sample: (baseline: StatsBaseline) => Promise<VideoSendStats | null>,
|
|
315
|
+
private readonly sample: (baseline: StatsBaseline, isCurrent: () => boolean) => Promise<VideoSendStats | null>,
|
|
282
316
|
private readonly report: (event: VideoLimitedEvent) => void,
|
|
283
317
|
private readonly intervalMs = LIMIT_SAMPLE_MS,
|
|
318
|
+
private readonly onSuspend: () => void = () => {},
|
|
284
319
|
) {}
|
|
285
320
|
|
|
286
321
|
get running(): boolean {
|
|
@@ -290,10 +325,16 @@ export class VideoLimitWatch {
|
|
|
290
325
|
/** Start or stop sampling. Safe to call as often as anything changes. */
|
|
291
326
|
set(wanted: boolean): void {
|
|
292
327
|
if (wanted && !this.timer) {
|
|
328
|
+
this.visibilityDocument = typeof document !== 'undefined' ? document : undefined;
|
|
329
|
+
this.visibilityDocument?.addEventListener('visibilitychange', this.visibilityChanged);
|
|
330
|
+
if (this.visibilityDocument?.visibilityState === 'hidden') this.visibilityChanged();
|
|
293
331
|
this.timer = setInterval(() => void this.tick(), this.intervalMs);
|
|
294
332
|
} else if (!wanted && this.timer) {
|
|
295
333
|
clearInterval(this.timer);
|
|
296
334
|
this.timer = null;
|
|
335
|
+
this.generation++;
|
|
336
|
+
this.visibilityDocument?.removeEventListener('visibilitychange', this.visibilityChanged);
|
|
337
|
+
this.visibilityDocument = undefined;
|
|
297
338
|
}
|
|
298
339
|
}
|
|
299
340
|
|
|
@@ -305,17 +346,21 @@ export class VideoLimitWatch {
|
|
|
305
346
|
this.set(false);
|
|
306
347
|
const was = this.tracker.reported;
|
|
307
348
|
this.tracker = initialLimitTracker();
|
|
308
|
-
this.baseline
|
|
349
|
+
this.baseline = new Map();
|
|
309
350
|
return was && was !== 'none' ? { reason: 'none', width: 0, height: 0, fps: 0, bitrate: 0 } : null;
|
|
310
351
|
}
|
|
311
352
|
|
|
312
353
|
private async tick(): Promise<void> {
|
|
313
354
|
// A slow getStats must not pile samples up behind it.
|
|
314
355
|
if (this.sampling) return;
|
|
356
|
+
if (this.visibilityDocument?.visibilityState === 'hidden') return;
|
|
357
|
+
if (this.warmup > 0) { this.warmup--; return; }
|
|
358
|
+
const generation = this.generation;
|
|
359
|
+
const isCurrent = () => this.timer !== null && generation === this.generation && this.visibilityDocument?.visibilityState !== 'hidden';
|
|
315
360
|
this.sampling = true;
|
|
316
361
|
try {
|
|
317
|
-
const stats = await this.sample(this.baseline);
|
|
318
|
-
if (!stats || !
|
|
362
|
+
const stats = await this.sample(this.baseline, isCurrent);
|
|
363
|
+
if (!stats || !isCurrent()) return;
|
|
319
364
|
const { tracker, report } = trackLimit(this.tracker, limitReasonOf(stats.layers));
|
|
320
365
|
this.tracker = tracker;
|
|
321
366
|
if (report) this.report({ reason: report, width: stats.width, height: stats.height, fps: stats.fps, bitrate: stats.bitrate });
|