Skip to content

Microphone menu goes stale: Bluetooth mic missing after reconnect, app silently records from wrong (dead) device #176

Description

@ShumengSerac

Summary

The Microphone menu goes stale: a Bluetooth microphone (AirPods Pro) that is connected and visible in System Settings → Sound → Input does not appear in OpenSuperWhisper's Microphone menu until the app is restarted. Meanwhile the app silently falls back to a different device, which can produce recordings of pure digital silence that Whisper "transcribes" as hallucinated text like "Thank you."

Environment

  • OpenSuperWhisper 0.1.0 (Homebrew cask)
  • macOS 15.5, MacBook Air (Apple Silicon), lid closed on external display
  • AirPods Pro 2 (also paired to an iPhone, auto-switching enabled)

What happens

  1. AirPods Pro disconnect (left the desk / auto-switched to iPhone) and later reconnect to the Mac.
  2. System Settings → Sound → Input lists "AirPods Pro" as available. OpenSuperWhisper's Microphone submenu does not — it only shows "MacBook Air Microphone".
  3. Because the previously selected device is no longer in the app's (stale) list, MicrophoneService.updateCurrentMicrophone() silently falls back to the "default" device, preferring the built-in microphone.
  4. On a MacBook with the lid closed, the built-in microphone enumerates fine but delivers pure digital zeros (I verified the recorded WAVs: every sample exactly 0). Whisper hallucinates on silence — the transcription history fills with "Thank you." / "Piano music" (or "Sous-titrage Société Radio-Canada" in French, as a commenter on Feature request: Support specifying input device #57 reported) with no error shown to the user (related: Silent failure when engine fails to load or transcription fails — no error shown to user #117).

Restarting the app fixes the menu, because the device list is re-scanned at launch.

Root cause

MicrophoneService refreshes availableMicrophones only:

  • once in init, and
  • on AVCaptureDeviceWasConnected / AVCaptureDeviceWasDisconnected notifications.

Those AVFoundation notifications are not delivered reliably for Bluetooth audio devices re-registering with CoreAudio (they mostly fire for wired/USB plug events). So the app's list drifts out of sync with reality.

I verified the discovery API itself is fine: while the app's menu was missing the AirPods, a standalone script running the exact same AVCaptureDevice.DiscoverySession(deviceTypes: [.microphone, .external], mediaType: .audio, ...) query did return the AirPods (uid XX-XX-XX-XX-XX-XX:input, transport blue). The list in the app is stale — discovery is not the problem, the refresh triggers are.

System Settings stays correct because it observes CoreAudio's kAudioHardwarePropertyDevices property on the system object, which fires reliably whenever the HAL adds or removes any device, regardless of transport.

Suggested fix

Observe CoreAudio's device-list changes directly in MicrophoneService via AudioObjectAddPropertyListenerBlock(kAudioObjectSystemObject, kAudioHardwarePropertyDevices, ...) and refresh availableMicrophones + currentMicrophone when it fires. The status bar menu already rebuilds reactively from $availableMicrophones, so no UI changes are needed.

Two adjacent details worth handling in the same pass:

  • refreshAvailableMicrophones() currently clears selectedMicrophone whenever the list is momentarily empty, so the user's saved choice is not restored when their device reconnects mid-session.
  • Publishing the list only when it actually changed avoids rebuilding the status bar menu on every no-op HAL event.

I'll open a PR implementing this shortly.

Likely duplicates / related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions