Jaa


Multi MediaElement - A Playlist Solution (next item no waiting)

We get quite a few questions in the forums about how to handle playlists when using the MediaElement. I’m defining playlist as a series of songs, videos, etc. that play sequentially one after another. Unfortunately the MediaElement doesn’t support native playlist capability. This is an interesting omission because Media Foundation has a rather elaborate playlist or as it is called sequencing system.

Luckily it is rather easy to wire up a simple playlist solution with the MediaElement. Unfortunately most naive solutions can cause long delays between playlist items. This is because we need to open and load every item in the playlist before we can start playing it. So if you are fine with the overhead of opening and loading the next playlist item the simple solution is recommended because you know… it is simple.

However, if you want each item to start immediately after the pervious item has finished then you need something a bit more complex. One solution is to use two MediaElements. One MediaElemet is always playing and the second is opening and loading the next track in the background ready to start playback as soon as it is needed. When one playlist item ends we can immediately start playback of the next. Then the one that was just playing starts to queue the next item. Sounds simple right?

The key to making any playlist solution work with the MediaElement is to handle the “MediaEnded” event. When we receive this event we know that the item is done playing. We can then check the playlist and start the next item playing. Luckily unlike with the Media Player SDK, the MediaElement guarantees that we will always get the “MediaEnded” event. Without this a playlist solution would be impossible.

If we are using two MediaElemets we look at the first two items in the playlist. We set the source of the first MediaElement (current) and the second MediaElement (next) to the first and second items in the playlist. We start playback of the first MediaElement and allow the second to load, open and then pause. When the current MediaElement finishes playing we swap it with the next MediaElement so next becomes current and current becomes next. We start playback of the current MediaElement and queue the next item in the list using the next MediaElemnt.

Still with me? Good!

This works great until you start skipping around in the list. Let’s say I have a playlist with four items, one, two, three and four. I start playback at the beginning of the playlist, item one. Naturally item two is queued and ready to play. Now what happens if the user skips directly from the currently playing item, item one, to the third item in the playlist, item three? We have item two queued and ready to go but we can’t use it because we skipped to item three. Those darn users always trying to muck about with a simple and elegant solution.

If we allow this common behavior we need to come up with some way to handle this scenario in our code. There are lots of different possible implementations. In the sample code included below I do some tricky (okay maybe hackey) stuff with the “Tag” properties of the MediaElements to keep track of what playlist item the MediaElements correspond to. In other words, if MediaElement two has playlist item two queued and ready to go and the user clicks on playlist item three we compare the currently selected playlist item, item three, with the index of the item that is actually queued in the MediaElement, item two. Since they are not the same we can’t just start playback of item two so we have to chuck item two and load item three and four into our two MediaElements.

Still with me? Yeah, I know it gets a bit complex. Take a look at the code. I think that will help get you back on track.

James

MultiMediaElementPlaylist.zip

Comments

  • Anonymous
    August 07, 2014
    Wouldn't it be easier and more efficient to always load the next song into the memory and use a InMemoryRandomAccessStream as the MediaElements source? It should take no time for the mediaelement to open and buffer a file from the memory.