diff --git a/apps/desktop/src/lib/wake-client-capture.ts b/apps/desktop/src/lib/wake-client-capture.ts index 92dfd62ac54dd..3681bffe35c6f 100644 --- a/apps/desktop/src/lib/wake-client-capture.ts +++ b/apps/desktop/src/lib/wake-client-capture.ts @@ -113,6 +113,9 @@ export async function startClientWakeCapture( // frames so the detector still sees contiguous recent PCM rather than gaps // from fire-and-forget discard-while-inflight. const MAX_QUEUED_FRAMES = 24 // ~1.9s at 80 ms/frame + // Coalesce queued frames into one wake.feed call (backend splits them back + // into engine frames). 4 × 80 ms ≈ 3 RPCs/s steady-state instead of 12.5. + const MAX_FRAMES_PER_FEED = 4 const queue: Float32Array[] = [] let draining = false @@ -123,12 +126,14 @@ export async function startClientWakeCapture( draining = true try { while (!stopped && queue.length > 0) { - const frame = queue.shift() - if (!frame) { + const batch = queue.splice(0, MAX_FRAMES_PER_FEED) + if (batch.length === 0) { break } try { - const pcm = floatToInt16LE(frame) + const merged = new Float32Array(batch.length * frameLength) + batch.forEach((frame, i) => merged.set(frame, i * frameLength)) + const pcm = floatToInt16LE(merged) await options.request('wake.feed', { pcm: bytesToBase64(pcm), sample_rate: TARGET_RATE diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 191b2d42e13f8..383e2d186c28b 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -13400,7 +13400,7 @@ def _(rid, params: dict) -> dict: return _err(rid, 4001, f"invalid base64 pcm: {e}") if not pcm: return _ok(rid, {"fed": False, "reason": "empty"}) - # Soft size cap (~0.5s of 16kHz int16 mono = 16000 bytes) + # Soft size cap: 64000 bytes = 2s of 16 kHz int16 mono if len(pcm) > 64000: return _err(rid, 4001, "pcm frame too large") sr = params.get("sample_rate")