Crash report: 94AF43D3-67EF-4948-B897-ABCDF91EACEC
Version: 0.2.115 (142), TestFlight, iPad17,4, iOS 26.3
Date: 2026-05-20 16:56
Root cause: MicrophoneRelay.startAsync(bodyHost:) calls input.installTap(onBus:bufferSize:format:block:) with no guard against a tap already being installed. AVAudioNode.installTap throws an Objective-C NSException when a tap is already on bus 0 — this cannot be caught with Swift do-catch, so it aborts the process.
The start() method has no early-exit if isRunning == true, so a second call (e.g., on reconnect or stream restart) races to install a second tap and crashes.
Stack trace (top frames):
AVFAudio AVAudioEngineImpl::InstallTapOnNode + 1376
AVFAudio -[AVAudioNode installTapOnBus:bufferSize:format:block:] + 564
HydraHeadiPad MicrophoneRelay.startAsync(bodyHost:) + 704 (MicrophoneRelay.swift:51)
Fix (MicrophoneRelay.swift):
guard !isRunning else { return } at the top of startAsync to prevent double-start.input.removeTap(onBus: 0) before installTap as a defensive belt-and-suspenders measure.