Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioPlayer preloaded sound leaks from memory

I have an AVAudioPlayer instance that loads sound in memory with audioPlayer.prepareToPlay(), and then after a few start playing it. I have a problem that in approximately ten minutes after entering background, it leaks from memory and I is not being prepared. After that fed hours, I don't have an ability to run prepareToPlay() again. How to leave that preloaded sound in memory for a long term? I am preparing sound to play in applicationDidFinishLaunchingWithOptionsmethod:

let dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
    dispatch_async(dispatchQueue, {[weak self] in
        var audioSessionError: NSError?

        let audioSession = AVAudioSession.sharedInstance()
        NSNotificationCenter.defaultCenter().addObserver(self!, selector: "handleInterruption:", name: AVAudioSessionInterruptionNotification, object: nil)
        audioSession.setActive(true, error: nil)

        if (audioSession.setCategory(AVAudioSessionCategoryPlayback, error: &audioSessionError)) {
            println("Successfully set the audio session")
        } else {
            println("Could not set the audio session")
        }

        let filePath = NSBundle.mainBundle().pathForResource("sound", ofType:"mp3")
        let fileData = NSData(contentsOfFile: filePath!, options: .DataReadingMappedIfSafe, error: nil)
        var error:NSError?

        self!.audioPlayer = AVAudioPlayer(data: fileData, error: &error)

        self!.audioPlayer?.numberOfLoops = -1

        self!.audioPlayer?.delegate = self

        if (self?.audioPlayer?.prepareToPlay() != false) {
            println("Successfully prepared for playing")
        } else {
            println("Failed to prepare for playing")
        }
    })

Then in didReceiveRemoteNotification I am trying to play it in background: self.audioPlayer?.play(), it returns true. Probably it works, but after about 10 - 20 minutes it does not work. And note that .play() now returns false.

  1. Is there a sense to disable ARC (Automatic Reference Counting) to release and dealloc audioPlayer manually?

  2. Maybe I need to use lower level APIs such as OpenAL? However I won't use it since it is deprecated in iOS 9 and later I will need to rewrite it without OpenAL.

  3. Any more ideas? Maybe I need to use Audio Units with RemoteIO? If it will work, provide some examples please.

  4. Maybe there are third party frameworks like ObjectAL - an easy implementation of OpenAL. As I know it is available in iOS 9.

These methods are just my assumptions. But them main question remains the same: Will those methods work from background?

like image 373
Nikita Zernov Avatar asked Jul 03 '15 18:07

Nikita Zernov


1 Answers

You should just disable ARC. When you enter backgroud, then if you don't use it it is being released. In Swift create AVAudioPlayer as Unmanaged<T> object.

like image 79
Зернов Алексей Avatar answered Sep 23 '22 11:09

Зернов Алексей