feat: add --listen-during-wake-sound argument (#273)

* feat: add --listen-during-wake-sound argument

---------

Co-authored-by: Florian Asche <github@florian-asche.de>
This commit is contained in:
Willian WangandFlorian Asche authored and GitHub committed 2026-07-18 19:16:11 +02:00
1 parent 9b2a8b4b30
commit a66c0e4f28
7 files changed
+45 -2

No files matched your search

+4
View File
@@ -60,6 +60,10 @@ LVA_PULSE_COOKIE="/run/user/${LVA_USER_ID}/pulse/cookie"
### Enable thinking sound (optional):
# ENABLE_THINKING_SOUND="1"
### Start listening during wake sound (optional):
# Start listening immediately after wake word detection, without waiting for the wake sound to finish
# LISTEN_DURING_WAKE_SOUND="1"
### Wake word directory (optional):
# path for custom files in docker is for example "app/wakewords/custom"
# WAKE_WORD_DIR="app/wakewords"
+2 -2
View File
@@ -76,10 +76,9 @@ For all other users, we have different installation methods available (Docker, s
```sh
usage: __main__.py [-h] [--name NAME] [--audio-input-device AUDIO_INPUT_DEVICE] [--list-input-devices] [--audio-input-block-size AUDIO_INPUT_BLOCK_SIZE] [--audio-output-device AUDIO_OUTPUT_DEVICE] [--list-output-devices] [--wake-word-dir WAKE_WORD_DIR] [--mic-auto-gain] [--mic-noise-suppression]
[--wake-model WAKE_MODEL] [--stop-model STOP_MODEL] [--download-dir DOWNLOAD_DIR] [--refractory-seconds REFRACTORY_SECONDS] [--wakeup-sound WAKEUP_SOUND] [--timer-finished-sound TIMER_FINISHED_SOUND] [--processing-sound PROCESSING_SOUND]
[--mute-sound MUTE_SOUND] [--unmute-sound UNMUTE_SOUND] [--preferences-file PREFERENCES_FILE] [--host HOST] [--network-interface NETWORK_INTERFACE] [--port PORT] [--enable-thinking-sound] [--debug]
[--mute-sound MUTE_SOUND] [--unmute-sound UNMUTE_SOUND] [--preferences-file PREFERENCES_FILE] [--host HOST] [--network-interface NETWORK_INTERFACE] [--port PORT] [--enable-thinking-sound] [--listen-during-wake-sound] [--debug]
```
| Parameter | Description | Default |
| ------------------------------- | ------------------------------------------------------------- | ------------------------------------ |
| `--name` | Name of the voice assistant device (required) | Autogenerated (`lva-MAC-ADDRESS`) |
@@ -108,6 +107,7 @@ usage: __main__.py [-h] [--name NAME] [--audio-input-device AUDIO_INPUT_DEVICE]
| `--network-interface` | Network interface for ESPHome server | Autodetected |
| `--port` | Port for ESPHome server | 6053 |
| `--enable-thinking-sound` | Enable thinking sound on startup | False |
| `--listen-during-wake-sound` | Start listening while the wake sound is still playing | False |
| `--peripheral-host` | Bind address for the peripheral WebSocket API | 0.0.0.0 |
| `--peripheral-port` | Port for the peripheral WebSocket API | 6055 |
| `--peripheral-volume-step` | Volume change per button press, 0.0–1.0 | %(default)s |
+4
View File
@@ -60,6 +60,10 @@ if [ "$ENABLE_THINKING_SOUND" = "1" ]; then
EXTRA_ARGS+=( "--enable-thinking-sound" )
fi
if [ "$LISTEN_DURING_WAKE_SOUND" = "1" ]; then
EXTRA_ARGS+=( "--listen-during-wake-sound" )
fi
if [ -n "${WAKE_WORD_DIR}" ]; then
EXTRA_ARGS+=( "--wake-word-dir" "$WAKE_WORD_DIR" )
fi
+13
View File
@@ -191,6 +191,7 @@ Environment=PREFERENCES_FILE="/home/pi/linux-voice-assistant/preferences.json"
# Environment=START_LISTENING_SOUND="sounds/start_listening_button.flac"
# Environment=TIMER_FINISHED_SOUND="sounds/timer_finished.flac"
# Environment=PROCESSING_SOUND="sounds/processing.wav"
# Environment=LISTEN_DURING_WAKE_SOUND="0"
# Environment=MUTE_SOUND="sounds/mute_switch_on.flac"
# Environment=UNMUTE_SOUND="sounds/mute_switch_off.flac"
# Environment=PERIPHERAL_HOST="0.0.0.0"
@@ -280,6 +281,7 @@ The following variables can be configured in the `.env` or in the service file:
| `START_LISTENING_SOUND` | `sounds/start_listening_button.flac` | Sound file for pressing button to talk |
| `TIMER_FINISHED_SOUND` | `sounds/timer_finished.flac` | Sound file for timer finished |
| `PROCESSING_SOUND` | `sounds/processing.wav` | Sound file for processing state |
| `LISTEN_DURING_WAKE_SOUND` | false | Set to "1" to start listening immediately after wake word detection, without waiting for the wake sound to finish |
| `MUTE_SOUND` | `sounds/mute_switch_on.flac` | Sound file for mute on |
| `UNMUTE_SOUND` | `sounds/mute_switch_off.flac` | Sound file for Configure Audio Devices
| `PERIPHERAL_HOST` | 0.0.0.0 | Host for the peripheral WebSocket API |
@@ -291,6 +293,17 @@ The following variables can be configured in the `.env` or in the service file:
💡 **Note:** For the systemd installation some variables set in the service need to be without `LVA_` prefix.
### Feature: Listen During Wake Sound
By default, LVA waits until the wake sound has finished playing before it starts listening for your spoken command. This can force a short pause between saying the wake word and the rest of your request. For example: `Okay Nabu <pause until wake sound finishes> turn on the kitchen lights`.
Enable `LISTEN_DURING_WAKE_SOUND="1"` to let LVA begin listening immediately after the wake word is detected, even while the wake sound is still playing. This allows you to say the wake word and the full command in one go.
This feature is especially useful when you want a more natural interaction flow and do not want to wait to confirm that the wake word was detected before speaking the command.
Keep in mind that listening while the wake sound is playing can also make the microphone pick up some of that wake sound as echo, depending on your speaker and microphone setup. This echo can interfere with speech-to-text and make commands less accurate. If you run into this, see [Enabling Acoustic Echo Cancellation (AEC)](enabling_aec.md).
### Use own soundfiles:
If you want to use your own sounds, you can add them to the `sounds/custom` aka `/var/lib/docker/volumes/lva_sounds_custom/_data` directory and reference them in the `.env` file.
+6
View File
@@ -224,6 +224,11 @@ async def main() -> None:
default=900.0, # 15 minutes
help="Seconds before a ringing timer auto-stops (default: 900)",
)
parser.add_argument(
"--listen-during-wake-sound",
action="store_true",
help="Start listening immediately after wake word detection, without waiting for the wake sound to finish",
)
parser.add_argument(
"--debug",
action="store_true",
@@ -426,6 +431,7 @@ async def main() -> None:
mic_noise_suppression=preferences.mic_noise_suppression,
audio_input_channels=args.audio_input_channels,
timer_max_ring_seconds=args.timer_max_ring_seconds,
listen_during_wake_sound=args.listen_during_wake_sound,
)
if fallback_used:
+1
View File
@@ -174,6 +174,7 @@ class ServerState:
mic_volume: int = 100 # 1–100, default maximum
audio_input_channels: int = 2 # number of mic channels to stream
timer_max_ring_seconds: float = 900.0
listen_during_wake_sound: bool = False
def broadcast(self, msgs: "Iterable[message.Message]") -> None:
"""Send messages to every connected API client.
+15
View File
@@ -834,11 +834,26 @@ class VoiceSatelliteProtocol(APIServer):
self._pipeline_active = True
self._emit(LVAEvent.WAKE_WORD_DETECTED)
self.duck()
if self.state.listen_during_wake_sound:
_LOGGER.debug("Starting audio streaming immediately (listen_during_wake_sound enabled)")
self.state.tts_player.play(self.state.wakeup_sound)
self._start_audio_streaming(wake_word_phrase)
else:
self.state.tts_player.play(
self.state.wakeup_sound,
done_callback=lambda: self._on_wakeup_sound_finished(wake_word_phrase),
)
def _start_audio_streaming(self, wake_word_phrase: str) -> None:
"""Start streaming audio during wake sound detection."""
_LOGGER.debug(
"Starting audio streaming for: %s",
wake_word_phrase,
)
self.send_messages([VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)])
self._is_streaming_audio = True
self._emit(LVAEvent.LISTENING)
def _on_wakeup_sound_finished(self, wake_word_phrase: str) -> None:
"""Callback invoked when the wakeup chime finishes; begin STT streaming."""
_LOGGER.debug(