7
votes

Is it possible to receive audio input from iPhone's built-in microphone, and play that audio through a Bluetooth headset, at the same time?

My goal is to always use the built-in microphone as the input device, even if the output device is a headset, because the built-in microphone is more convenient in my use cases.

I know how to achieve my goal when the output device is a wired headset, like the one that comes bundled with an iPhone. I simply plug the wired headset in, and call the following method:

- (void)selectBuiltInMicrophone
{
    AVAudioSession *session = [AVAudioSession sharedInstance];
    for (AVAudioSessionPortDescription *port in session.availableInputs)
        if ([port.portType isEqualToString:AVAudioSessionPortBuiltInMic]) {
            NSError *error;
            [session setPreferredInput:port error:&error];
            break;
        }
}

By calling the above method, the input device will be switched from the wired headset's microphone to iPhone's built-in microphone, while the output device remains unaffected, so the iPhone will record from the built-in microphone and play through the wired headset. This is what I expect.

The problem is, this method does not work when the headset is a Bluetooth one. If I connect a Bluetooth headset to the iPhone, then call the above method, the built-in microphone will becomes the input device, which is great, but the output device will also be changed to iPhone's receiver, which is bad.

It seems that the input and the output of a Bluetooth headset are locked together: you either use both of them, or you use none of them. Is my goal really impossible? Or there exists a way to overcome the apparent limitation?

2
Have you been able to solve this problem? Have you tried playing around with overrideOutputAudioPort function or anything else?Artash

2 Answers

4
votes

It is not possible to receive audio input from iPhone's built-in microphone, and play that audio through a Bluetooth headset, at the same time

  1. There is a prevention that you can use like a walkie-talkie .
  2. you have to create Two sessions . Means while recording audio you have to enable audio session with recordandplay.
  3. while Playing you have to set the option to audiosession (allowingBluetooth) .
  4. While Recording You have to set recordandplay.
0
votes

You can choose a specific microphone while playing audio through a bluetooth audio device.

  // set audio session category to .playAndRecord. use do-catch if you need error-handling
  try? AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetoothA2DP, .allowBluetooth])

  // check if currentRoute is set to a bluetooth audio device
  let btOutputTypes: [AVAudioSession.Port] = [.bluetoothHFP, .bluetoothA2DP, .bluetoothLE]
  let btOutputs = AVAudioSession.sharedInstance().currentRoute.outputs.filter { btOutputTypes.contains($0.portType) }

  // if so, set preferred audio input to built-in mic
  if !btOutputs.isEmpty {
     let builtInMicInput = AVAudioSession.sharedInstance().availableInputs?.filter { $0.portType == .builtInMic }.first
     try? AVAudioSession.sharedInstance().setPreferredInput(builtInMicInput)
  } else {
     // set default input
     try? AVAudioSession.sharedInstance().setPreferredInput(nil)
  }

  try? AVAudioSession.sharedInstance().setActive(true)

or you can follow detailed instruction from here https://developer.apple.com/library/archive/qa/qa1799/_index.html

EDIT: It turns out there is easier way to use Built-In Mic as an input while using bluetooth headphone as output. Just set AVAudioSession's categoryOptions like this

// allow only A2DP. you may set other mode or options, excluding .allowBluetooth
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.allowBluetoothA2DP])

By removing .allowBluetooth from AVAudioSession's categoryOptions, It won't allow HFP, which is a protocol to use bluetooth device as an input. Thus it will automatically change it's input route to built-in mic.

If you have more than one input (for example, if your device is connected to usbAudio or lineIn input device) you're still gonna need to use setPreferredInput in order to change your input route to built-in mic.