From 9b4cebb6cc6fd125c47e9366e30d68ed6fee3457 Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Fri, 27 Mar 2026 23:29:43 -0300 Subject: [PATCH 1/8] feat: add --listen-during-wake-sound argument --- README.md | 4 +++- docker-entrypoint.sh | 8 ++++++++ docs/install_application.md | 4 +++- linux_voice_assistant/__main__.py | 6 ++++++ linux_voice_assistant/models.py | 1 + linux_voice_assistant/satellite.py | 20 +++++++++++++------- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 59b79b7b..f9154ab6 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ For all other users we have different installation methods available (Docker, sy ``` 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] [--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] [--timer-max-ring-seconds TIMER_MAX_RING_SECONDS] [--listen-during-wake-sound] [--debug] ``` | Parameter | Description | Default | @@ -77,6 +77,8 @@ 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 | +| `--timer-max-ring-seconds` | Seconds before a ringing timer auto-stops | 900.0 | +| `--listen-during-wake-sound` | Start listening immediately after wake word detection, without waiting for the wake sound to finish | False | | `--debug` | Print DEBUG messages to console | False | ## Build Information diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 4d7b023e..7a191d79 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -44,6 +44,14 @@ if [ "$ENABLE_THINKING_SOUND" = "1" ]; then EXTRA_ARGS+=( "--enable-thinking-sound" ) fi +if [ -n "${TIMER_MAX_RING_SECONDS}" ]; then + EXTRA_ARGS+=( "--timer-max-ring-seconds" "$TIMER_MAX_RING_SECONDS" ) +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 diff --git a/docs/install_application.md b/docs/install_application.md index b14a3fed..a1955efb 100644 --- a/docs/install_application.md +++ b/docs/install_application.md @@ -252,14 +252,16 @@ The following variables can be configured in the `.env` or in the service file: | `AUDIO_INPUT_DEVICE` | Autodetected | Audio input device name | | `AUDIO_OUTPUT_DEVICE` | Autodetected | Audio output device name | | `ENABLE_THINKING_SOUND` | false | Set to "1" to enable thinking sound | +| `TIMER_MAX_RING_SECONDS` | 900 | Seconds before a ringing timer auto-stops | | `WAKE_WORD_DIR` | `app/wakewords` | Path to the wake word directory | | `WAKE_MODEL` | `okay_nabu` | Wake word model to use | | `REFACTORY_SECONDS` | `2` | Refractory period in seconds after wake word | | `WAKEUP_SOUND` | `sounds/wake_word_triggered.flac` | Sound file for wake word triggered | | `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 +| `UNMUTE_SOUND` | `sounds/mute_switch_off.flac` | Sound file for mute off | 💡 **Note:** For the systemd installation some variables set in the service need to be without `LVA_` prefix. diff --git a/linux_voice_assistant/__main__.py b/linux_voice_assistant/__main__.py index 2160889c..0f0f3a8b 100644 --- a/linux_voice_assistant/__main__.py +++ b/linux_voice_assistant/__main__.py @@ -151,6 +151,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", @@ -354,6 +359,7 @@ async def main() -> None: download_dir=args.download_dir, volume=initial_volume, timer_max_ring_seconds=args.timer_max_ring_seconds, + listen_during_wake_sound=args.listen_during_wake_sound, ) if args.enable_thinking_sound: diff --git a/linux_voice_assistant/models.py b/linux_voice_assistant/models.py index 366b8431..1c8d01c7 100644 --- a/linux_voice_assistant/models.py +++ b/linux_voice_assistant/models.py @@ -98,6 +98,7 @@ class ServerState: connected: bool = False volume: float = 1.0 timer_max_ring_seconds: float = 900.0 + listen_during_wake_sound: bool = False def save_preferences(self) -> None: """Save preferences as JSON.""" diff --git a/linux_voice_assistant/satellite.py b/linux_voice_assistant/satellite.py index f468bb86..67c00fd6 100644 --- a/linux_voice_assistant/satellite.py +++ b/linux_voice_assistant/satellite.py @@ -399,14 +399,20 @@ def wakeup(self, wake_word: Union[MicroWakeWord, OpenWakeWord]) -> None: _LOGGER.debug("Detected wake word: %s", wake_word_phrase) self._pipeline_active = True self.duck() - self.state.tts_player.play( - self.state.wakeup_sound, - done_callback=lambda: self._on_wakeup_sound_finished(wake_word_phrase), - ) + + if self.state.listen_during_wake_sound: + _LOGGER.debug("Starting audio streaming immediately (listen_during_wake_sound enabled)") + self._start_audio_streaming(wake_word_phrase) + self.state.tts_player.play(self.state.wakeup_sound) + else: + self.state.tts_player.play( + self.state.wakeup_sound, + done_callback=lambda: self._start_audio_streaming(wake_word_phrase), + ) - def _on_wakeup_sound_finished(self, wake_word_phrase: str) -> None: - """Callback invoked when the wakeup sound finishes playing.""" - _LOGGER.debug("Wakeup sound finished, starting audio streaming with wake word: %s", wake_word_phrase) + def _start_audio_streaming(self, wake_word_phrase: str) -> None: + """Callback invoked to start streaming audio after/during wake word detection.""" + _LOGGER.debug("Starting audio streaming with wake word: %s", wake_word_phrase) self.send_messages( [VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)], ) From 92ca777de5a3c2ac258f5f6ecdc5c64e68781f73 Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Fri, 27 Mar 2026 23:39:50 -0300 Subject: [PATCH 2/8] Update docstring for audio streaming callback --- linux_voice_assistant/satellite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux_voice_assistant/satellite.py b/linux_voice_assistant/satellite.py index 67c00fd6..265ed633 100644 --- a/linux_voice_assistant/satellite.py +++ b/linux_voice_assistant/satellite.py @@ -411,7 +411,7 @@ def wakeup(self, wake_word: Union[MicroWakeWord, OpenWakeWord]) -> None: ) def _start_audio_streaming(self, wake_word_phrase: str) -> None: - """Callback invoked to start streaming audio after/during wake word detection.""" + """Start streaming audio after/during wake word detection.""" _LOGGER.debug("Starting audio streaming with wake word: %s", wake_word_phrase) self.send_messages( [VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)], From 040b99ed3b84f51ab105c068ac70bac51b4a1c6c Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Sat, 28 Mar 2026 17:02:49 -0300 Subject: [PATCH 3/8] Remove TIMER_MAX_RING_SECONDS from install documentation Removed TIMER_MAX_RING_SECONDS from configuration options. --- docs/install_application.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/install_application.md b/docs/install_application.md index a1955efb..885e90ce 100644 --- a/docs/install_application.md +++ b/docs/install_application.md @@ -252,7 +252,6 @@ The following variables can be configured in the `.env` or in the service file: | `AUDIO_INPUT_DEVICE` | Autodetected | Audio input device name | | `AUDIO_OUTPUT_DEVICE` | Autodetected | Audio output device name | | `ENABLE_THINKING_SOUND` | false | Set to "1" to enable thinking sound | -| `TIMER_MAX_RING_SECONDS` | 900 | Seconds before a ringing timer auto-stops | | `WAKE_WORD_DIR` | `app/wakewords` | Path to the wake word directory | | `WAKE_MODEL` | `okay_nabu` | Wake word model to use | | `REFACTORY_SECONDS` | `2` | Refractory period in seconds after wake word | From fe3f9d32d1ca1c7876a76460cbafa71030d7c48e Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Sat, 28 Mar 2026 17:04:21 -0300 Subject: [PATCH 4/8] Remove default value for timer-max-ring-seconds --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index f9154ab6..4b20bc5d 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ For all other users we have different installation methods available (Docker, sy ``` 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] [--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] [--timer-max-ring-seconds TIMER_MAX_RING_SECONDS] [--listen-during-wake-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 | @@ -77,7 +77,6 @@ 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 | -| `--timer-max-ring-seconds` | Seconds before a ringing timer auto-stops | 900.0 | | `--listen-during-wake-sound` | Start listening immediately after wake word detection, without waiting for the wake sound to finish | False | | `--debug` | Print DEBUG messages to console | False | From 43b17ec1c6579c097c13d425d444ce997cc220c6 Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Sat, 28 Mar 2026 17:29:39 -0300 Subject: [PATCH 5/8] improve listen_during_wake_sound doc --- docs/install_application.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/install_application.md b/docs/install_application.md index 885e90ce..9a00ba29 100644 --- a/docs/install_application.md +++ b/docs/install_application.md @@ -182,6 +182,7 @@ Environment=PREFERENCES_FILE="/home/pi/linux-voice-assistant/preferences.json" # Environment=WAKEUP_SOUND="sounds/wake_word_triggered.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" ExecStart=/home/pi/linux-voice-assistant/docker-entrypoint.sh @@ -264,6 +265,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 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. From 1b434d7b7412052d2c0e2f888294c39df3b8bb83 Mon Sep 17 00:00:00 2001 From: Willian Wang Date: Thu, 23 Apr 2026 01:55:13 -0300 Subject: [PATCH 6/8] chore: add LISTEN_DURING_WAKE_SOUND to .env.example --- .env.example | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.env.example b/.env.example index e5480046..2dee01b1 100644 --- a/.env.example +++ b/.env.example @@ -54,6 +54,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" From e015993913b99326f4ae69da842f2b0cda7fdad1 Mon Sep 17 00:00:00 2001 From: Florian Asche Date: Sat, 25 Apr 2026 03:09:41 +0200 Subject: [PATCH 7/8] Remove TIMER_MAX_RING_SECONDS from entrypoint script Remove unused TIMER_MAX_RING_SECONDS argument handling --- docker-entrypoint.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 6711a9d3..210eed85 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -56,10 +56,6 @@ if [ "$ENABLE_THINKING_SOUND" = "1" ]; then EXTRA_ARGS+=( "--enable-thinking-sound" ) fi -if [ -n "${TIMER_MAX_RING_SECONDS}" ]; then - EXTRA_ARGS+=( "--timer-max-ring-seconds" "$TIMER_MAX_RING_SECONDS" ) -fi - if [ "$LISTEN_DURING_WAKE_SOUND" = "1" ]; then EXTRA_ARGS+=( "--listen-during-wake-sound" ) fi From 849d87abaa61cfbfd6508e9b1f945467cb369c33 Mon Sep 17 00:00:00 2001 From: Florian Asche Date: Sat, 25 Apr 2026 03:15:13 +0200 Subject: [PATCH 8/8] Fix formatting in satellite.py --- linux_voice_assistant/satellite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux_voice_assistant/satellite.py b/linux_voice_assistant/satellite.py index 72c76b2d..637824d5 100644 --- a/linux_voice_assistant/satellite.py +++ b/linux_voice_assistant/satellite.py @@ -654,7 +654,7 @@ def _delayed_wakeup() -> None: _LOGGER.debug("Detected wake word: %s", wake_word_phrase) self._pipeline_active = True self.duck() - + if self.state.listen_during_wake_sound: _LOGGER.debug("Starting audio streaming immediately (listen_during_wake_sound enabled)") self._start_audio_streaming(wake_word_phrase)