I have an AVAudioPlayerNode object which sends a callback once it is finished playing. That callback triggers many other functions in the app, one of which sends out a courtesy stop() message. For some reason, calling stop() at the moment the AVAudioPlayerNode finishes causes a crash. In the code here, I have abbreviated it so that the AVAudioPlayerNode just calls stop immediately to demonstrate the effect (rather than including my whole application). You can see clearly that it crashes. I don't understand why. Either a) the node is still playing and stop() stops it or b) it is done playing and stop can be ignored.
My guess is that this is some edge case where it is at the very end of the file buffer, and it is in an ambiguous state where has no more buffers remaining, yet is technically still playing. Perhaps calling stop() tries to flush the remaining buffers and they are empty?
func testAVAudioPlayerNode(){
let testBundle = Bundle(for: type(of: self))
let url = URL(fileURLWithPath: testBundle.path(forResource: "19_lyrics_1", ofType: "m4a")!)
let player = AVAudioPlayerNode()
let engine = AVAudioEngine()
let format = engine.mainMixerNode.outputFormat(forBus: 0)
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: format)
let delegate = FakePlayMonitorDelegate()
do {
let audioFile = try AVAudioFile(forReading: url)
let length = audioFile.length
player.scheduleFile(audioFile, at: nil, completionCallbackType: AVAudioPlayerNodeCompletionCallbackType.dataPlayedBack, completionHandler: {(completionType) in
print("playing = \(player.isPlaying)")
player.stop()
})
try engine.start()
let expectation = self.expectation(description: "playback")
delegate.expectation = expectation
player.play()
self.waitForExpectations(timeout: 6.0, handler: nil)
} catch {
}
}