Hello!
I'm experiencing an issue with iOS's audio routing system when trying to use Bluetooth headphones for audio output while also recording environmental audio from the built-in microphone.
Desired behavior:
- Play audio through Bluetooth headset (AirPods)
- Record unprocessed environmental audio from the iPhone's built-in microphone
Actual behavior:
- When explicitly selecting the built-in microphone, iOS reports it's using it (in currentRoute.inputs)
- However, the actual audio data received is clearly still coming from the AirPods microphone
- The audio is heavily processed with voice isolation/noise cancellation, removing environmental sounds
Environment Details
- Device: iPhone 12 Pro Max
- iOS Version: 18.4.1
- Hardware: AirPods
- Audio Framework: AVAudioEngine (also tried AudioQueue)
Code Attempted
I've tried multiple approaches to force the correct routing:
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
// Configure to allow Bluetooth output but use built-in mic
try? session.setCategory(.playAndRecord,
options: [.allowBluetoothA2DP, .defaultToSpeaker])
try? session.setActive(true)
// Explicitly select built-in microphone
if let inputs = session.availableInputs,
let builtInMic = inputs.first(where: { $0.portType == .builtInMic }) {
try? session.setPreferredInput(builtInMic)
print("Selected input: \(builtInMic.portName)")
}
// Log the current route
let route = session.currentRoute
print("Current input: \(route.inputs.first?.portName ?? "None")")
// Configure audio engine with native format
let inputNode = audioEngine.inputNode
let nativeFormat = inputNode.inputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: nativeFormat) { buffer, time in
// Process audio buffer
// Despite showing "Built-in Microphone" in route, audio appears to be
// coming from AirPods with voice isolation applied - welp!
}
try? audioEngine.start()
}
I've also tried various combinations of:
- Different audio session modes (.default, .measurement, .voiceChat)
- Different option combinations (with/without .allowBluetooth, .allowBluetoothA2DP)
- Setting session.setPreferredInput() both before and after activation
Diagnostic Observations
When AirPods are connected:
- AVAudioSession.currentRoute.inputs correctly shows "Built-in Microphone" after setPreferredInput()
- The actual audio data received shows clear signs of AirPods' voice isolation processing
- Background/environmental sounds are actively filtered out...
- When recording a test audio played near the phone (not through the app), the recording is nearly silent. Only headset voice goes through.
Questions
- Is there a workaround to force iOS to actually use the built-in microphone while maintaining Bluetooth output?
- Are there any lower-level configurations that might resolve this issue?
Any insights, workarounds, or suggestions would be greatly appreciated. This is blocking a critical feature in my application that requires environmental audio recording while providing audio feedback through headphones 😅