Nikhil Sridhar
Nikhil Sridhar

Reputation: 1740

Record and playback using bluetooth earphone's mic & internal speaker in Swift

I currently have a pair of Bluetooth earbuds. From this post, I have the code needed to retrieve audio from the Bluetooth earbuds' microphone and then playback the audio through the Bluetooth earbuds. However, I want to modify the code so that I can retrieve audio from the Bluetooth earbuds' microphone and then playback the audio through the phone's INTERNAL speaker / through any other pair of earbuds that may be physically connected to the phone. How would I go about doing that? This is my current code:

import UIKit
import AVFoundation

class PlayRecordVC: UIViewController, AVAudioRecorderDelegate {

    let audioSession = AVAudioSession.sharedInstance()
    let player = AVAudioPlayerNode()
    let engine = AVAudioEngine()

    override func viewDidLoad() {
        super.viewDidLoad()

        do{
            try audioSession.setCategory(.playAndRecord, mode: .default, options: [.allowBluetooth])
            try audioSession.overrideOutputAudioPort(.speaker)
            try audioSession.setActive(true)
        } catch{
            print(error.localizedDescription)
        }
        let input = engine.inputNode

        engine.attach(player)

        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)

        engine.connect(player, to: engine.mainMixerNode, format: inputFormat)

        input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) -> Void in
            self.player.scheduleBuffer(buffer)
            print(buffer)
        }
    }

    @IBAction func start(_ sender: UIButton) {
        try! engine.start()
        player.play()
    }

    @IBAction func stop(_ sender: UIButton) {
        engine.stop()
        player.stop()
    }

}

UPDATE:

When I add the line audioSession.overrideOutputAudioPort(.speaker) no audio plays at all (neither from the Bluetooth earbuds nor the phone's internal speaker)

Upvotes: 3

Views: 1941

Answers (2)

Julian Silvestri
Julian Silvestri

Reputation: 2027

let audioSession = AVAudioSession.sharedInstance()
do {

    try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .allowBluetooth)
    try audioSession.setMode(AVAudioSessionModeDefault)
    try audioSession.setActive(true)
} catch {
print(error)
}

need to define the correct mode I believe. Not exactly sure which mode will work best in your case. https://developer.apple.com/documentation/avfoundation/avaudiosession/mode

This link below has extension for checking if microphone is plugged in. https://stackoverflow.com/a/52460651/8272698

Upvotes: 1

Enricoza
Enricoza

Reputation: 1142

I haven't tested if this actually causes microphone to still be used by the headphones, but by default to route the audio to the speakers instead of the headphones this should work:

try! audioSession.overrideOutputAudioPort(.speaker)  

Here is the documentation of the method.

There is also this category option you could give to the audio session to have that same effect but also avoid it to be reset by gestures (like attaching new headphones).

If after your test you find out this actually moves also the recording to use the internal microphone, I think there is no other way (at least no other way that I found of).

Upvotes: 1

Related Questions