Skip to content

Hang on audio-device change in 1.6.5 — AVAudioEngine start/stop stalls in _GetHWFormat (distinct from #665 crash) #682

Closed

Description

@poltorrr

Summary

Since the #665 fix, FluidVoice no longer crashes on audio-device changes — it hangs instead. The window stays responsive, but dictation is dead: pressing the hotkey does nothing, because the audio pipeline is frozen. Only Force Quit clears it. I'm doing that ~10 times a day.

This is a different defect from #665 (that SIGABRT is fixed). Here the app spins/deadlocks inside AVAudioEngine start and stop, both stuck in Apple's hardware-format query _GetHWFormat.

Environment

  • FluidVoice 1.6.5 (build 16)
  • macOS 26.3.1 (25D2128), Apple Silicon, MacBook Pro (MacBookPro18,3), 16 GB
  • Speech model: parakeet-tdt
  • Mic: built-in — PreferredInputDeviceUID = BuiltInMicrophoneDevice (nothing exotic selected)
  • ExperimentalDirectAudioCaptureEnabled = true, ExperimentalDirectAudioCaptureForcedOff = true — the app auto-disabled its direct-capture fast path after repeated failures, so it now always uses the AVAudioEngine ("compatibility") path, which is the one that hangs
  • Audio devices that come and go here: iPhone Continuity mic, LG UltraFine Display Audio, Hue Sync Audio (4-ch), Microsoft Teams Audio, ZoomAudioDevice

Symptoms

  • UI responds; dictation does not. Hotkey press does nothing.
  • One thread pinned ~11% CPU; process otherwise idle.
  • Never recovers on its own — requires Force Quit.

Evidence — two live sample captures

Both show the audio engine wedged in _GetHWFormat.

1) Hang while STARTING the engine (most recent):

ASRService audio-capture path
  ASRService.startCompatibilityAudioCapture(reason:)
    ASRService.startEngine()
      AVAudioEngineImpl::Initialize(NSError**)        <- ~85% of samples stuck here
AVAudioIOUnit queue (~100% CPU)
  AVAudioIOUnit::IOUnitPropertyListener(...)
    AVAudioIOUnit_OSX::_GetHWFormat(...)              <- spinning

2) Hang while STOPPING/retiring the engine (earlier):

DispatchQueue app.fluidvoice.audio-engine-retirement (serial)
  AudioEngineRetirementDrain.enqueueAndWait(_:)       <- synchronous wait
    -[AVAudioEngine dealloc] -> ~AVAudioIOUnit_OSX()
      blocked on _dispatch_event_loop_wait_for_ownership
AVAudioIOUnit queue (~100% CPU)
  AVAudioIOUnit::IOUnitPropertyListener(...)
    AVAudioIOUnit_OSX::_GetHWFormat(...)              <- spinning

In (2), the engine dealloc waits on the AVAudioIOUnit queue via enqueueAndWait, but that queue never yields because it's stuck in the hardware-format property listener. The process sat wedged like this for ~30 minutes.

Also observed (same subsystem)

Reproduction

  1. Run 1.6.5 on a machine with audio devices that appear/disappear.
  2. Trigger an audio-device change while using the app. Reliable triggers for me:
    • Physically plugging or unplugging headphones or an external amplifier / audio interface.
    • Virtual/multi-channel devices appearing or disappearing (Microsoft Teams, Zoom, Hue Sync).
    • The iPhone Continuity mic or a display's audio waking up.
  3. FluidVoice hangs — either failing to start capture (hotkey does nothing) or freezing during engine teardown. Force Quit required. Happens even with the plain built-in mic selected.

Suggested directions

  • The hang sits in AVAudioEngine start/stop, both blocked on _GetHWFormat. Consider removing the IOUnit property listener before engine teardown, and not driving engine init/dealloc synchronously (enqueueAndWait) on a queue that the hardware-format listener can block.
  • Add a timeout/watchdog around engine start and retirement so a stuck _GetHWFormat degrades gracefully instead of freezing the whole capture path.
  • Debounce device/format-change events; a burst currently triggers repeated teardown/rebuild.
  • Direct-capture got force-disabled on this machine, so the app is permanently on the hanging path — worth revisiting that fallback so a machine that fails direct capture isn't stranded on a compatibility path that also hangs.

Full .ips crash reports and .hang spindumps available on request.

Activity

  1. poltorrr commented on Jul 21, 2026

    @poltorrr
    Author

    Reproduced live just now by plugging in earbuds — this time it crashed (EXC_BAD_ACCESS / SIGSEGV) instead of hanging, and the crash is in the same _GetHWFormat / IOUnitPropertyListener path as the hangs in the report.

    FluidVoice 1.6.5 (build 16), macOS 26.3.1 (25D2128), 2026-07-21 20:28.

    Thread (queue: AVAudioIOUnit) — EXC_BAD_ACCESS (SIGSEGV), bad address 0x1
      objc_retain
      -[AVAudioFormat isEqual:]
      AVAudioIOUnit::_GetHWFormat(unsigned int, unsigned int*) + 712
      invocation function for block in AVAudioIOUnit::IOUnitPropertyListener(...)
      _dispatch_lane_serial_drain
      _dispatch_lane_invoke
      _dispatch_workloop_worker_thread
      start_wqthread
    

    So the hardware-format property listener (IOUnitPropertyListener -> _GetHWFormat -> -[AVAudioFormat isEqual:]) either spins (the hangs in the original report) or dereferences a bad/dangling AVAudioFormat and crashes (here), depending on timing — both on the AVAudioIOUnit queue, both fired by a device change. Same root: the IOUnit property listener is live and racing during a device/format change while the format objects it compares are being torn down.

    A few seconds later, disabling AirPods dropped it straight back into the hung state — every audio-device change (plug/unplug earbuds, toggle AirPods) trips it.

  2. grohith327 commented on Jul 21, 2026

    @grohith327
    Collaborator

    Hey @poltorrr thanks for the detailed report. Can you try one thing for me ? Can you restart your app and enable the Faster Recording Start and let me know if it still crashes while switching audio.

    Image
  3. poltorrr commented on Jul 21, 2026

    @poltorrr
    Author

    Thanks @grohith327. One catch worth flagging: Faster Recording Start is already enabled in the UI, but the app has silently force-disabled direct capture underneath it. Current defaults for com.FluidApp.app:

    ExperimentalDirectAudioCaptureEnabled   = 1
    ExperimentalDirectAudioCaptureForcedOff = 1
    DirectAudioCaptureConsecutiveFailures   = 2
    

    So after 2 consecutive failures the app set ...ForcedOff = 1 and fell back to the AVAudioEngine compatibility path — which is the path that hangs/crashes (AVAudioEngineImpl::Initialize / _GetHWFormat). I just reproduced the crash again with the toggle on, which fits: the toggle is on, but direct capture isn't actually running because of the forced-off flag.

    How would you like me to clear the forced-off state so I can genuinely test direct capture — toggle the setting off and back on, delete one of those keys, or is there a hidden reset? Happy to run the test once direct capture is actually active.

  4. exondus commented on Jul 22, 2026

    @exondus

    Hey @poltorrr thanks for the detailed report. Can you try one thing for me ? Can you restart your app and enable the Faster Recording Start and let me know if it still crashes while switching audio.

    Image

    This worked for me. Thanks @grohith327

  5. poltorrr commented on Jul 22, 2026

    @poltorrr
    Author

    Following up: enabling Faster Recording Start didn't help here — as I noted above, on my machine the app force-disables direct capture at startup (ForcedOff flips back to 1, and it even turns the toggle back off), so it always runs the AVAudioEngine compatibility path. Glad it worked for @exondus, but I can't get direct capture to stay on to reproduce that.

    What did fix it: I downgraded to 1.6.0 (build 12) and the problem is gone. Plugging/unplugging AirPods no longer hangs or crashes — several device switches, no issue. So this looks like a regression introduced after 1.6.0, in the audio-capture / AVAudioEngine path.

    One minor thing in 1.6.0: the first few times I hit record, the recorder flashes on and off and I have to retry once or twice, but it always starts eventually — no hangs, no crashes.

    Environment unchanged: macOS 26.3.1 (25D2128), MacBookPro18,3, built-in mic. Happy to test a specific build between 1.6.0 and 1.6.4 if that would help pin down where the compatibility path broke.

  6. adamgranted commented on Jul 22, 2026

    @adamgranted

    Seeing the same behavior as @poltorrr, AirPods are wrecking havoc on 1.6.5. I'm experiencing regular crashes as my AirPods automatically switch between devices.

    Ironically this is what plagued open-wispr, prompting the switch to FluidVoice in the first place. Happy to collect any additional logs or details to help with the bug.

  7. grohith327 commented on Jul 22, 2026

    @grohith327
    Collaborator

    @poltorrr / @adamgranted sorry you both are running into this issue and are blocked.

    @poltorrr let me share a build that attempts to fix this. The ExperimentalDirectAudioCaptureForcedOff is a one time marker. It might be confusing but toggling it back on in the app should ensure CoreAudio is used

    @adamgranted have you tried the turning the toggle back on as shown in the screenshot above or still no luck ??

    We're trying to get a release out by EOD today/tomorrow that addresses. I am not fully able to replicate this on my machine so would it if you folks can try out a custom and let me know

  8. poltorrr commented on Jul 22, 2026

    @poltorrr
    Author

    Thanks @grohith327, happy to test a custom build — I don't see a link in your comment though, so whenever it's ready drop it here and I'll run it.

    When I cleared it manually (via defaults) it re-armed to 1 on the next launch and the toggle flipped itself off — so the in-app toggle must reset it differently. I'll test that path on the build you send.

  9. grohith327 commented on Jul 22, 2026

    @grohith327
    Collaborator

    Sounds good, working on it now. Will get it to you in some time. Thank you for your patience @poltorrr

  10. adamgranted commented on Jul 22, 2026

    @adamgranted

    @grohith327 all good, thanks for building it in the first place. I can confirm that I'm still experiencing crashes regardless of "Fast Recording State" enablement. So this is an identical bug to @poltorrr.

    It pretty consistently looks like one of the following states:

    1. Intentional AirPod selection in MacOS > run FluidVoice > transcripts without issue.
    2. Phone call / media plays from iPhone > AirPods switch > after call/media end > attempt FluidVoice transcription > crash*

    *Occasionally I will be able to stop FluidVoice from recording but on second recording attempt (after state 2), FluidVoice will crash on attempt to use the AirPods as an audio input. In both cases, the AirPods still show as connected in macOS which I assume is apart of Apples handoff system attempting to be clever. Sometimes the crash is immediate, sometimes it's a lock up, sometimes I have to force quit FluidVoice via Activity Monitor.

    Happy to test a custom build whenver its ready.

  11. grohith327 commented on Jul 22, 2026

    @grohith327
    Collaborator

    Hey @adamgranted / @poltorrr here is the build. Please try it out and let me know if you are still experiencing the issue.

    FluidVoice-682.zip

  12. adamgranted commented on Jul 22, 2026

    @adamgranted

    @grohith327 macOS reports that the app is damaged because code-signature verification is failing. It looks like the ZIP is missing several signed files from CTranscribe.framework and also contains some extra macOS metadata files.

    Image

    Would you mind checking the packaging/signing process and sending a fresh build when you have a chance? The app may need its embedded frameworks re-signed before the final app is signed and zipped.

  13. grohith327 commented on Jul 23, 2026

    @grohith327
    Collaborator

    Hey @adamgranted, sorry I had to accept some new terms of service from Apple, my app signing was failing and I didn't realize 🙄. Please try this build and let me know. Thank you!

    FluidVoice-SIGNED-NOTARIZED.zip

  14. adamgranted commented on Jul 25, 2026

    @adamgranted

    @grohith327, thanks. The custom build still crashes. It occasionally successfully changes the microphone, but mostly fails during attempts, causing a crash. The floating UI shows it attempts recording, has no mic, requests AirPods transition, and then disappears.

    I’ll stress the 1.6.0 build again, as I haven’t had any crashes during microphone transitions. Let me know what else you need.

  15. grohith327 commented on Jul 31, 2026

    @grohith327
    Collaborator

    Hey folks, appreciate the patience. We released version 1.6.6 with some improvements. CoreAudio flow is made the default with a bunch of improvements and this should prevent a lot of the issues, especially audio device input changes. We will sunset the AVAudioEngine flow in the next 1-2 versions

  16. added
    awaiting responseOlder issue will close after three days unless this label is removed.
    on Jul 31, 2026
  17. adamgranted commented on Aug 6, 2026

    @adamgranted

    @grohith327 I don't think this one is out of the woods, even in 1.6.7 the AirPods mic stability is (anecdotally) worse than 1.6.0.

    I'm about to downgrade again since 1.6.7 is hitting that similar wall of not being able to properly use my AirPods microphone even when the host shows a healthy system settings vu-meter on speaking.

    I have not had a crash yet with 1.6.7 but the intermittent ability for FluidVoice to hear me persists. Anything else I can do to help capture this bug?

  18. removed
    awaiting responseOlder issue will close after three days unless this label is removed.
    on Aug 6, 2026
  19. grohith327 commented on Aug 6, 2026

    @grohith327
    Collaborator

    Hey @adamgranted, is there a reason you prefer your AirPods mic over your MacBook mic ?

  20. adamgranted commented on Aug 6, 2026

    @adamgranted

    @grohith327 yes, MacBook stays closed and docked at my primary desk.

    I'll do some more digging and see if I can identify exactly why 1.6.0 is AirPod stable compared to 1.6.7

  21. grohith327 commented on Aug 6, 2026

    @grohith327
    Collaborator

    Gotcha, that makes sense. And you don't any external mics is it ?

    We generally do not recommend using Bluetooth devices as mics, we're trying to nudge people away from that unless absolutely necessary. The main reason being, even if reliability improves, there are still some issues which just cannot be solved. Like for example, the muffled audio issue when you some audio/video playing.

    For the closed Mac thing, we'll get a fix out soon to pick the one available. Sorry about that.

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

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