Search code examples
iosswiftxcodeavplayeravaudioplayer

AVAudioPlayer causing app to crash


I am working on an app that receives an integer every 200MS and will play a tone for the size of the integer evenly spread over the next 200MS interval. The sound works fine but the app crashes at completely random times. I originally was testing on an ipod(5th gen) and it crashes anywhere between 1 min and 10 min giving me the error

"EXC_BREAKPOINT (EXC_ARM_BREAKPOINT, subcode=0xdefe)"

Before I was getting an EXC_BAD_ACCESS but after moving the player definition to the AppDelegate among other attempted fixes the message is now the ARM Breakpoint one. I also tried on my iPhone 6S+ and it ran for over 15 min with no crashes.

The player is defined within the ViewController(as suggested by another post on here) like so:

var audioPlayer: AVAudioPlayer!

Here is the code within a view controller class that works to play the tone:

//called for every beep
@objc func playSound() {
    toneCount += 1
    if toneCount >= totalTones{
        if toneTimer != nil {
            toneTimer?.invalidate()
            toneTimer = nil
        }
    }
    do{
        guard let url = Bundle.main.url(forResource: "geiger", withExtension: "mp3") else { return }
        audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)
        audioPlayer.play()
    }catch{
        print("failed")
    }

}

This is output to console when the crash happens:

"[AVAudioPlayer performSelector:withObject:]: message sent to deallocated instance 0x1886b590"

In the stackframe(not sure if this is correct term, but the frame to the left of the console output) the player variable is brought up showing it is equal to (AVAudioPlayer)? and within the player variable is "ObjectiveC.NSObject" which itself is empty

Really not too sure what else to try as I've tried making player a weak variable, but then the tone doesn't play. I've tried defining it in the view controller. It also puzzles me as to why it seems to not crash on the iphone 6S+ and why it is completely random as to when the crash happens.

I've also tried to do a singleton class in a separate file like this:

let tone = soundtest()

class soundtest {
    func playTone() {
        do{
            print("played Sound")
            guard let url = Bundle.main.url(forResource: "geiger", withExtension: "mp3") else { return }
            let audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try AVAudioSession.sharedInstance().setActive(true)
            audioPlayer.play()
        }catch{
            print("failed")
        }
    }
}

the attempt to play the tone sound like this:

tone.playTone()

and now the sound doesnt play


Solution

  • Most likely the crash is happening because the audioPlayer was released before the sound end. To prevent that, as your wrote in comment, you can check if player is playing sound before calling playSound. Or store each player in array, then release when sound end.