cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

main
goq / portal / frame-stats.mjs
frame-stats.mjs 6.3K
1import { normalizeNetworkDiagnostics } from './network-diagnostics.mjs';23function exactUnsigned(value) {4 return Number.isSafeInteger(value) && value >= 0 ? value : null;5}67function formatFrameCount(value) {8 return `${value} ${value === 1 ? 'frame' : 'frames'}`;9}1011/**12 * Names and formats each browser-side video discard counter without conflating13 * latest-frame-wins presenter overwrites with transport or decoder loss.14 */15export function formatVideoDiscardTelemetry({16 transportDroppedFrames,17 frontendDroppedFrames,18 decoderDroppedFrames,19 presenterOverwrittenFrames,20}) {21 const counters = [22 transportDroppedFrames,23 frontendDroppedFrames,24 decoderDroppedFrames,25 presenterOverwrittenFrames,26 ].map(exactUnsigned);27 if (counters.some((value) => value === null)) {28 throw new TypeError('video discard counters must be exact unsigned integers');29 }3031 const totalFrames = counters.reduce((total, value) => total + value, 0);32 if (!Number.isSafeInteger(totalFrames)) {33 throw new RangeError('video discard total exceeds the exact integer range');34 }3536 return {37 total: formatFrameCount(totalFrames),38 transport: formatFrameCount(transportDroppedFrames),39 frontend: formatFrameCount(frontendDroppedFrames),40 decoder: formatFrameCount(decoderDroppedFrames),41 presenterOverwrite: formatFrameCount(presenterOverwrittenFrames),42 };43}4445export function isCurrentFrameGeneration(generation, activeGeneration) {46 return Number.isSafeInteger(generation)47 && generation > 048 && Number.isSafeInteger(activeGeneration)49 && activeGeneration > 050 && generation === activeGeneration;51}5253function exactDurationMs(value) {54 return Number.isFinite(value) && value >= 0 ? value : null;55}5657function firstExactUnsigned(...values) {58 for (const value of values) {59 const exact = exactUnsigned(value);60 if (exact !== null) return exact;61 }62 return null;63}6465function durationSummary(payload, prefix) {66 const count = exactUnsigned(payload[`${prefix}_sample_count`]);67 if (count === null) return null;68 if (count === 0) return { count: 0, p50Ms: null, p95Ms: null, maxMs: null };69 const p50Ms = exactDurationMs(payload[`${prefix}_p50_ms`]);70 const p95Ms = exactDurationMs(payload[`${prefix}_p95_ms`]);71 const maxMs = exactDurationMs(payload[`${prefix}_max_ms`]);72 if (p50Ms === null || p95Ms === null || maxMs === null) return null;73 return { count, p50Ms, p95Ms, maxMs };74}7576/**77 * Validates the exact v2 frame-stat fields while retaining the aggregate78 * aliases emitted by older clients. A null value means that metric must be79 * presented as unavailable rather than inferred from a differently named unit.80 */81export function normalizeFrameStatsPayload(payload) {82 if (!payload || typeof payload !== 'object') throw new TypeError('frame stats must be an object');8384 const statsVersion = exactUnsigned(payload.stats_version) ?? 1;85 const v2 = statsVersion >= 2;86 const v3 = statsVersion >= 3;87 const v4 = statsVersion >= 4;88 const queueDroppedFrames = v2 ? exactUnsigned(payload.frontend_queue_dropped_total) : null;89 const resyncDroppedFrames = v2 ? exactUnsigned(payload.frontend_resync_dropped_total) : null;90 const splitFrontendTotal = queueDroppedFrames !== null && resyncDroppedFrames !== null91 && Number.isSafeInteger(queueDroppedFrames + resyncDroppedFrames)92 ? queueDroppedFrames + resyncDroppedFrames93 : null;94 const rawObjectDroppedFrames = v395 ? exactUnsigned(payload.transport_object_dropped_total) : null;96 const rawLateObjectDroppedFrames = v397 ? exactUnsigned(payload.transport_late_object_dropped_total) : null;98 const objectCountersValid = rawObjectDroppedFrames !== null99 && rawLateObjectDroppedFrames !== null100 && rawLateObjectDroppedFrames <= rawObjectDroppedFrames;101102 let queue = null;103 let resync = null;104 let transportIntervals = null;105 let ipcSendDurations = null;106 let timingWindow = null;107 let networkDiagnostics = null;108 if (v2) {109 const depth = exactUnsigned(payload.frontend_queue_depth);110 const peak = exactUnsigned(payload.frontend_queue_peak);111 const capacity = exactUnsigned(payload.frontend_queue_capacity);112 if (depth !== null && peak !== null && capacity !== null) {113 queue = { depth, peak, capacity };114 }115116 const episodes = exactUnsigned(payload.frontend_resync_episode_total);117 const totalMs = exactDurationMs(payload.frontend_resync_duration_ms_total);118 const maxMs = exactDurationMs(payload.frontend_resync_duration_ms_max);119 const active = typeof payload.frontend_resync_active === 'boolean'120 ? payload.frontend_resync_active : null;121 const currentMs = payload.frontend_resync_duration_ms_current === null122 ? null : exactDurationMs(payload.frontend_resync_duration_ms_current);123 if (episodes !== null && totalMs !== null && maxMs !== null && active !== null124 && ((!active && currentMs === null) || (active && currentMs !== null))) {125 resync = { episodes, active, totalMs, currentMs, maxMs };126 }127128 transportIntervals = durationSummary(payload, 'transport_interval');129 ipcSendDurations = durationSummary(payload, 'frontend_ipc_send_duration');130 const windowMs = exactDurationMs(payload.timing_window_ms);131 const sampleCapacity = exactUnsigned(payload.timing_sample_capacity);132 if (windowMs !== null && sampleCapacity !== null) {133 timingWindow = { windowMs, sampleCapacity };134 }135 }136137 if (v4 && payload.network_diagnostics !== null && payload.network_diagnostics !== undefined) {138 try {139 networkDiagnostics = normalizeNetworkDiagnostics(payload.network_diagnostics);140 } catch (_) {141 // Network diagnostics are supplemental. A malformed snapshot must not142 // discard otherwise valid frame statistics or be partially displayed.143 networkDiagnostics = null;144 }145 }146147 return {148 statsVersion,149 transportDroppedFrames: firstExactUnsigned(150 payload.sequence_dropped_total,151 payload.host_dropped_frames,152 ),153 objectDroppedFrames: objectCountersValid ? rawObjectDroppedFrames : null,154 lateObjectDroppedFrames: objectCountersValid ? rawLateObjectDroppedFrames : null,155 frontendDroppedFrames: firstExactUnsigned(156 payload.frontend_dropped_total,157 payload.frontend_dropped_frames,158 splitFrontendTotal,159 ),160 queueDroppedFrames,161 resyncDroppedFrames,162 queue,163 resync,164 transportIntervals,165 ipcSendDurations,166 timingWindow,167 networkDiagnostics,168 };169}