jenkins 9204773e7d av-test: publish bounded continuity watch and recent observations
Vendor tested Lesavka observer assets and numeric receipt schema from 6b97ceb1. Verified 65 JS tests, 10 service tests, kustomize render and Kubernetes client dry-run. No media upload, capture activation or changes to the homepage and private OCR.
2026-10-22 21:47:13 -05:00

42 lines
2.1 KiB
JavaScript

// A cumulative, one-credit metadata reporter: never copies or sends audio.
class Activity extends AudioWorkletProcessor {
constructor(options) {
super(); this.frames=0; this.inputFrames=0; this.zeroFrames=0;
this.energy=0; this.peak=0; this.credit=true; this.next=0; this.stopped=false;
this.watch=options?.processorOptions?.continuityWatch===true;
this.startedFrame=this.watch?currentFrame:0;this.lastAckFrame=this.startedFrame;
this.port.onmessage=({data})=>{
if(data==='ack'){this.credit=true;if(this.watch)this.lastAckFrame=currentFrame;}
if(data==='stop')this.stopped=true;
};
}
process(inputs,outputs) {
if(this.stopped)return false;
if(this.watch) {
// Long watches require a live UI owner. Withheld ACKs stop work
// autonomously; they never renew the fixed ten-hour deadline.
const age=currentFrame-this.startedFrame,unacked=currentFrame-this.lastAckFrame;
if(!Number.isSafeInteger(age)||age<0||unacked<0||age>=sampleRate*36025||unacked>sampleRate*10) {
this.stopped=true;this.port.postMessage({watchStopped:true});return false;
}
} else if(this.frames >= sampleRate*125)return false;
const block=outputs[0]?.[0]?.length ?? 128;
const samples=inputs[0]?.[0];
this.frames+=block;
if(samples) for(const value of samples) {
this.inputFrames++; this.energy+=value*value;
this.peak=Math.max(this.peak,Math.abs(value));
if(value===0)this.zeroFrames++;
}
// Output is left at zero: no monitoring/playback or acoustic feedback.
if(this.credit && this.frames>=this.next) {
this.port.postMessage({inputFrames:this.inputFrames,processedFrames:this.frames,
exactZeroFrames:this.zeroFrames,rms:this.inputFrames ? Math.sqrt(this.energy/this.inputFrames) : 0,
peak:this.peak,sampleRate});
this.credit=false; this.next=this.frames+sampleRate;
}
return true;
}
}
registerProcessor('av-activity',Activity);