When Apple opened iOS for
development, they didn’t initially provide a method for accessing the
iPod library. This led to applications implementing their own libraries
for background music and a less-than-ideal experience for the end user.
Thankfully, developers
can now directly access the iPod library and play any of the available
music files. Best of all, this is amazingly simple to implement!
First, you’ll be using the MPMediaPickerController class to choose the music to play. There’s only a single method we’ll be calling from this class:
initWithMediaTypes: Initializes the media picker and filters the files that are available in the picker
We’ll configure its behavior with a handful of properties that can be set on the object:
prompt: A string that is displayed to the user when choosing songs
allowsPickingMultipleItems: Configures whether the user can choose one or more sound files
Like the AVAudioPlayer, we’re going to conform to the MPMediaPickerControllerDelegate protocol so that we can react when the user chooses a playlist. The method that we’ll be adding as part of the protocol is mediaPicker:didPickMediaItems:.
To play back the audio, we’ll take advantage of the MPMusicPlayerController
class, which can use the playlist returned by the media picker. To
control starting and pausing the playback, we’ll use four methods:
iPodMusicPlayer: This class method initializes the music player as an “iPod” music player, capable of accessing the iPod music library.
setQueueWithItemCollection: Sets the playback queue using a playlist (MPMediaItemCollection) object returned by the media picker.
play: Starts playing music.
pause: Pauses the music playback.
As you can see, when you get
the hang of one of the media classes, the others start to seem very
“familiar,” using similar initialization and playback control methods.
Implementing the Media Picker
To use a media picker,
we’ll follow steps similar to the Image Picker: We’ll initialize and
configure the behavior of the picker, and then add the picker as a modal
view. When the user is done with the picker, we’ll add the playlist it
returns to the music player and dismiss the picker view controller. If
the user decides they don’t want to pick anything, we’ll simply dismiss
the picker and move on.
For all of these steps to fall
into place, we must already have an instance of the music player so
that we can hand off the playlist. Recall that we declared an instance
variable musicPlayer for the MediaPlaygroundViewController class. We’ll go ahead and initialize this variable in the MediaPlaygroundViewController.m viewDidLoad method. Add the following line to the method now (the location isn’t important):
musicPlayer=[MPMusicPlayerController iPodMusicPlayer];
With that small addition, our instance of the music player is ready, so we can proceed with coding the chooseiPod: method to display the media picker.
Update the MediaPlaygroundViewController implementation file with the new method in Listing 1.
Listing 1.
1: -(IBAction)chooseiPod:(id)sender {
2: MPMediaPickerController *musicPicker;
3:
4: [musicPlayer stop];
5: nowPlaying.text=@"No Song Playing";
6: [ipodPlayButton setTitle:@"Play iPod Music"
7: forState:UIControlStateNormal];
8:
9: musicPicker = [[MPMediaPickerController alloc]
10: initWithMediaTypes: MPMediaTypeMusic];
11:
12: musicPicker.prompt = @"Choose Songs to Play" ;
13: musicPicker.allowsPickingMultipleItems = YES;
14: musicPicker.delegate = self;
15:
16: [self presentModalViewController:musicPicker animated:YES];
17: [musicPicker release];
18: }
|
First, line 2 declares the instance of MPMediaPickerController, musicPicker.
Next, lines 4–7 make sure that when the picker is called, the music player will stop playing its current song, the nowPlaying
label in the interface is set to the default string “No Song Playing”,
and the playback button is set to read “Play iPod Music”. These lines
aren’t necessary, but they keep our interface from being out of sync
with what is actually going on in the application.
Lines 9–10 allocate and initialize the media picker controller instance. It is initialized with a constant, MPMediaTypeMusic,
that defines the type of files the user will be allowed to choose with
the picker. You can provide any of five values listed here:
MPMediaTypeMusic | Music files |
MPMediaTypePodcast | Podcasts |
MPMediaTypeAudioBook | Audio books |
MPMediaTypeAnyAudio | Any audio type |
MPMediaTypeAny | Any media type |
Line 12 sets a message that will be displayed at the top of the music picker.
In line 13, we set the allowsPickingMultipleItems property to a Boolean value (YES or NO) to configure whether the user can select one or more media files.
Line 14 sets the delegate music picker’s delegate. In other words, it tells the musicPicker object to look in the MediaPlaygroundViewController for the MPMediaPickerControllerDelegate protocol methods.
Line 16 uses the musicPicker view controller to display the iPod music library over the top of our application’s view.
Finally, line 17 releases the musicPicker.
Watch Out!
If you find it confusing that you release the musicPicker
in this method, I don’t blame you. After the music picker is added to
the modal view, its retain count is incremented, so releasing it
essentially means that we aren’t responsible for it anymore. When the
modal view controller is dismissed later, the music picker will be
autoreleased.
What’s frustrating is that although this init, alloc, release pattern works well here,
you may find yourself thinking that some other object can be managed
similarly and end up releasing when you shouldn’t. Only a thorough read
of the corresponding Apple documentation will tell you with certainty
how something will behave.
Getting the Playlist
To get the playlist that is returned by media picker (an object called MPMediaItemCollection) and clean up after ourselves, we’ll add the mediaPicker:didPickMediaItems: protocol method from Listing 2 to our growing implementation.
Listing 2.
1: - (void)mediaPicker: (MPMediaPickerController *)mediaPicker
2: didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
3: [musicPlayer setQueueWithItemCollection: mediaItemCollection];
4: [self dismissModalViewControllerAnimated:YES];
5: }
|
When the user is finished picking songs in the media picker, this method is called and passed the chosen items in a MPMediaItemCollection object, mediaItemCollection. In line 3, the music player instance, musicPlayer, is subsequently configured with the playlist via the setQueueWithItemCollection: method.
To clean things up, the modal view is dismissed in line 4.
Cleaning Up After the Media Picker
We’ve got one more situation
to account for before we can wrap up the media picker: the possibility
of a user exiting the media picker without choosing anything (touching
Done without picking any tracks). To cover this event, we’ll add the
delegate protocol method mediaPickerDidCancel. As with the image picker, we just need to dismiss the modal view controller. Add this method to the MediaPlaygroundViewController.m file:
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
[self dismissModalViewControllerAnimated:YES];
}
Congratulations! You’re almost
finished! The media picker feature is now implemented, so our only
remaining task is to add the music player and make sure the
corresponding song titles are displayed.
Implementing the Music Player
Because the musicPlayer object was created in the viewDidLoad method of the view controller (see the start of “Implementing the Media Picker”) and the music player’s playlist was set in mediaPicker:didPickMediaItems:, the only real work that the playiPod: method must handle is starting and pausing playback.
To spice things up a bit, we’ll try to be a bit clever—toggling the ipodPlayButton title between Play iPod Music (the default) and Pause iPod Music as needed. As a final touch, we’ll access a property of musicPlayer MPMusicPlayerController object called nowPlayingItem. This property is an object of type MPMediaItem, which contains a string property called MPMediaItemPropertyTitle set to the name of the currently playing media file, if available.
Watch Out!
To grab the title from musicPlayer.nowPlayingItem, we’ll use a MPMediaItem instance method valueForProperty.
For example: [musicPlayer.nowPlayingItem valueForProperty: MPMediaItemPropertyTitle]
If you attempt to use musicPlayer.nowPlayingItem.MPMediaItemPropertyTitle, it will fail. You must use the valueForProperty: method to retrieve the title or other MPMediaItem properties.
Putting this all together, we get the implementation of playiPod in Listing 3.
Listing 3.
1: -(IBAction)playiPod:(id)sender {
2: if ([ipodPlayButton.titleLabel.text isEqualToString:@"Play iPod Music"]) {
3: [musicPlayer play];
4: [ipodPlayButton setTitle:@"Pause iPod Music"
5: forState:UIControlStateNormal];
6: nowPlaying.text=[musicPlayer.nowPlayingItem
7: valueForProperty:MPMediaItemPropertyTitle];
8: } else {
9: [musicPlayer pause];
10: [ipodPlayButton setTitle:@"Play iPod Music"
11: forState:UIControlStateNormal];
12: nowPlaying.text=@"No Song Playing";
13: }
14: }
|
Line 2 checks to see whether the ipodPlayButton
title is set to Play iPod Music. If it is, line 3 starts playback,
lines 4–5 reset the button to read “Pause iPod Music”, and lines 6–7 set
the nowPlaying label to the title of the current audio track.
If the ipodPlayButton title is not
Play iPod Music (line 8), the music is paused, the button title is
reset to Play iPod Music, and the onscreen label is changed to display
No Song Playing.
After completing the method
implementation, save the MediaPlaygroundViewController.m file, and
choose Build and Run to test the application. Pressing the Choose iPod
Music button will open a media picker, as shown in Figure 1.
After you’ve created a
playlist, press the Done button in the media picker, and then touch Play
iPod Music to begin playing the sounds you’ve chosen. The title of the
current song is displayed at the bottom of the interface.
There
was quite a bit covered in this hour’s lesson, but consider the
capabilities you’ve uncovered. Your projects can now tie into the same
media capabilities that Apple uses in its iPhone apps—delivering rich
multimedia to your users with a relatively minimal amount of coding.