Resolved — posting the fix for anyone who hits this later.
Root cause
An EXAppExtensionAttributes block in our main app's Info.plist was registering the host app itself as an embedded com.apple.appintents-extension carrying our intents:
<key>EXAppExtensionAttributes</key>
<dict>
<key>EXExtensionPointIdentifier</key>
<string>com.apple.appintents-extension</string>
<key>IntentsSupported</key>
<array>
<string>FeatureAppIntent</string>
...
</array>
</dict>
After removing that block:
AVCaptureSession.startRunning() with the audio AVCaptureDeviceInput attached no longer fires -11800 / 'what'.
currentRoute.inputs is no longer empty — MicrophoneBuiltIn shows up as expected.
AVAudioRecorder.record() returns true (we'd also tried that path; same family of bug).
The three spurious routeChangeNotification(.categoryChange) events also stop.
Why it matters
Declaring AppIntents this way registers the main app bundle itself as hosting an appintents-extension extension point. Even though no intent was being invoked, that registration appears to engage the audio HAL pipeline at app launch in a way that conflicts with AVCaptureSession audio input attachment.
None of the workarounds we tried could pre-empt it from app code, because it happens before main() runs:
AVAudioSession config combinations (.playAndRecord / .videoRecording, .record / .measurement, every option combo)
Codec-recovery patterns (1-shot, 2-shot stop + start)
usesApplicationAudioSession = false toggle
Pod-level SDK bisect (ad mediations, MediaPipe, etc.)
The fix
Declare AppIntents in a real, separate App Intents Extension target — its own Info.plist, its own EXAppExtensionAttributes — instead of embedding EXAppExtensionAttributes directly in the host app’s Info.plist.
Moving the intents into a sibling extension target (same project, separate target) resolves the issue with no loss of intent functionality.
Hope this saves someone else the bisect.
Topic:
Media Technologies
SubTopic:
Audio
Tags: