Resources : Blog

Integrate Music Player in iPhone

By Nilesh Patil in iPhone - iPad

September 25, 2012

< All >

Overview:

Playing Music is quite simple in ios, we need to access the iPod(Music Player) instance in our app, and program it with MediaPlayer Framework provide public apis to access the features. we are going to learn following features

order viagra

of Music Player in this tutorial:

  1. Play/Pause Music.
  2. Play Next / Previous Song.
  3. Repeat the song list.
  4. Shuffle the songs.
  5. Control the Volume.
  6. Select Song from MPMediaPickerController interface.
  7. Select the Songs by defining custom Interface, by using MediaQuery.
  8. Reset(clear) the songs list.

PRE-REQUISITE:

ios >= 4
ios device (You cannot test the Music Player on simulator)
xcode 4

REQUIRED FRAMEWORK:

MediaPlayer Framework

Let us start with the example, open Xcode, create view based application, name it music player. add
MediaPlayer framework. This framework provide all the required API for music player.

Let us design the UI first, I am using interface builder to design the UI, Open the file, MUSICViewController.xib
add following component

Add following UI component to MUSICViewController View,

UIButton for Play/Pause Music.
UIButton, to play NEXT song in list.
UIButton, to play PREVIOUS song in list.
UISlider, to control music volume.
UIButton, to Repeat the Song list.
UIButton, to shuffle the Song list.
UIButton to select songs using MediaPicker Interface.
UIButton to select Playlist using custom interface.
UITableView, to display selected songs.

so after adding the UIComponent our Player will look like as below,

UIComponent

Music player xib

Now Open the file MUSICViewController.h

[objc]</p>
<p>#import<br />
#import<br />
#import &quot;PlayListView.h&quot;</p>
<p>@interface MUSICViewController : UIViewController</p>
<p>@end</p>
<p>[/objc]

Here we have added delegate for media Picker controller, MPMediaPickerControllerDelegate.
and delegate for PlayListView which will represent our custom interface to access songs from iPod library
and imported file

now open MUSICViewController.m file and add following code

[objc]</p>
<p>@interface MUSICViewController () {</p>
<p>@private</p>
<p>IBOutlet UIButton *_playPauseButton;</p>
<p>IBOutlet UILabel *_currentlyPlayingSong;</p>
<p>IBOutlet UITableView *_songTableView;</p>
<p>IBOutlet UISlider *_volumeSlider;</p>
<p>MPMediaItemCollection *_userMediaItemCollection;</p>
<p>PlayListView *_playListView;<br />
}</p>
<p>@property (nonatomic,strong) MPMusicPlayerController *musicPlayer;</p>
<p>- (IBAction)playPauseMusic:(id)sender;<br />
– (IBAction)playNextSongInList:(id)sender;<br />
– (IBAction)playPreviousSongInList:(id)sender;<br />
– (IBAction)repeatSongList:(id)sender;<br />
– (IBAction)shuffleSongList:(id)sender;<br />
– (IBAction)changeVolume:(id)sender;<br />
– (IBAction)selectSongs:(id)sender;<br />
– (IBAction)selectPlayList:(id)sender;</p>
<p>- (void)removeMusicPlayerObserver;<br />
– (void)addMusicPlayerObserver;<br />
– (void)initializeMusicPlayer;</p>
<p>- (void)updateTheMediaColledtionsItems:(MPMediaItemCollection *)mediaItemCollection;<br />
– (void)clearMusicList;</p>
<p>@end</p>
<p>@implementation MUSICViewController</p>
<p>@synthesize musicPlayer = _musicPlayer;</p>
<p>[/objc]

Above code is self explanatory here we have created the instance variables for Music player UI Component.
Define the methods for Play/Pause, Next, Previous, Repeat, Shuffle, Select Songs and Select Playlist.
Connected the instance variables and IBActions in xib.

[objc]</p>
<p>#pragma mark – View lifecycle</p>
<p>- (void)viewDidLoad<br />
{<br />
[super viewDidLoad];<br />
[self initializeMusicPlayer];</p>
<p>// Do any additional setup after loading the view, typically from a nib.<br />
}</p>
<p>- (void)viewDidUnload<br />
{<br />
[super viewDidUnload];<br />
// Release any retained subviews of the main view.<br />
// e.g. self.myOutlet = nil;</p>
<p> [self removeMusicPlayerObserver];</p>
<p>}</p>
<p>#pragma mark Music Player</p>
<p>- (void)initializeMusicPlayer {</p>
<p> self.musicPlayer = [MPMusicPlayerController iPodMusicPlayer];</p>
<p> [self.musicPlayer setShuffleMode:MPMusicShuffleModeOff];</p>
<p> [self.musicPlayer setRepeatMode:MPMusicRepeatModeNone];</p>
<p> [self clearMusicList];</p>
<p>}</p>
<p>[/objc]

Here we have initialize self.musicplayer to ipodMusicPlayer instance.
Set the Shuffle and repeat property of Music player to NO.
clearMusicList clears the Music player, songs list. As we are accessing the ipodMusicPlayer, it is possible that songs are already present in the iPod songs queue.

[objc]</p>
<p>#pragma Add observer to Music Player state Notifications</p>
<p>- (void)addMusicPlayerObserver {</p>
<p>[[NSNotificationCenter defaultCenter] addObserver:self<br />
selector:@selector(handleNowPlayingSongStateChanged:)<br />
name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification<br />
object:self.musicPlayer];</p>
<p>[[NSNotificationCenter defaultCenter] addObserver:self<br />
selector:@selector(handlePlaybackStateChanged:)<br />
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification<br />
object:self.musicPlayer];</p>
<p>[[NSNotificationCenter defaultCenter] addObserver:self<br />
selector:@selector(handleVolumeChangedFromOutSideApp:)<br />
name:MPMusicPlayerControllerVolumeDidChangeNotification<br />
object:self.musicPlayer];<br />
[self.musicPlayer beginGeneratingPlaybackNotifications];<br />
}</p>
<p>[/objc]

We have added notifications for music payer. This is needed since we are using the same instance of iPodMusicPlayer so if user changes the music / volume from outside this app our app need to know so accordingly we can handle it in our app.

[objc]</p>
<p>#pragma Remove observer for Music Player Notifications</p>
<p>- (void)removeMusicPlayerObserver {</p>
<p>[[NSNotificationCenter defaultCenter] removeObserver:self<br />
name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification<br />
object:self.musicPlayer];<br />
[[NSNotificationCenter defaultCenter] removeObserver:self<br />
name:MPMusicPlayerControllerPlaybackStateDidChangeNotification<br />
object:self.musicPlayer];<br />
[[NSNotificationCenter defaultCenter] removeObserver:self<br />
name:MPMusicPlayerControllerVolumeDidChangeNotification<br />
object:self.musicPlayer];</p>
<p>[self.musicPlayer endGeneratingPlaybackNotifications];<br />
}</p>
<p>[/objc]

Removed the added notifications in viewDidUnload.

[objc]</p>
<p>#pragma Music player Notification selectors</p>
<p>- (void)handleNowPlayingSongStateChanged:(id)notification {</p>
<p> MPMediaItem *currentItem = self.musicPlayer.nowPlayingItem;</p>
<p> _currentlyPlayingSong.text = [currentItem valueForProperty:MPMediaItemPropertyTitle];</p>
<p>}</p>
<p>[/objc]

handleNowPlayingSongStateChanged method gets called whenever the currently playing songs changes.
MPMediaItem, represents single media with all the associated informations.

[objc]</p>
<p>- (void)handlePlaybackStateChanged:(id)notification {</p>
<p> MPMusicPlaybackState playbackState = self.musicPlayer.playbackState;</p>
<p> if (playbackState == MPMusicPlaybackStatePaused || playbackState == MPMusicPlaybackStateStopped) {</p>
<p> [_playPauseButton setTitle:@&quot;Play&quot; forState:UIControlStateNormal];</p>
<p> }else if (playbackState == MPMusicPlaybackStatePlaying) {</p>
<p> [_playPauseButton setTitle:@&quot;Pause&quot; forState:UIControlStateNormal];<br />
}</p>
<p>}</p>
<p>[/objc]

handlePlaybackStateChanged method gets called when Play, Pause events occur,
MPMusicPlaybackState, represents the current Music player state i.e Play, Pause, Stop.

[objc]</p>
<p>- (void)handleVolumeChangedFromOutSideApp:(id)notification {</p>
<p> [_volumeSlider setValue:self.musicPlayer.volume animated:YES];</p>
<p>}</p>
<p>[/objc]

handleVolumeChangedFromOutSideApp method gets called when the volume is changed for example when you change the sound form external volume button of device.

All the above notifications methods get called when music player state is changed from the App(here I mean our sample app) or from outside app(i.e from iPod application).

[objc]</p>
<p>#pragma Music Player Controls Methods</p>
<p>- (IBAction)playPauseMusic:(id)sender {</p>
<p> MPMusicPlaybackState playbackState = self.musicPlayer.playbackState;</p>
<p> if (playbackState == MPMusicPlaybackStateStopped || playbackState == MPMusicPlaybackStatePaused) {</p>
<p> [self.musicPlayer play];</p>
<p> [_playPauseButton setTitle:@&quot;Play&quot; forState:UIControlStateNormal];</p>
<p> } else if (playbackState == MPMusicPlaybackStatePlaying) {</p>
<p> [self.musicPlayer pause];</p>
<p> [_playPauseButton setTitle:@&quot;Pause&quot; forState:UIControlStateNormal];<br />
}</p>
<p>}</p>
<p>[/objc]

playPauseMusic method gets called when user clicks on play/pause button.

[objc]</p>
<p>- (IBAction)playNextSongInList:(id)sender {</p>
<p> [self.musicPlayer skipToNextItem];</p>
<p>}</p>
<p>[/objc]

playNextSongInList gets called when user clicks the Next button, this method selects the next song in the list.

[objc]</p>
<p>- (IBAction)playPreviousSongInList:(id)sender {</p>
<p> static NSTimeInterval skipToBeginningOfSongIfElapsedTimeLongerThan = 3.5;</p>
<p> NSTimeInterval playbackTime = self.musicPlayer.currentPlaybackTime;<br />
[/objc]

if (playbackTimeplayPreviousSongInList gets called when user clicks the Previous button, this method first checks the current song elapse time if it is <= 3.5 then it select the previous song in the list, else it plays the currently playing song from the beginning.

[objc]<br />
– (IBAction)repeatSongList:(id)sender {<br />
if (self.musicPlayer.repeatMode == MPMusicRepeatModeNone ) {<br />
[self.musicPlayer setRepeatMode:MPMusicRepeatModeAll];<br />
[sender setTitle:@&quot;YES&quot; forState:UIControlStateNormal];<br />
} else {<br />
[self.musicPlayer setRepeatMode:MPMusicRepeatModeNone];<br />
[sender setTitle:@&quot;NO&quot; forState:UIControlStateNormal];<br />
}<br />
}<br />
[/objc]

repeatSongList method gets called when user click the Repeat button. if repeat is Set to YES then after all selected songs in the list are played then it start playing the list from the beginning again.

[objc]<br />
– (IBAction)shuffleSongList:(id)sender {<br />
if (self.musicPlayer.shuffleMode == MPMusicShuffleModeOff ) {<br />
[self.musicPlayer setShuffleMode:MPMusicShuffleModeSongs];<br />
[sender setTitle:@&quot;YES&quot; forState:UIControlStateNormal];<br />
} else {<br />
[self.musicPlayer setShuffleMode:MPMusicShuffleModeOff];<br />
[sender setTitle:@&quot;NO&quot; forState:UIControlStateNormal];<br />
}<br />
}<br />
[/objc]

shuffleSongList method gets called when user clicks the Shuffle button. if Shuffle is set to YES then songs are are played in random order.

[objc]<br />
– (IBAction)changeVolume:(id)sender {<br />
self.musicPlayer.volume = _volumeSlider.value;<br />
}<br />
[/objc]

ChangeVolume method gets called when user click on volume control.

[objc]<br />
– (IBAction)selectSongs:(id)sender {<br />
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAny];<br />
mediaPicker.delegate = self;<br />
[self presentModalViewController:mediaPicker animated:YES];<br />
}<br />
[/objc]

selectSong method displays the Media Player framework provided UI interface for selecting songs.

[objc]<br />
– (IBAction)selectPlayList:(id)sender {<br />
_playListView = [[PlayListView alloc] initWithFrame:CGRectMake(0,0, 320, 460)];<br />
[_playListView setPlayListViewDelegate:self];<br />
[self.view addSubview:_playListView];<br />
}<br />
[/objc]

selectPlayList method displays the custom created UI interface for selecting songs. We will discuss this “PlayListView” class later in the tutorial.

[objc]<br />
– (void)clearMusicList {<br />
MPMediaPropertyPredicate *predicate =<br />
[MPMediaPropertyPredicate predicateWithValue: @&quot;NoSongsName&quot; forProperty:MPMediaItemPropertyTitle];<br />
MPMediaQuery *mediaquery = [[MPMediaQuery alloc] init];<br />
[mediaquery addFilterPredicate:predicate];<br />
[self.musicPlayer setQueueWithQuery:mediaquery];<br />
self.musicPlayer.nowPlayingItem = nil;<br />
[self.musicPlayer stop];<br />
_userMediaItemCollection = nil;<br />
[_songTableView reloadData];<br />
}<br />
[/objc]

clearMusicList resets the current music. MPMediaPropertyPredicate defines the filtering criteria. MPMediaQuery contains the collection of media items based on filters. here our filter is song name @”NoSongsName” with matching string will be added to player queue.

[objc]<br />
#pragma mark MPMediaPickerController delegate methods<br />
– (void)mediaPicker: (MPMediaPickerController *)mediaPicker<br />
didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {<br />
[self dismissModalViewControllerAnimated:YES];<br />
[self updateTheMediaColledtionsItems:mediaItemCollection];<br />
}<br />
[/objc]

mediaPicker Delegate method gets called after user selects the song from MediaPicker view and clicks Done button.

[objc]<br />
– (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {<br />
[self dismissModalViewControllerAnimated:YES];<br />
}</p>
<p>- (void)updateTheMediaColledtionsItems:(MPMediaItemCollection *)mediaItemCollection {<br />
if (_userMediaItemCollection == nil) {<br />
_userMediaItemCollection = mediaItemCollection;<br />
[self.musicPlayer setQueueWithItemCollection: _userMediaItemCollection];<br />
[self.musicPlayer play];<br />
} else {<br />
BOOL wasPlaying = NO;</p>
<p> if (self.musicPlayer.playbackState == MPMusicPlaybackStatePlaying) {<br />
wasPlaying = YES;<br />
}<br />
MPMediaItem *nowPlayingItem = self.musicPlayer.nowPlayingItem;<br />
NSTimeInterval currentPlaybackTime = self.musicPlayer.currentPlaybackTime;<br />
NSMutableArray *currentSongsList= [[_userMediaItemCollection items] mutableCopy];<br />
NSArray *nowSelectedSongsList = [mediaItemCollection items];<br />
[currentSongsList addObjectsFromArray:nowSelectedSongsList];<br />
_userMediaItemCollection = [MPMediaItemCollection collectionWithItems:(NSArray *) currentSongsList];<br />
[self.musicPlayer setQueueWithItemCollection: _userMediaItemCollection];<br />
self.musicPlayer.nowPlayingItem = nowPlayingItem;<br />
self.musicPlayer.currentPlaybackTime = currentPlaybackTime;<br />
if (wasPlaying) {<br />
[self.musicPlayer play];<br />
}<br />
}<br />
[_songTableView reloadData];<br />
}<br />
[/objc]

updateTheMediaColledtionsItems method gets called for 2 scenarios 1) after selecting the songs from Media Picker view 2) after selecting songs from PlayList View. Here we check MPMediaItemCollection, which is collection of media items, is initialized or not. If it is not initialized then we initialize it with the mediaItemCollection passed in the argument. If already initialized then we check if the music player is playing. If yes then we collect the currently playing song properties and then add the new selected songs in the MPMediaItemCollection and assign it to Music player queue, and start playing the song which was interrupted while updating the payer queue.

[objc]<br />
#pragma mark PlayList View delegate methods<br />
– (void)selectedPlayList:(MPMediaPlaylist*)playlist {<br />
[self clearMusicList];<br />
[self updateTheMediaColledtionsItems:playlist];<br />
}<br />
[/objc]

selectedPlayList method gets called when user select the playlist. Pass the selected playList (which is collection of media items) to updateTheMediaColledtionsItems, before passing it to mediaItemCollection we reset the user’s Songs list, so that only playlist songs are displayed.

[objc]<br />
#pragma mark Table view data source -<br />
(NSInteger)tableView:(UITableView *)tableView<br />
numberOfRowsInSection:(NSInteger)section {<br />
return [_userMediaItemCollection.items count];<br />
}</p>
<p>// Customize the appearance of table view cells.<br />
– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {<br />
static NSString *cellIdentifier = @&quot;Cell&quot;;<br />
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];<br />
if (cell == nil) {<br />
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];<br />
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];<br />
}<br />
MPMediaItem *anItem = (MPMediaItem *)[_userMediaItemCollection.items objectAtIndex: [indexPath row]];<br />
if (anItem) {<br />
cell.textLabel.text = [anItem valueForProperty:MPMediaItemPropertyTitle];<br />
}<br />
return cell;<br />
}</p>
<p>#pragma mark – #pragma mark Table view delegate </p>
<p>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {<br />
if ([_userMediaItemCollection.items count] &gt; 0) {<br />
MPMediaItem *selectedItem = (MPMediaItem *)[_userMediaItemCollection.items objectAtIndex:[indexPath row]];<br />
[self.musicPlayer setNowPlayingItem:selectedItem];<br />
[self.musicPlayer play];<br />
}</p>
<p> [tableView deselectRowAtIndexPath:indexPath animated:YES];</p>
<p>}</p>
<p>-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath {</p>
<p> return 20;<br />
}</p>
<p>[/objc]

We are done with MUSICViewController.m.
Now we are going to add the custom interface for selecting playlist, remember we are adding interface which will fetch all the created playlist from the music library. So if you do not have create one.

Add UIView Class name it “PlayListView”
Open “PlayListView.h”

[objc]</p>
<p>#import<br />
#import</p>
<p>@protocol PlayListViewDelegate;</p>
<p>@interface PlayListView : UIView</p>
<p>@property (assign) id playListViewDelegate;</p>
<p>@end</p>
<p>@protocol PlayListViewDelegate</p>
<p>- (void)selectedPlayList:(MPMediaPlaylist*)playlist;</p>
<p>@end</p>
<p>[/objc]

Here we define protocol which will be used in MUSICViewController to get the selected playlist.

Open “PlayListView.m”

[objc]</p>
<p>#import &quot;PlayListView.h&quot;</p>
<p>@interface PlayListView () {</p>
<p>@private</p>
<p> UITableView *_playListTableView;</p>
<p> NSMutableArray *_playListArray;<br />
}</p>
<p>- (void)getPlayList;<br />
– (void)createPlayListTable;<br />
– (void)createCloseButton;</p>
<p>@end</p>
<p>@implementation PlayListView</p>
<p>@synthesize playListViewDelegate = _playListViewDelegate;</p>
<p>- (id)initWithFrame:(CGRect)frame<br />
{<br />
self = [super initWithFrame:frame];<br />
if (self) {</p>
<p> [self getPlayList];<br />
[self createCloseButton];<br />
[self createPlayListTable];</p>
<p> }<br />
return self;<br />
}</p>
<p>- (void)getPlayList {</p>
<p> MPMediaQuery *playlistsQuery = [MPMediaQuery playlistsQuery];<br />
_playListArray = (NSMutableArray*)[playlistsQuery collections];<br />
}</p>
<p>[/objc]

getPlayList this method fetches the playlist present in the music library. So please make sure you create the playlist. Basically MPMediaQuery as discussed above (reference clear play list method) it represent the mediaitemCollection based on filters i.e predicates. since playlistsQuery predicates is already present in mediaPlayer framework we use it directly. if you want to access some particular songs then you can create the predicate with the required filter and pass it to mediaquery.

[objc]</p>
<p>- (void)createPlayListTable {</p>
<p> _playListTableView = [[UITableView alloc]initWithFrame:CGRectMake(0,30,320,430)];<br />
[_playListTableView setDelegate:self];<br />
[_playListTableView setDataSource:self];</p>
<p> [self addSubview: _playListTableView];</p>
<p>}</p>
<p>- (void)createCloseButton {</p>
<p> UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];</p>
<p> [closeButton setFrame:CGRectMake(2,2,50,25)];</p>
<p> [closeButton addTarget:self action:@selector(closePlayListView) forControlEvents:UIControlEventTouchUpInside];</p>
<p> [closeButton setTitle:@&quot;Close&quot; forState:UIControlStateNormal];</p>
<p> [self addSubview: closeButton];</p>
<p>}</p>
<p>- (void)closePlayListView {</p>
<p> [self removeFromSuperview];<br />
}</p>
<p>#pragma mark -<br />
#pragma mark Table view data source</p>
<p>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section<br />
{</p>
<p> return [_playListArray count];<br />
}</p>
<p>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath<br />
{</p>
<p> static NSString *cellIdentifier = @&quot;Cell&quot;;</p>
<p> UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];</p>
<p> if (cell == nil) {</p>
<p> cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];</p>
<p> [cell setSelectionStyle:UITableViewCellSelectionStyleGray];<br />
}</p>
<p> MPMediaPlaylist *playlist = [_playListArray objectAtIndex:[indexPath row]];</p>
<p> NSString *playlistName = ;</p>
<p> cell.textLabel.text = playlistName;</p>
<p> return cell;<br />
}</p>
<p>#pragma mark -<br />
#pragma mark Table view delegate</p>
<p>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath<br />
{</p>
<p> if ([_playListArray count] &gt; 0) {</p>
<p> MPMediaPlaylist *selectedplaylist = [_playListArray objectAtIndex:[indexPath row]];</p>
<p> if ([self.playListViewDelegate respondsToSelector:@selector(selectedPlayList:)]) {</p>
<p> [self.playListViewDelegate selectedPlayList:selectedplaylist];</p>
<p> }</p>
<p> [self removeFromSuperview];<br />
}</p>
<p> [tableView deselectRowAtIndexPath:indexPath animated:YES];</p>
<p>}</p>
<p>-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*) indexPath<br />
{</p>
<p> return 30;<br />
}</p>
<p>@end</p>
<p>[/objc]

We are done with the Music Player Tutorial, build and run on iOS Device.
you can download the source code from here

  • Radu Ursache

    thank you for your post, really helped. btw, fix the code samples.

  • http://gentleninja.com/blog/makeyourownapp Ridhi Mistry

    This is a very good thing especially to those fresh developers. Simple but very accurate info… Many thanks for sharing this one. A must read post!

    I have built an IOS Music Player Code Script – http://gentleninja.com/musicplayercodescript