MysteryPancake MysteryPancake - 29 days ago 7
Swift Question

Swift: How to stop scheduleBuffer completion handler being called when interrupted?

So, I have a AVAudioPlayerNode I'm scheduling a lot of buffers on using the following:

node.scheduleBuffer(buffer, at: nil, options: .interrupts, completionHandler: completeFunc)


But I'm having a bit of a problem. If I play another buffer interrupting the currently playing buffer, the completion handler for the buffer getting interrupted is still being called. I guess this makes sense, but I can't seem to find a way to check if the file actually COMPLETED playing or if it was interrupted. Is there a way I can do this?

Any answers will help!

Answer

You will need an interruption state variable that is referenced in the completion handler and toggled by the interrupting code. Here's some shorthand code that makes some assumptions on how you're looping through buffers:

var node: AVAudioPlayerNode!
var loopingBuffers: [AVAudioPCMBuffer] = [buffer1, buffer2, buffer3]
var interruptBuffers = false // state variable to handle the interruption

func scheduleNextBuffer() {
    /* code to find the next buffer in the loopingBuffers queue */

    // assuming you have instantiated an AVAudioPlayerNode elsewhere
    node.scheduleBuffer(nextBuffer, completionHandler: bufferCompletion)
}

func bufferCompletion() {
    // check the state variable to make certain the completionHandler isn't being triggered by a scheduling interruption
    guard !interruptBuffers else { return }
    scheduleNextBuffer()
}

func interruptBuffers() {
    let newBuffers: [AVAudioPCMBuffer] = [buffer4, buffer5, buffer6]

    interruptBuffers = true

    node.scheduleBuffer(buffer4, at: nil, options: .interrupts, completionHandler: bufferCompletion)

    // cleanup your state and queue up your new buffers
    interruptBuffers = false
    loopingBuffers = newBuffers
}
Comments