4

Is there any possibility to identify if the AVAudioEngine did finish its played sound? In the past I used the AVAudioPlayer's function:

func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
    // Code after finished the played sound
}

Now I need some effects, but there is no func of AVAudioEnginge provided that identifies the end of the played sound.

I searched a lot, but unfortunately I found only this func in the documentation of AVAudioEngine:

var running: Bool { get }

My current solution will be to check the "running" boolean, if it's false the player is not playing anymore. Does somebody know a better solution for AVAudioEngine? Thank you very much!

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
AlexWoe89
  • 844
  • 1
  • 11
  • 23
  • 1
    My current solution: I have a NSTimer, that triggers an event every millisecon. If the AVAudioEngine reaches its end time, I trigger manually my own didFinish func.... If anybody has a better solution, please feel free to share it here. Thank you. – AlexWoe89 Dec 15 '15 at 11:00

3 Answers3

3

I attach an AVAudioPlayerNode to my engine

player = AVAudioPlayerNode()

    let file = try! AVAudioFile(forReading: url)
    let buffer = AVAudioPCMBuffer(PCMFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))

    do {
        print("read")
        try file.readIntoBuffer(buffer)
    } catch _ {
    }

engine.attachNode(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)

self.player.scheduleBuffer(buffer, completionHandler: {
    print("Complete")
})

        engine.prepare()
    do {
        try engine.start()
    } catch _ {
        print("Play session Error")
    }

    player.play()

I hope that helps!

user4812000
  • 1,033
  • 1
  • 13
  • 24
  • Happy to help! If this worked for you, please mark it as the answer. – user4812000 Dec 31 '15 at 16:50
  • 1
    For me this only fires when the scheduling is completed, which is almost immediately. It doesn't fire when the media playback completes. – jho Jun 12 '23 at 17:02
2

I also used a NSTimer as I haven't found any other solution/delegate. But it's fired only once and starts right after the audiofile ends (that means, the very first parameter "seconds" has the value of the duration of the audiofile). The selector is my "custom delegate" function.

Saerdn
  • 218
  • 2
  • 17
1

The accepted answer seems to call the completionHandler as soon as SCHEDULING is finished, not as soon as playing the audio file is finished.

As per iOS 11.0+ / macOS 10.13+ use:

self.player.scheduleBuffer(buffer, completionCallbackType: .dataPlayedBack completionHandler: {
    print("Complete")
})
hotdogsoup.nl
  • 1,078
  • 1
  • 9
  • 22