bug: switching from listen mode to record does not stop the listener #13
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_voice#13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
When the user is in listen (wake word) mode and starts a recording,
is_listeningis never set tofalse. Both listening and recording run simultaneously.Impact
The listen processor keeps buffering audio and may send spurious
WakeWordmessages during an active recording session. The buffer also grows without bound until the connection closes.File
crates/hero_voice_ui/src/ws.rs:222-243— theStarthandler setsis_recording = truebut does not setis_listening = falseor resetlisten_processor.Specification: Fix Start handler not stopping listen mode
Objective
Ensure that when a client sends
ClientMessage::Startwhile in wake-word listen mode, the listener is cleanly stopped so that listening and recording never run simultaneously.Requirements
ClientMessage::Startmust setis_listening = falsein addition tois_recording = true.ClientMessage::Startmust resetlisten_processorso no stale VAD buffer carries over if Listen is re-entered later.Stop,Listen, and the binary audio loop is unchanged.Files to Modify
crates/hero_voice_ui/src/ws.rs— update theClientMessage::Startarm.Files to Create
None.
Implementation Plan
Step 1: Update the Start handler
File:
crates/hero_voice_ui/src/ws.rsIn the
Ok(ClientMessage::Start { topic, audio_dir })arm, immediately after*is_recording.lock().await = true;, add:Ordering rationale:
is_recording = truefirst — this alone is enough to suppress the wake-word branch in the binary loop (guarded bylistening && !recording).is_listening = falsesecond — makes the state flags consistent and prevents the flag from staying stale until the nextStop.listen_processor.reset()last — safe to run whileis_recordingis alreadytruebecause the binary loop cannot be inside the wake-word branch once recording is true.audio_processor.reset()andtopic_sidassignment follow unchanged.Each lock is acquired, mutated, and released on its own line — no lock is held across an
awaiton another lock — matching the pattern already used throughout this file. The binary loop acquires locks in the same order (is_recording, thenis_listening, then the relevant processor), so no reordering is introduced.Dependencies: none.
Step 2: Manual verification
No unit test is added. The bug is a state-machine flag inside an async WebSocket handler whose surrounding context (
axum::WebSocket,mpscchannels,LocalTranscriber) is not currently factored for unit testing, and extracting a synchronous helper just for two flag writes plus areset()call would add more indirection than it removes. Verification is manual against the running stack:hero_voice_uiand open the UI.Wake word detected!lines during the recording window.listen_processor.reset()did not break re-entry).Dependencies: Step 1 complete.
Acceptance Criteria
ClientMessage::Startarm setsis_listening = false.ClientMessage::Startarm callslisten_processor.lock().await.reset().awaiton a different lock within the Start arm.cargo build -p hero_voice_uisucceeds.cargo clippy -p hero_voice_ui -- -D warningssucceeds.Notes
!recordingguard on the wake-word branch already prevents most user-visible impact, but the state inconsistency and the unreset buffer are real bugs.Stopalready sets both flags tofalse; this change bringsStartinto symmetry with it.Test Results
Command:
cargo test --workspaceBreakdown:
hero_voicelib unit tests: 13 passedhero_voice_sdklib unit tests: 5 passedNo test was added for this change. The bug is a state-machine flag in an async WebSocket handler with no unit-test scaffolding for the surrounding handler. The spec chose manual verification against the running stack; see the spec comment for the steps.
cargo clippy -p hero_voice_ui --all-targets -- -D warningsalso passes.Implementation Summary
Changes
Single-file change:
crates/hero_voice_ui/src/ws.rs, inside theClientMessage::Startarm.Two lines added, plus a short doc comment explaining why:
*is_listening.lock().await = false;— clears the wake-word listening flag, bringingStartinto symmetry withStop(which already clears both flags).listen_processor.lock().await.reset();— drops the stale VAD buffer so wake-word detection gets a clean slate the next time the client sendsListen.Scope preserved
Stop,Listen, and the binary audio loop is unchanged.awaiton another lock; lock-acquisition order matches the rest of the file.Acceptance criteria — status
ClientMessage::Startarm setsis_listening = false.ClientMessage::Startarm callslisten_processor.lock().await.reset().awaiton a different lock.cargo build -p hero_voice_uisucceeds.cargo clippy -p hero_voice_ui --all-targets -- -D warningssucceeds.cargo test --workspacepasses (18 total, 18 passed, 0 failed).Wake word detected!during recording; Listen re-entry still works after Stop) — to be performed on merge or by the reviewer.Files changed
crates/hero_voice_ui/src/ws.rs— +5 lines (2 functional, 3 comment).Pull request opened: #17