Skip to content

macOS: prevent Voice Wake crash when no input device is available#18235

Closed
agisilaos wants to merge 2 commits intoopenclaw:mainfrom
agisilaos:fix/macos-voicewake-no-mic-crash-try-two
Closed

macOS: prevent Voice Wake crash when no input device is available#18235
agisilaos wants to merge 2 commits intoopenclaw:mainfrom
agisilaos:fix/macos-voicewake-no-mic-crash-try-two

Conversation

@agisilaos
Copy link

@agisilaos agisilaos commented Feb 16, 2026

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
  1. 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
  1. 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

Greptile Summary

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

Confidence Score: 5/5

  • 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.

Last reviewed commit: 680ec7d

(5/5) You can turn off certain types of comments like style here!

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added stale Marked as stale due to inactivity and removed stale Marked as stale due to inactivity labels Feb 22, 2026
@steipete
Copy link
Contributor

Closing as AI-assisted stale-fix triage.

Linked issue #12169 ("Mac app: SIGABRT crash when no audio input device available (voice wake)") is currently closed and was closed on 2026-02-23T04:32:59Z with state reason not_planned.
Given that issue state, this fix PR is no longer needed in the active queue and is being closed as stale.

If the underlying bug is still reproducible on current main, please reopen this PR (or open a new focused fix PR) and reference both #12169 and #18235 for fast re-triage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment