Entering background on iOS4 to play audio

iwasrobbed picture iwasrobbed · Jul 1, 2010 · Viewed 12.5k times · Source

The documentation is rather poorly written when talking about playing audio in the background. It gives the impression that all you have to do to continue playing the audio that you are currently playing is to just add a key/value pair to the info.plist file and wallah, it's magic.

However, this is not the case. For instance, if I play an mp3 that is 2 minutes long, obviously the audio is long enough to be able to play after I hit the home button to send my app to the background. The thing is, even though I have that key/value pair in my info.plist file, it pauses the audio and then resumes playing once I switch back to the app.

Apple states that all frameworks for audio support background and the sound should continue playing up until the point that it ends and then Apple will suspend your app.

So, my question is: What are they doing that I am missing? Do I also have to use their new delegates somehow or call the audio on the applicationDidEnterBackground? To me, that wouldn't make sense since I am not saving state (they do for me with fast app switching) or really handling anything in the background other than audio which they say is supposed to be handled automagically.

Answer

progrmr picture progrmr · Jul 1, 2010

You also need to make calls to beginBackgroundTaskWithExpirationHandler: before you start a song (do it all the time whether in foreground or not) and endBackgroundTask when it ends.

This tells iOS that you want to be able to continue processing even if your app gets put in the background. It does not create a new task or thread, it's just a flag to iOS that you want to keep running. The audio will play to completion without this, but when it completes if you want to start another track you must be able to run in the background.

You can use it like this:

// ivar, initialized to UIBackgroundTaskInvalid in awakeFromNib
UIBackgroundTaskIdentifier bgTaskId; 

When starting an audio player we save the bg task id:

if ([audioPlayer play]) {
  bgTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
}

Now the audioPlayerDidFinishPlaying: callback will still occur because we have told iOS that we are doing a task that needs to continue even if we get put in the background. That way we get the callback and can start the next audio file.

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)success
{
    UIBackgroundTaskIdentifier newTaskId = UIBackgroundTaskInvalid;

    if (self.haveMoreAudioToPlay) {
        newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
        [self playNextAudioFile];
    }

    if (bgTaskId != UIBackgroundTaskInvalid) {
        [[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
    }

    bgTaskId = newTaskId;
}