Question

I'm working on an application that integrates with the iPod Music app on iOS. It displays different music groupings (i.e., MPMediaItemCollections) and it allows the user to play these groupings in the Music app, using [MPMusicPlayerController ipodMusicPlayer].

My issue is that I'm having difficulty getting shuffle functionality working the same way between my app and the music app. When I play a song, I call:

MPMusicPlayerController* musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
[musicPlayer stop];
MPMediaItemCollection* collection = [self.displayedContainerGroup getMediaItemCollection];
[musicPlayer setQueueWithItemCollection:collection];
[musicPlayer setNowPlayingItem:[container getMediaItem];
[musicPlayer play];

This works great if shuffle is turned off. If the user selects a song (which is part of an album), this plays the album in the music app and starts on the specified song.

If shuffle is turned on, though, what this appears to do is shuffle the songs first, and then jumps to the new nowPlayingItem in the order that they were just shuffled in. The problem with this is that unless the nowPlayingItem was shuffled to first in order, it doensn't end up playing all the songs in the album.

The MPMusicPlayerController documentation says about nowPlayingItem: "To specify that playback should begin at a particular media item in the playback queue, set this property to that item while the music player is stopped or paused."

So, I'm wondering if there's a way to make this work for shuffle mode - start on one user-selected song in an album, and then play all the rest of the songs shuffled. Or should I just create a custom MPMediaItemCollection and shuffle it myself for this?

Was it helpful?

Solution

This seems to have worked; I had to turn off shuffle, add the songs, switch to the now playing item, and then turn shuffle back on:

[musicPlayer stop];
BOOL shuffleWasOn = NO;
if (musicPlayer.shuffleMode != MPMusicShuffleModeOff)
{
     musicPlayer.shuffleMode = MPMusicShuffleModeOff;
     shuffleWasOn = YES;
}
[musicPlayer setQueueWithItemCollection:mediaItemCollectionIn];
[musicPlayer setNowPlayingItem:mediaItemIn];
if (shuffleWasOn)
     musicPlayer.shuffleMode = MPMusicShuffleModeSongs;

[musicPlayer play];

OTHER TIPS

Here is a Swift 4 implementation of the answer by DivideByZer0. I have restructured the code into two functions, stop() and play(), which can be used independently to stop and play too.

Important: One important difference, I found that it is necessary to store shuffleMode before calling musicPlayer.stop(). shuffleMode sometimes changes after calling musicPlayer.stop().

let musicPlayer = MPMusicPlayerController.systemMusicPlayer
private var shuffleMode = MPMusicPlayerController.systemMusicPlayer.shuffleMode

private func stop() {
    shuffleMode = musicPlayer.shuffleMode
    musicPlayer.shuffleMode = MPMusicShuffleMode.off

    musicPlayer.stop()
}

private func play() {
    musicPlayer.shuffleMode = shuffleMode

    musicPlayer.prepareToPlay()
    musicPlayer.play()
}

func play(itemCollection: MPMediaItemCollection, startingAt index: Int) {
    stop()

    musicPlayer.setQueue(with: itemCollection)
    musicPlayer.nowPlayingItem = itemCollection.items[index]

    play()
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top