So now you have to understand
first understand what installTap does when you call it on inputNode?
Ans:
it just listens to Node's Buffer but before installation we have to tell it which Bus to installTap, what will be the bufferSize that will come from inputNode, and what will be the audioFormat of input of inputNode
so whenever you want change the input microphone there are proper safe flow which has to be followed.
class AudioProcessor
{
// Audio resources
var audioEngine: AVAudioEngine!
var inputNode: AVAudioInputNode!
var formatIn: AVAudioFormat
static let sharedInstance = AudioProcessor()
private init()
{
self.audioEngine = AudioResources.sharedInstance.audioEngine
self.inputNode = self.audioEngine.inputNode
self.formatIn = self.inputNode.inputFormat(forBus: 0)
}
open func pause()
{
self.audioEngine.inputNode.removeTap(onBus: 0)
self.audioEngine.stop()
}
open func resume()
{
if !self.audioEngine.isRunning
{
self.installTap()
self.audioEngine.prepare()
self.audioEngine.inputNode.volume = 1.0
try self.audioEngine.start()
}
}
func installTap()
{
self.audioEngine = AudioResources.sharedInstance.audioEngine
self.inputNode = self.audioEngine.inputNode
self.formatIn = self.inputNode.inputFormat(forBus: 0)
self.inputNode.installTap(
onBus: 0,
bufferSize: 4096,
format: self.formatIn
)
{ (buffer,_) in
//DO WHATEVER YOU WANT TO DO WITH BUFFER
}
}
}
//After that add notification observers in your VC
NotificationCenter.default.addObserver(self, selector: #selector(self.handleRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil)
@objc func handleRouteChange(_ notification: Notification) {
let devices = AVAudioSession.sharedInstance().availableInputs ?? []
let currentDevice = AVAudioSession.sharedInstance().currentRoute.inputs.first?.portName ?? ""
if let inputDevicePortDescription = devices.first(where: {$0.portName == currentDevice}) {
AudioProcessor.sharedInstance.pause()
AudioProcessor.sharedInstance.resume()
}
}