3
votes

I am using AVAudioSession to listen to voice input. it works fine for wired headphones but it is not working for connected bluetooth device. Following is the code I am using to set input to bluetooth mic

func setupSessionForRecording() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.allowBluetooth]) 
    } catch let error as NSError   {
        debugPrint("Error in listening "+error.localizedDescription)
    }
    var inputsPriority: [(type: String, input: AVAudioSessionPortDescription?)] = [
        (AVAudioSessionPortLineIn, nil),
        (AVAudioSessionPortHeadsetMic, nil),
        (AVAudioSessionPortBluetoothHFP, nil),
        (AVAudioSessionPortUSBAudio, nil),
        (AVAudioSessionPortCarAudio, nil),
        (AVAudioSessionPortBuiltInMic, nil),
        ]
    for availableInput in audioSession.availableInputs! {
        guard let index = inputsPriority.index(where: { $0.type == availableInput.portType }) else { continue }
        inputsPriority[index].input = availableInput
    }
    guard let input = inputsPriority.filter({ $0.input != nil }).first?.input else {
        fatalError("No Available Ports For Recording")
    }
    do {
        try audioSession.setPreferredInput(input)
        try audioSession.setMode(AVAudioSessionModeMeasurement)
        try audioSession.setActive(true, with: .notifyOthersOnDeactivation)
        try audioSession.setPreferredIOBufferDuration(10)
    } catch {
        fatalError("Error Setting Up Audio Session")
    }
}

This code stops taking input from device mic and I also get sound in bluetooth headset that it is ready to listen but it doesn't pick any input from device.

Also,

When I am trying to play any audio into bluetooth headset It doesn't work. Here is the code to play audio

        do {
            let output = AVAudioSession.sharedInstance().currentRoute.outputs[0].portType
            if output == "Receiver" || output == "Speaker"{
                try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
            }
            else{
                try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
            }
            print("Voice Out \(output)" )
        } catch let error as NSError {
            print("audioSession error: \(error.localizedDescription)")
            os_log("Error during changing the current audio route: %@"    , log: PollyVoiceViewController.log, type: .error, error)
        } catch {
            os_log("Unknown error during changing the current audio route", log: PollyVoiceViewController.log, type: .error)
        }
        do {
            let soundData =  try Data(contentsOf: url as URL)
            self.audioPlayer = try AVAudioPlayer(data: soundData)
            self.audioPlayer?.prepareToPlay()
            self.audioPlayer?.volume = 3.0
            self.audioPlayer?.delegate = self
            self.audioPlayer?.play()
        } catch let error as NSError {
            print("Error getting the audio file"+error.description)
        }
1
Hi, did you solved it?Ofir Malachi

1 Answers

1
votes

The reason is: BluetoothHFP is not available in AVAudioSessionModeMeasurement mode

AVAudioSessionModeMeasurement

After you set try audioSession.setMode(AVAudioSessionModeMeasurement), the audioSession.availableInputs is not contain the BluetoothHFP.

This mode is intended for apps that need to minimize the amount of system-supplied signal processing to input and output signals. If recording on devices with more than one built-in microphone, the primary microphone is used.

And in the document of setPreferredInput(_:)

The AVAudioSessionPortDescription must be in the availableInputs array.

The value of the inPort parameter must be one of the AVAudioSessionPortDescription objects in the availableInputs array. If this parameter specifies a port that is not already part of the current audio route and the app’s session controls audio routing, this method initiates a route change to use the preferred port.

And it must set up after setting the mode.

You must set a preferred input port only after setting the audio session’s category and mode and activating the session.