Skip to content

fix: support Bluetooth audio input devices (AirPods)#70

Merged
jafreck merged 1 commit intomainfrom
fix/bluetooth-audio-input
Mar 30, 2026
Merged

fix: support Bluetooth audio input devices (AirPods)#70
jafreck merged 1 commit intomainfrom
fix/bluetooth-audio-input

Conversation

@jafreck
Copy link
Copy Markdown
Owner

@jafreck jafreck commented Mar 30, 2026

Problem

AirPods (and other Bluetooth devices) connected to macOS would deliver silence when used as the default audio input device. The microphone was never activated because cpal's low-level AudioUnit HAL doesn't trigger the Bluetooth A2DP → HFP profile switch that enables the mic.

Root Cause

macOS Bluetooth devices start in A2DP mode (high-quality output only). The microphone requires HFP/SCO mode, which higher-level Apple frameworks (AVCaptureSession) trigger automatically, but cpal's AudioUnit HAL does not.

Fix

  • CoreAudio activation hook (activate.rs): Re-sets the default input device via AudioObjectSetPropertyData, which nudges macOS into establishing the Bluetooth SCO link. Platform-gated (#[cfg(target_os = "macos")]), no-op elsewhere, no new dependencies.
  • Dead-stream detection: ensure_warm() now probes callback activity before each recording. If the device disconnected (e.g. Bluetooth dropped), the stream is re-opened on the current default device.
  • Diagnostic logging: Device name/config logged on open. VAD logs RMS when rejecting audio. Empty transcription results are now logged instead of silently dropped.

Testing

  • Verified AirPods Pro transcription works with denoiser enabled
  • Verified MacBook mic still works normally
  • Verified dead-stream recovery when AirPods disconnect mid-session
  • All 345 existing tests pass

On macOS, Bluetooth devices like AirPods connect in A2DP mode (output
only). The microphone requires a switch to HFP/SCO, which cpal's
low-level AudioUnit HAL doesn't always trigger.

Changes:
- Add CoreAudio activation hook (activate.rs) that re-sets the default
  input device via AudioObjectSetPropertyData to nudge macOS into
  establishing the Bluetooth SCO link for microphone input
- Add dead-stream detection in ensure_warm() using a callback counter
  so disconnected devices are detected and the stream is re-opened
- Log device name, sample rate, channels, and format when opening a
  device for easier debugging of audio issues
- Log audio RMS in VAD when speech detection fails, and log when
  transcription produces empty text (previously silent)
@jafreck jafreck force-pushed the fix/bluetooth-audio-input branch from 62835e1 to 319613d Compare March 30, 2026 05:22
@jafreck jafreck merged commit a6f96ae into main Mar 30, 2026
5 checks passed
@jafreck jafreck deleted the fix/bluetooth-audio-input branch March 30, 2026 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant