Error opening InputStream: Device unavailable [PaErrorCode -9985]
When the wake word "hal" is detected, the system transitions from IDLE to RECORDING state. This triggers:
- Wake word detector stops
- Audio recorder tries to start immediately
- ERROR: Audio device still in use by wake word detector
The wake word detector's audio stream isn't fully closed before the recorder tries to open the same audio device (PCM2902).
06:40:49 - WAKE WORD DETECTED!
06:40:49 - State transition: IDLE -> RECORDING
06:40:49 - Stopping wake word listener...
06:40:49 - Starting audio recording...
06:40:49 - Opening audio stream...
06:40:49 - ERROR: Device unavailable [PaErrorCode -9985]
06:40:50 - Audio stream closed ← Too late!
File: main_new.py lines 144-148
The on_recording callback stops the wake word detector but doesn't wait for the audio device to be fully released before handle_recording() is called.
# BEFORE - No delay
async def on_recording(metadata):
logger.info("Entered RECORDING state")
if subsystem_manager and subsystem_manager.wake_word_detector:
await subsystem_manager.stop_wake_word_listening()
# handle_recording() called immediately after this callbackAdd a configurable delay after stopping the wake word detector to ensure the audio device is fully released.
Added new configuration parameter:
# Wake Word Configuration
WAKE_WORD=hal
WAKE_WORD_MODEL_PATH=./models/vosk-model-small-en-us-0.15
WAKE_WORD_SIMILARITY=0.6
WAKE_WORD_DEVICE_RELEASE_DELAY=0.5 # NEW: Seconds to wait for device releaseAdded configuration loading (line 45):
# Wake Word Configuration
self.WAKE_WORD = os.getenv('WAKE_WORD', 'max')
self.WAKE_WORD_MODEL_PATH = os.getenv('WAKE_WORD_MODEL_PATH', ...)
self.WAKE_WORD_SIMILARITY = float(os.getenv('WAKE_WORD_SIMILARITY', '0.6'))
self.WAKE_WORD_DEVICE_RELEASE_DELAY = float(os.getenv('WAKE_WORD_DEVICE_RELEASE_DELAY', '0.5')) # NEW
logger.info(f"Wake word device release delay: {self.WAKE_WORD_DEVICE_RELEASE_DELAY}s")Added delay in on_recording callback (lines 144-153):
# AFTER - With configurable delay
async def on_recording(metadata):
logger.info("Entered RECORDING state")
if subsystem_manager and subsystem_manager.wake_word_detector:
await subsystem_manager.stop_wake_word_listening()
# Brief delay to ensure audio device is fully released
delay = config.WAKE_WORD_DEVICE_RELEASE_DELAY
logger.info(f"Waiting {delay}s for audio device release...")
await asyncio.sleep(delay)
logger.info("Audio device released, ready for recording")06:40:49 - WAKE WORD DETECTED!
06:40:49 - State transition: IDLE -> RECORDING
06:40:49 - Stopping wake word listener...
06:40:49 - Waiting 0.5s for audio device release...
06:40:50 - Audio stream closed ← Device released
06:40:50 - Audio device released, ready for recording
06:40:50 - Starting audio recording...
06:40:50 - Opening audio stream...
06:40:50 - ✓ Recording started successfully
-
Run the main application:
python3 main_new.py
-
Say the wake word "hal"
-
Check logs for:
Waiting 0.5s for audio device release... Audio device released, ready for recording Recording started - speak now... -
Verify NO error:
Device unavailable [PaErrorCode -9985]
If you still see the device unavailable error:
-
Edit
.env:WAKE_WORD_DEVICE_RELEASE_DELAY=1.0 # Increase to 1 second -
Restart application
If 0.5s works perfectly, you could try reducing it:
WAKE_WORD_DEVICE_RELEASE_DELAY=0.3 # Reduce to 300msPortAudio/ALSA Device Access:
- Only ONE process/stream can have exclusive access to an audio device at a time
- Wake word detector opens device with:
sd.InputStream(device=2, ...) - Audio recorder tries to open same device:
sd.InputStream(device=2, ...) - If first stream isn't closed, second open fails with PaErrorCode -9985
Even though stop_wake_word_listening() is async and we await it, the underlying PortAudio cleanup happens in a separate thread and takes time:
- Python calls
stream.stop()→ returns immediately - PortAudio sends stop signal to audio thread
- Audio thread processes final buffers
- Audio thread closes ALSA device
- Device is finally available ← This is not instant!
The 0.5s delay ensures step 5 completes before we try to open the device again.
WAKE_WORD_DEVICE_RELEASE_DELAY=0.5 # 500ms delay- Too short (< 0.3s): May still get "Device unavailable" errors
- Optimal (0.3-0.7s): Device releases cleanly, minimal user-perceived delay
- Too long (> 1.0s): Works but creates awkward pause after wake word
Recommended: Start with 0.5s, reduce to 0.3s if tests show it's stable.
.env- Configuration file (line 19)config.py- Configuration loader (line 45)main_new.py- Main application with state callbacks (lines 144-153)audio_recorder.py- Audio recording class (uses device parameter)wake_word_detector_improved.py- Wake word detector (opens audio device)
✅ Benefits:
- Eliminates "Device unavailable" errors
- Allows smooth transition from wake word detection to recording
- Configurable delay for different hardware
- Adds 0.5s delay between wake word detection and recording start
- User must pause slightly after saying wake word (already needed anyway)
Problem: Audio device conflict when transitioning from wake word listening to recording.
Solution: Add configurable 0.5s delay after stopping wake word detector to ensure device is fully released.
Configuration: WAKE_WORD_DEVICE_RELEASE_DELAY=0.5 in .env
Status: ✅ Fixed - Device release delay prevents conflicts