AVAudioEngine player node excessive delay

346 views Asked by At

I am trying to use AVAudioEngine for listening to mic samples and playing them simultaneously via external speakers or headphones (assuming they are attached to iOS device). I tried the following using AVAudioPlayerNode and it works, but there is too much delay in the audio playback. Is there a way to hear sound realtime without delay?

var engine: AVAudioEngine!
var playerNode: AVAudioPlayerNode!
var mixer: AVAudioMixerNode!
var audioEngineRunning = false

public func setupAudioEngine() {
    
    self.engine = AVAudioEngine()
   
    let input = engine.inputNode
    let format = input.inputFormat(forBus: 0)
    
    playerNode = AVAudioPlayerNode()
    engine.attach(playerNode)
  
    self.mixer = engine.mainMixerNode
    
    engine.connect(self.playerNode, to: self.mixer, format: playerNode.outputFormat(forBus: 0))
    
    engine.inputNode.installTap(onBus: 0, bufferSize: 4096, format: format, block: { buffer, time in
        self.playerNode.scheduleBuffer(buffer, completionHandler: nil)
    })
    
    do {
        engine.prepare()
        try self.engine.start()
        audioEngineRunning = true
        
        self.playerNode.play()
    }
    catch {
        print("error couldn't start engine")
        audioEngineRunning = false
    }
    
}

  
1

There are 1 answers

0
Kakhi Kiknadze On

You could try connecting the input node straight into the main mixer or output node so that your input signal passes through the physical output.

let mainMixer = engine.mainMixerNode
let input = engine.inputNode
let format = input.inputFormat(forBus: 0)
engine.connect(input, to: mainMixer, fromBus: 0, toBus: 0, format: format)

If you need, you could, as well, split the signal using connection points. Assuming you've got some effect nodes connected to main mixer's 0 and 1 bus, you could connect input to bus 2 of main mixer and bus 0 on effect nodes. (This is just an example and you could choose your own busses).

let connectionPoints: [AVAudioConnectionPoint] = [
    .init(node: mainMixer, bus: 2),
    .init(node: someEffectNode, bus: 0),
    .init(node: someOtherEffectNode, bus: 0)
]
        
engine.connect(input, to: connectionPoints, fromBus: 0, format: format)

In my case there is a slight, millisecond delay that my ear notices but not too dealbreaker. There might be some other stuff that would reduce delay. Maybe we could provide smaller buffering value somewhere but I'm still new with AVFoundation and investigating some stuff.

UPDATE: I've just noticed you're using buffering size of 4096 which is too high for live performance btw. That's one of the reasons of the delay.