#18235: macOS: prevent Voice Wake crash when no input device is available
app: macos
stale
size: S
Cluster:
Voice Transcription Enhancements
## Summary
- prevent macOS app crash when Voice Wake starts without a usable default audio input device
- add CoreAudio preflight for default input availability before installing AVAudioEngine tap
- keep failure in the recoverable runtime path (log + stop), avoiding SIGABRT process termination
## Bug
On Macs with no usable input device (common on Mac mini/headless setups), enabling Voice Wake can crash:
- `AVAudioNode.installTapOnBus` throws Objective-C exception
- exception crosses into Swift runtime and aborts the app (`SIGABRT`)
## Root Cause
`VoiceWakeRuntime.start(with:)` proceeded to `installTap` without verifying that the default input device is both present and input-capable/alive.
## Changes
1. `AudioInputDeviceObserver`
- added `hasUsableDefaultInputDevice()`
- added `inputAvailabilitySummary()` for diagnostics
- added private helper for default UID vs alive input UID matching
2. `VoiceWakeRuntime.start(with:)`
- added startup guard using `AudioInputDeviceObserver.hasUsableDefaultInputDevice()` before installing tap
- throws normal `NSError` (with input summary) and exits via existing catch/stop flow
3. Tests
- added `AudioInputDeviceObserverTests` covering:
- missing default UID
- default UID not alive/input-capable
- default UID valid/alive
## Validation
- `swift test --filter AudioInputDeviceObserverTests`
- `swift test --filter VoiceWakeRuntimeTests`
## Fixes
- Fixes #17484
- Fixes #16418
- Fixes #16118
- Fixes #15740
- Fixes #12169
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Prevents a crash (`SIGABRT`) on Macs without a usable audio input device (e.g., Mac mini/headless setups) by adding a CoreAudio preflight check before installing the `AVAudioEngine` tap in `VoiceWakeRuntime.start(with:)`. The new `AudioInputDeviceObserver.hasUsableDefaultInputDevice()` method verifies the default input device UID is both present and alive before proceeding, converting what was a fatal ObjC exception into a recoverable error handled through the existing catch/stop flow.
- `AudioInputDeviceObserver` gains `hasUsableDefaultInputDevice()` and `inputAvailabilitySummary()` with a clean private helper that matches the default device UID against alive input UIDs
- `VoiceWakeRuntime.start(with:)` now guards on input device availability before engine creation, throwing a descriptive `NSError` that the existing `catch` block handles gracefully
- New `AudioInputDeviceObserverTests` cover nil UID, mismatched UID, and valid UID cases via a `#if DEBUG` test hook
- Note: `VoiceWakeTester` and `MicLevelMonitor` have similar `installTap` patterns without this preflight guard — they may benefit from the same protection in a follow-up, though they are less critical since they are user-initiated rather than automatic
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — it adds a defensive guard that prevents a crash on the error path without changing any happy-path behavior.
- The change is small, well-scoped, and only adds a guard before existing code. The new check is purely additive — when a usable input device exists, behavior is identical to before. When no device exists, the code now takes a graceful error path instead of crashing. The logic is simple (UID lookup + set membership) and tested. No existing tests or behavior are affected.
- No files require special attention. Consider applying the same `hasUsableDefaultInputDevice()` guard to `VoiceWakeTester.swift` and `MicLevelMonitor.swift` in a follow-up.
<sub>Last reviewed commit: 680ec7d</sub>
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#5656: fix(macos): prevent crash on launch when no microphone available
by sfo2001 · 2026-01-31
86.7%
#14458: fix(voicewake): avoid crash on foreign transcript ranges
by guchang · 2026-02-12
74.5%
#9703: feat(macos): Voice settings restructure + Whisper transcription sup...
by nsd97 · 2026-02-05
72.9%
#15909: Guard notifications on macOS; fix focus issue and build fixes
by jasonkneen · 2026-02-14
67.7%
#3337: fix(macos-app): patch SwiftPM Bundle.module accessor for app bundle
by skymoore · 2026-01-28
67.1%
#9926: fix(macos): guard UNUserNotificationCenter when no bundle identifier
by webcpu · 2026-02-05
66.7%
#12157: feat(macos): add Granola-style meeting notes with live transcription
by npow · 2026-02-08
66.5%
#20475: fix(macos): resolve 120%+ CPU regression and gateway stability
by teknomage8 · 2026-02-19
66.3%
#20053: feat(voicewake): trigger-based routing to agent/session
by longbiaochen · 2026-02-18
66.1%
#19828: feat: reply notifications for macOS and web UI
by fal3 · 2026-02-18
65.8%