// A cumulative, one-credit metadata reporter: never copies or sends audio. class Activity extends AudioWorkletProcessor { constructor() { 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.port.onmessage=({data})=>{ if(data==='ack')this.credit=true; if(data==='stop')this.stopped=true; }; } process(inputs,outputs) { if(this.stopped || 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);