Internet Radio in C# (Part 2, Playlists)
In the previous tutorial I taught you how to use Bass to stream audio from the internet. While our radio player is amazing enough, there is, however, a missing factor in it pertaining to playlists. In this tutorial you will learn:
- How to load a playlist from an internet radio station
- How to create your own playlist
This tutorial builds off of the previous one and so you will need the following requirements.
- Visual C# Express (sorry, Visual C# Express 2005 is no longer available)
- Bass.NET 2.3 (scroll down until you find the .NET 2.0 link)
- Un4seen Bass api (top download link for Windows)
Most internet radio stations like to play in playlist format. Well, if you look around, all internet radio stations use some form of playlists. The nice part about conforming here is that we can reuse the playlist again when we put together our polished C# Media Player.
While there are a few streaming formats for playlist (ASX, M3U, XSPF) the most common playlist format is PLS. PLS as a playlist format is a fairly expressive format. The specification is listed below (via Wikipedia):
Header
- [playlist] : This tag indicates that it is a Playlist File
- NumberOfEntries : This variable indicates the number of tracks
Track Entry
Assuming track entry #X
- FileX : Variable defining location of stream.
- TitleX : Defines track title.
- LengthX : Length in seconds of track. Value of -1 indicates indefinite.
Footer
- Version : Playlist version. Currently only a value of 2 is valid.
[playlist]
NumberOfEntries=3
File1=http://streamexample.com:80
Title1=My Favorite Online Radio
Length1=-1
File2=http://example.com/song.mp3
Title2=Remote MP3
Length2=286
File3=/home/myaccount/album.flac
Title3=Local album
Length3=3487
Version=2
Knowing this format, we can read it in with a simple PLS parser to load in any PLS supported radio station. Specifically, we can support Shoutcast stations in our little media player. First, I will create a new class called PLSHelper. Using the StreamReader class, we can read in the playlist and determine where all the songs are located as well as their associated titles. First, declare the variables that are included in a playlist.
Next, create the readonly property for each of the above variables. After that, we need to actually load the playlist. The following code snippet will accomplish this using the StreamReader class.
Essentially, we split the entire playlist string by the given name. Since there is only one of the given name in the entire playlist it is safe to assume that there will be two splits. So on NumberOfEntries=, the first split string will contain "[version]\n" and the second split will be the rest of the playlist string. If there is more than one of the given name it still won't matter since we're just interested in the second index of the array. Next, we just need to find the next index of the non integer in the second string. This is done in the IndexOfNonNumber method.
Pretty simple. We just check each character until we find a character that is not a number; followed by returning that index. We use that index as the length. After that we will simply substring the playlist split to get the variable. This is very similar to how we will obtain all the files. Next, we just need to make two calls back in the LoadPlaylist method.
Lastly, the CreateProperties method. This method will need to run a loop to parse out each variable of a playlist entry.
First, we create the array to store the playlist entry variable. Next, we will split on the given name. Since the first split is always going to be "[version]\nNumberOfEntries=3\n" we start at i + 1. Then, we need to remove the start of the split to exclude the number and the equals sign. So, the split on File will result in:
After that, we just need to substring until we find the break line sequence denoted by "\n". That will get the entire variable entry that we need at each instance in the playlist. Lastly, we just need to make the call to the method on each entry variable.1=http....
2=http...
3=http....
That's it! Now we can use this little helper to load any standard playlist. We just need to make a modification to our Player class to load in a playlist and use this class when it receives a location.
There, I've added the PLSHelper as a field level variable and I created it in the constructor of the Player. In this method, I am checking what is being loaded (either a playlist, local song, or online song). Also, I've added a readonly property to the PLSHelper in the Player class to allow access from our user interface code. Now that we have a playlist, we should add something to our user interface to make it useable. I've added a listbox. Your form may look similar.
Next, we need to change our load code. Right now, our load code is calling the LoadSong method; instead, we need to call the Load method we just created. After that, we need to update our listbox to display what's in the playlist.
Lastly, we need to update what's being played by the selected item in the listbox. Use the SelectedIndexChanged event on the listbox for this. Then add the following code snippet.
And there you go. The last thing we need to do is update our playlist to include single songs that we load instead of a whole playlist. Modify your Load code in the Player class to the following snippet.
Not much left. Whenever a song is loaded directly, we need to clear the playlist, followed by adding the song to the play list. This is done through two helper methods in the PLSHelper. First, the clear playlist:
public void ClearPlaylist()
{
locations = new string[0];
titles = new string[0];
lengths = new string[0];
version = 2;
pls = string.Empty;
count = 0;
}
And that's it! Call the Add method from your Player class and you should be good to go. Hit F5, load up a playlist and see your creation shine. In this tutorial you learned how to use internet radio playlist standards to load in any .pls file. As well, you were able to create your own playlist in the making of. As an extra bonus, add save functionality to your list; shouldn't be too difficult just remember to follow the playlist standard.
UPDATE: The source code also includes file loading with default program settings and it will run in a single process.
[Source code]
Comments