Some checks failed
Tests / Declarative: Post Actions failed: 42, skipped: 89, passed: 4273
31 lines
1.6 KiB
JavaScript
31 lines
1.6 KiB
JavaScript
// Metadata only. No frames or PCM are retained. These are OBSERVER metrics,
|
|
// never an automatically passing sync/freshness/artifact report.
|
|
export class VideoMetrics {
|
|
constructor() { this.last = null; this.intervals = []; this.callbacks = 0; this.unobserved = 0; this.resets = 0; }
|
|
observe(timeMs, presentedFrames) {
|
|
if (!Number.isFinite(timeMs) || !Number.isSafeInteger(presentedFrames) || presentedFrames < 0) return;
|
|
if (this.last) {
|
|
if (timeMs <= this.last.timeMs || presentedFrames <= this.last.presentedFrames) this.resets++;
|
|
else {
|
|
if (this.intervals.length < 15000) this.intervals.push(timeMs-this.last.timeMs);
|
|
this.unobserved += Math.max(0,presentedFrames-this.last.presentedFrames-1);
|
|
}
|
|
}
|
|
this.last = {timeMs,presentedFrames}; this.callbacks++;
|
|
}
|
|
summary() {
|
|
const sorted = [...this.intervals].sort((a,b)=>a-b);
|
|
return {callbacks:this.callbacks,unobservedPresentedFrames:this.unobserved,clockOrCounterResets:this.resets,
|
|
callbackIntervalP95Ms:sorted.length ? sorted[Math.ceil(sorted.length*.95)-1] : null,
|
|
callbackGapMaxMs:sorted.at(-1) ?? null,
|
|
note:"Browser presentation callbacks; gaps are not proof of transport loss or corrupted video."};
|
|
}
|
|
}
|
|
|
|
export function receipt(video,audio,settings,elapsedMs,reason) {
|
|
return {schema:"lesavka.rct-av-observer.v1",kind:"diagnostic-only",reason,elapsedMs,
|
|
settings,video:video.summary(),audio,
|
|
syncMeasured:false,freshnessMeasured:false,artifactsMeasured:false,
|
|
releaseEligible:false,recordedMedia:false};
|
|
}
|