Introduction

If you are writing a software which plays media on Windows Phone 7 and you want that software up in the marketplace, you will have to fulfill the wp7 application certification requirement 6.5.3:

Applications that Play a Video or Audio Segment

"An application may interrupt the currently playing music to play a non-interactive full motion video or audio segment (e.g. cut-scene or media clip) without asking for user consent. If music was playing prior to the segment, the application must resume music when the segment has completed."

Background

As I know, this can't be done completely yet, because of a little bug which I heard is under fixing! Currently there is no SDK functionality that lets you just resume the playback after your mediaplay. The reason why it can't be done requires a little understanding about the system's MediaPlayer:

The MediaPlayer class here provides the functions to control the system's MediaPlayer. This MediaPlayer stores the currently played songs in a special Queue which can be indexed like arrays too.

Basically there are 2 main problems with this Queue:

If you play a MediaContent on some MediaElement or SmoothStreamingMediaElement, it overrides the System's MediaElement Queue too, so you can't resume the Current MediaPlay.

It's a read-only collection, that means if you store the Songs played before your play, you can't restore them back to the Queue.

In XNA games, you can use music effects without damaging the queue, but if you want to play background music, that will stop the music and override the queue. One of Microsoft's solution with the Game Twin Blades is that the music plays when the game starts, it asks the user whether he/she wants to continue listening to the music or stop and hear the game music after. If we choose not to stop the music, we can play with our own music in the background.

The Workaround

Currently we have only one way to override the Queue, Playing Media. There are 4 scenarios of Background music playing on the Phone:

The user listens to the Radio

The user listens to a Song from the Music collection

The user listens to an Album from the Music Collection

The user listens to a PlayList from the Music Collection

The user adds songs from 2 or more albums/playlists to the now playing collection (find the explanation below)

So we store the Queue and the current Radio state before our media play, and then when we need to restore the previous state, we just check these 4 scenarios if it fits the stored list of songs or not.

After checking the stored RadioPower state, we need to iterate over the playlists and albums, and see which one has the same item number, and contains all songs from the stored queue. Then find the index of the currently played song to start the Playing from there. This way, we can restore the RadioPlay or the MusicPlay after our MediaPlayback. The downsides of this workaround is that we can't resume the current song where we left it (no XNA player method for seeking), the song will start from the beginning. It may be an issue for those who listen to long DJ Sets or Mixes regularly, but better than nothing. Note that the Radio sometimes gives back OFF power state while it's actually ON, so I am also watching that the queue's ActiveSongIndex is equal to -1 or not. When playing a real song, it is always greater than -1.

The User Adds Songs from 2 or More Albums/Playlists to the Now Playing Collection

"All of the collections, playlists, and queues returned by methods and properties in the Microsoft.Xna.Framework.Media namespace are immutable. You cannot add or remove objects from those collections or playlists. To create a custom 'playlist' of songs, games must maintain their own list of songs to play, and play those songs one at a time by calling MediaPlayer.Play."

This is the reason the 5th scenario cannot be restored. We also can't add items to the Now Playing collection in the Music Hub. I think the best solution is to simply let the user resume the music manually. With this approach, the queue stays intact and can be resumed by the user. If anybody has a better solution, please send it to me and I will post it here.

In my code, I made some functions which can be used freely for anyone under the MS-PL license, they are in the XnaMusicUtil.cs.

Saving the current state is really easy compared to the Restore function. If the radio is on or the ActiveSong equals -1, the user listens to the Radio. In every other case, if the queue has items, then the user Listens to some sort of Music. Read and store, that's all. We can stop the Music at the end of the Save if we want by simply setting the isStopping parameter to True.

Notice that we have to Play the Songs in order to restore the Queue, but if the original state was Stopped or Paused, we Stop/Pause them right after Playing. This could produce a small audio glitch resulted by the quick Audio on-off. I'm not even sure the final devices have this "effect" or not.

Both the Playlists and the Albums are SongCollection classes. I'm using the following function to compare them with the saved queue. If the SongCollection has all the Songs of the queue, then it determines the index of the last played song and starts the play with it.

Good to Know

The XNA framework requires the FrameworkDispatcher.Update() function to call regularly for proper function.

During my tests, I figured out that calling this function just after the other XNA function calls is enough, but if you want to make sure your code won't collapse because of this, you have to implement the XNAAsyncDispatcher from here:

Comments and Discussions

Another thing to note is that if you change the MediaPlayer.Volume in your XNA game (for example, you allow the user to adjust the game's music volume with a slider control) you need to restore the volume before your application exits. If you don't restore it before exiting, the user's songs will be affected by the volume change (although it doesn't seem to affect the radio volume - ?). Since there doesn't seem to be a volume control for the Zune player software in WP7 (and I am not talking about the hardware button volume controls here), there is no obvious way for a user to fix this (without going back into the game and adjusting its music-volume slider-bar).