anthropics / anthropics/claude-code

Voice mode: capture doesn't re-acquire the input device on default-device or topology changes — Bluetooth connect/disconnect silently kills dictation until restart

Open
#88,890 0 comments 0 reactions 0 assignees View on GitHub
area:tui bug platform:macos
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

## Environment

- Claude Code 2.1.239, macOS (Darwin 25.3.0), iTerm2
- Mics: Shure MV7+ (USB), AirPods Pro (Bluetooth)
- Voice mode: tap (`/voice tap`); hold mode behaves the same

## Summary

Voice mode resolves the audio input device once (at process start, or first
capture) and never re-acquires it. Two distinct failure classes follow, both
reproduced and isolated with OS-level capture verified healthy each time:

1. **Default-input change is ignored.** Started a session while AirPods were
the system default input, then switched the default to the USB mic in
System Settings. Voice mode kept recording from the old device. Toggling
`/voice` off/on does not rebind; only restarting the CLI does.
2. **Device-topology change wedges capture entirely.** With the correct mic
already the default and working, disconnecting the AirPods (removing
them) killed voice capture — even though the *pinned default device never
changed*. The AirPods leaving reshuffles the Core Audio device graph, the
stale stream dies, and voice mode delivers silence until the CLI is
restarted. Reconnecting Bluetooth devices does the same. In practice every
AirPods connect/disconnect during a session costs a restart.

## Why it looks like a user problem (and why it isn't)

The failure is silent: no error is surfaced at tap time (eventually "Voice
input is failing repeatedly and has been paused"). During each incident we
verified the OS side independently:

- `SwitchAudioSource -t input -c` confirmed the correct default input.
- `AVCaptureDevice.authorizationStatus(for: .audio)` returned `authorized`
for the hosting terminal.
- `ffmpeg -f avfoundation -i ":" -t 4 -af volumedetect` captured
healthy live audio (mean approx. -28 dB, peaks approx. -10 dB) from the exact device
voice mode should be using — at the same moment voice mode produced
nothing.

A fresh `claude` process picked the mic up correctly every time, which
isolates the defect to the running process's device binding.

## Expected behavior

Standard macOS capture hygiene: subscribe to the default-input-device-changed
property (`kAudioHardwarePropertyDefaultInputDevice`) and to configuration-
change notifications (`AVAudioEngineConfigurationChange` or equivalent), and
rebuild/re-acquire the input on either. Most capture apps (Zoom, QuickTime)
survive AirPods churn transparently.

## Suggested behavior if a full fix is deferred

Even without live rebinding, detecting a dead/invalidated stream and surfacing
"input device changed — voice needs a restart" (or auto-rebinding on the next
tap) would convert a silent failure into an actionable one.

## Related

- #36041 (input-device selection feature request) — complementary: a device
picker doesn't help if the binding to the picked device goes stale.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start from the /voice tap entry point and locate the voice-capture implementation that binds the input device. Reproduce a default-input switch and an AirPods connect/disconnect while checking whether the stream becomes invalid or silent. Done means capture re-acquires the current input or surfaces the documented actionable failure instead of requiring a CLI restart.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, python
Domain
audio-video-rtc, cli, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.