From 9d2ffd1b0d4f76aac58026fd2cc16ca207325a48 Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Sat, 30 May 2026 05:09:20 +0000 Subject: [PATCH] =?UTF-8?q?Fix=20silence=20timeout=20never=20firing=20?= =?UTF-8?q?=E2=80=94=20gate=20on=20audio=20amplitude?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on_audio was resetting the timer on every chunk including silence, so the timeout never fired. Now passes the raw chunk and checks RMS; only resets if energy is above 0.02 (speech, not ambient silence). Co-Authored-By: Claude Sonnet 4.6 --- lib/stt.mjs | 2 +- query-demo.mjs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/stt.mjs b/lib/stt.mjs index bb5bc80..ac0c408 100644 --- a/lib/stt.mjs +++ b/lib/stt.mjs @@ -132,7 +132,7 @@ export class Stt { let pending = Buffer.alloc(0) mic.stdout.on('data', (chunk) => { - if (on_audio) on_audio() + if (on_audio) on_audio(chunk) pending = Buffer.concat([pending, chunk]) // Feed complete VAD windows diff --git a/query-demo.mjs b/query-demo.mjs index 7bf1d04..69684fd 100644 --- a/query-demo.mjs +++ b/query-demo.mjs @@ -121,4 +121,12 @@ stt.listen(async (text) => { accumulated = '' await submit(query) -}, { on_audio: () => { if (accumulated) reset_silence_timer() } }) +}, { on_audio: (chunk) => { + if (!accumulated) return + // Only reset silence timer if audio has significant energy (not silence) + const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.byteLength >> 1) + let sum = 0 + for (let i = 0; i < samples.length; i++) sum += samples[i] * samples[i] + const rms = Math.sqrt(sum / samples.length) / 32768 + if (rms > 0.02) reset_silence_timer() +} })