Adding iPod Music Playback to your App

Development

I recently added the ability to play iPod Music to UtopiaGL (and Gravity Wave).  It’s very straight forward to do that with iPhone OS 3.x, but I wanted to add it in such a way that I could release updates to Apps initially submitted targeting OS 2.x, so that they could continue to run on OS 2.x devices, but would take advantage of the newer APIs on OS 3.x devices. It turns out this is pretty simple to do. Here is how it works.

iPod Library Music Picker

The shortest path to getting this up and running is to use the MPMediaPickerController, conveniently provided for you out of the box. This saves you all the hassle of presenting the user’s library to them in a structured way. Essentially is mirrors the actual iPod library interface, allowing the user to select their music in a familiar setting. Kicking off the picker couldn’t be easier:

- (void) selectMusic
{
    MPMediaPickerController* pickerController = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
    pickerController.prompt = @"Add songs to playlist";
    pickerController.allowsPickingMultipleItems = YES;
    pickerController.delegate = self;
    [_viewController presentModalViewController: pickerController animated:YES];
    [pickerController release];
}

In order to respond to the results of the Picker you need to implement the two delegate methods as below, which deal with Done and Cancel events.

- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection{
    [_viewController dismissModalViewControllerAnimated:YES];
    if( [mediaItemCollection count] )
    {
        MPMusicPlayerController* iPodController = [MPMusicPlayerController iPodMusicPlayer];
        [iPodController stop];
        [iPodController setQueueWithItemCollection: mediaItemCollection];
        [iPodController play];
    }
}

- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker{
    [_viewController dismissModalViewControllerAnimated:YES];
}

iPod Library Music Player

You have two choices when playing the selected music.  You can either use a local version of the player, which doesn’t modify the iPod’s current playlist, or you can use the actual iPod player, which does. I chose to use the actual iPod player, so that I can allow the user to start the App with music already playing.  At start up, if I detect that music is playing, I let it continue into the App.  If music was playing on start-up, I remember that and on App Exit, I don’t kill the playback, otherwise I do.  This means that if the user is listening to music, and then plays my App, they get to keep on listening to their music, during the App and even after they have exited my App.  If the user initiates playback while in my App, I kill playback on App exit.  In order to fully support this, you need to declare your app as being Ambient, described next.

Simultaneous iPod Music and Sound Effects

In order to allow music to continue into an App on start up, and also to allow simultaneous playback on in-game sound effects you need to declare you App as being ‘Ambient’.  This instructs the OS on how to behave when the App is starting up (should it kill iPod music, or is it ok to keep on playing?) and when you issue instructions to play addition sounds in-app (how should they be mixed?). In order to do this, you use the AVAudioSession class to set the category of your App to AVAudioSessionCategoryAmbient.  You need to do this right at the beginning of App initialization.

Class audioSessionClass = (NSClassFromString(@"AVAudioSession"));
if( audioSessionClass != nil )
{
    AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    NSError* audioSessionError = nil;
    [audioSession setCategory: AVAudioSessionCategoryAmbient error: &audioSessionError];
    if( audioSessionError )
    {
        // Error handling...
    }
}

Compiling on 3.x, Targeting 2.x

If you’re only targeting 3.x, then you’re pretty much done. If you need to target 2.x builds and programmatically detect if the current handset supports 3.x features then you have a few more hurdles to jump.  Noel Llopis has written a good article about this, and there is example code on the Apple Developer site (registration required).  In essence you do the following.

  • Set Base SDK to 3.x.
  • Set Compiler to 4.2.
  • Set Target OS to 2.x.
  • Include 3.x Frameworks, but use ‘Weak’ Linking, instead of ‘Required’.
  • Wrap 3.x API calls around code guards to check if they are supported, and provide fallback paths if not.

It’s worth pointing out that I didn’t have the linker problem that Noel cites – everything worked fine for me without any additional effort. I’m guessing that the issue has since been rectified (I’m working with Xcode 3.1.4).

Conclusion

It couldn’t be easier to add iPod Music support to your App, and thanks to the latest additions to the SDK, you can integrate very cleanly with the iPod look and feel.  With the flexibility provided in the build system, you can comfortably take advantage of this API (devices permitting), and continue targeting older OS versions (and support all your existing users) from a single build.

Filed under: , , , , .

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>