How to use a bluetooth microphone and a built-in speaker at the same time?

I'm trying to achieve a very simple task in iOS. I would like to get audio from a Bluetooth microphone and play the audio simultaneously using the built-in speaker.


Here is what I have right now. The app allows users to choose a speaker and a microphone source. However, whenever I pick a built-in speaker, the app will switch to a built-in microphone. And whenever I pick a Bluetooth microphone, the app will use the Bluetooth speaker. There is no way I can use the Bluetooth microphone and the built-in speaker separately.


import UIKit
import AVFoundation
import AVKit

class ViewController: UIViewController {

    var engine = AVAudioEngine()
    let player = AVAudioPlayerNode()
    let audioSession = AVAudioSession()
    var routePickerView = AVRoutePickerView(frame: CGRect(x: 0, y: 0, width: 0, height: 50))
    let bus = 0
    var isRunning = false
   
    @IBOutlet weak var viewHolder: UIStackView!
   
    override func viewDidLoad() {
        super.viewDidLoad()

        setUpAVRoutePicker()
        setUpAVSession()
    }

    func setUpAVRoutePicker() {
        viewHolder.addArrangedSubview(routePickerView)
    }
   
    func setUpAVSession() {
        do {
            try audioSession.setCategory(AVAudioSession.Category.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP, .allowAirPlay])
            try audioSession.setMode(AVAudioSession.Mode.default)
            try audioSession.overrideOutputAudioPort(AVAudioSession.PortOverride.speaker)
            try audioSession.setActive(true)
        } catch {
            print("Error setting up AV session!")
            print(error)
        }
    }
   
    @IBAction func start(_ sender: AnyObject) {
        isRunning = !isRunning
        sender.setTitle(isRunning ? "Stop" : "Start", for: .normal)
       
        if isRunning {
            engine.attach(player)
           
            let inputFormat = engine.inputNode.inputFormat(forBus: bus)
           
            engine.connect(player, to: engine.mainMixerNode, format: inputFormat)

            engine.inputNode.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) -> Void in
                self.player.scheduleBuffer(buffer)
            }
           
            do {
                try engine.start()
            } catch {
                print("Engine start error")
                print(error)
                return
            }
            player.play()
        } else {
            engine.inputNode.removeTap(onBus: bus)
            engine.stop()
            player.stop()
        }
       
    }
   
    @IBAction func onInputBtnClicked(_ sender: AnyObject) {
        let controller = UIAlertController(title: "Select Input", message: "", preferredStyle: UIAlertController.Style.actionSheet)
       
        for input in audioSession.availableInputs ?? [] {
            controller.addAction(UIAlertAction(title: input.portName, style: UIAlertAction.Style.default, handler: { action in
            do {
                try self.audioSession.setPreferredInput(input)
            } catch {
                print("Setting preferred input error")
                print(error)
            }
            }))
        }
        present(controller, animated: true, completion: nil)
    }

   
}


It seems like it's impossible to achieve that (https://stackoverflow.com/a/24519938/6308776), which is kinda crazy. I know that it's possible to achieve such a simple task on Android, but it looks like it's not possible for iOS. Does anyone have any ideas?


p/s: I would like to use a Bluetooth headset, and I don't want to have the transmission via wifi.