// Recent known-pilot observations. Fixed memory; no audio or content retained. const CAPACITY = 1000; export class PilotWindow { constructor(windowMs) { if (!Number.isFinite(windowMs) || windowMs <= 0 || windowMs > 100) { throw new RangeError('pilot observation duration'); } this.windowMs = windowMs; this.history = new Uint8Array(CAPACITY); this.next = 0; this.count = 0; this.lastEndMs = null; this.interruptions = 0; } interrupt() { this.next = 0; this.count = 0; this.lastEndMs = null; this.interruptions = Math.min(Number.MAX_SAFE_INTEGER, this.interruptions + 1); } observe(present, endMs) { if (typeof present !== 'boolean' || !Number.isFinite(endMs) || endMs < this.windowMs) { this.interrupt(); return; } // The detector emits equal-sized, contiguous sample windows. Missing // callbacks are unknown coverage, not evidence of missing pilot PCM. if (this.lastEndMs !== null && Math.abs(endMs - this.lastEndMs - this.windowMs) > 0.001) { this.interrupt(); } this.history[this.next] = present ? 1 : 0; this.next = (this.next + 1) % CAPACITY; this.count = Math.min(CAPACITY, this.count + 1); this.lastEndMs = endMs; } summary(nowMs) { let missing = 0, run = 0, longest = 0; const start = (this.next + CAPACITY - this.count) % CAPACITY; for (let n = 0; n < this.count; n++) { if (this.history[(start + n) % CAPACITY]) run = 0; else { missing++; run++; longest = Math.max(longest, run); } } const age = this.lastEndMs !== null && Number.isFinite(nowMs) && nowMs >= this.lastEndMs ? nowMs - this.lastEndMs : null; return { windowLimitMs: CAPACITY * this.windowMs, observedWindows: this.count, observedMs: this.count * this.windowMs, endMs: this.lastEndMs, observationAgeMs: age, coverageComplete: this.count === CAPACITY && age !== null && age <= 2 * this.windowMs, absentFraction: this.count ? missing / this.count : null, absenceMaxMs: this.count ? longest * this.windowMs : null, trailingAbsenceMs: this.count ? run * this.windowMs : null, interruptions: this.interruptions, }; } }