Posts

Post not yet marked as solved
0 Replies
1.4k Views
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.
Posted Last updated
.