How To: Create a Playlist for HTML5 Audio
Update: New article! - How To: Create a Dynamic Playlist for HTML5 Audio (Advanced)
Just a few years ago, if you wanted to add audio or video to your webpage, it wasn't as simple and easy as it is now using HTML5 and a modern browser. Lucky for us those days are long gone. You may already be familiar with the HTML5 ‘<audio>’ tag and how to use it to add an audio file to your webpage. For those who are not, here is a basic example:
<audio controls="controls">
<source src="/song.mp3" type="audio/mp3" />
<source src="/song.ogg" type="audio/ogg" />
Your browser does not support the audio tag.
</audio>
And here is the above code in action:
That's great if you only have or want one song to play on your webpage, but what if you have a list of songs that you want to put on your page? You could use the ‘<audio>’ tag several times; one for each song. That takes up a lot of space on your page and causes a lot of overhead and will slow down your page because every song has to be loaded each time the page is displayed. This is frustrating for the end user browsing your site. So how do you solve this problem? By creating a playlist for the songs you want on your page.
Check out the HTML5 Audio Playlist example here.
The Code
Let's jump right in and get started with the code. We need to start with some html first. I am only going to cover what we need for the audio and playlist from the example.
<div id="cwrap">
<div id="nowPlay">
<h3 id="npAction">Paused:</h3>
<div id="npTitle"></div>
</div>
<div id="audiowrap">
<div id="audio0">
<audio id="audio1" controls="controls" width="300">
Your browser does not support the HTML5 Audio Tag.
</audio>
</div>
<div id="extraControls">
<button id="btnPrev" class="ctrlbtn">|<< Prev Track</button> <button id="btnNext" class="ctrlbtn">Next Track >>|</button>
</div>
</div>
<div id="plwrap">
<div class="plHead">
<div class="plHeadNum">Track</div>
<div class="plHeadTitle">Title</div>
<div class="plHeadLength">Length</div>
</div>
<ul id="plUL">
<li>
<div class="plItem">
<div class="plNum">1</div>
<div class="plTitle">Happy Birthday Variation: In the style of Beethoven</div>
<div class="plLength">0:55</div>
</div>
</li>
<li>
<div class="plItem">
<div class="plNum">2</div>
<div class="plTitle">Wedding March Variation 1</div>
<div class="plLength">0:37</div>
</div>
</li>
<li>
<div class="plItem">
<div class="plNum">3</div>
<div class="plTitle">Happy Birthday Variation: In the style of Tango</div>
<div class="plLength">1:05</div>
</div>
</li>
<li>
<div class="plItem">
<div class="plNum">4</div>
<div class="plTitle">Wedding March Variation 2</div>
<div class="plLength">0:40</div>
</div>
</li>
<li>
<div class="plItem">
<div class="plNum">5</div>
<div class="plTitle">Random Classical</div>
<div class="plLength">0:59</div>
</div>
</li>
</ul>
</div>
</div>
Here is a brief explanation of the html code above:
- Line 1: Starts the div wrapper for our audio controls and the playlist.
- Line 2: Starts the Now Playing section.
- Line 3: Used to display the action of the audio player (i.e. Paused, Now Playing).
- Line 4: Used to display the title of the audio file that has been loaded.
- Lines 6 - 11: The audio control.
- Lines 12 - 14: Our playlist controls (previous and next buttons).
- Lines 16 - 59: Defines the playlist. We use an unordered list item for each title of the playlist.
By itself, the html code doesn't do anything. It won't even play a single audio file because we did not include any ‘<source>’ tags to tell it which file(s) to load. We did that on purpose as you will see later.
To make this work we need to add some Javascript to the page. The example is written using jQuery. To start, we add the following lines of code just before the closing ‘</body>’ tag.
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
jQuery(function($) {
var supportsAudio = !!document.createElement('audio').canPlayType;
- Line 1: Add the jQuery library. (see the related articles for more information.)
- Line 2: Start a script block.
- Line 3: Start a jQuery script.
- Line 4: Declares a variable named ‘supportsAudio’ and sets a boolean value to it.
With “!!document.createElement('audio').canPlayType;” we are checking whether or not the users browser supports the html5 ‘<audio>’ tag by creating a new audio element in the DOM (Document Object Model) and calling the ‘canPlayType’ method without any arguments. Because of this we have to use two exclamation points (!!) to get the correct boolean value. If we call it without any exclamation points we would get the following:
document.createElement('audio').canPlayType: function canPlayType() { [native code] }
With only one exclamation point we do get a boolean value. However, it is the opposite of what we are asking:
!document.createElement('audio').canPlayType: false <-(can not play audio file)
With two exclamation points we get the correct boolean value:
!!document.createElement('audio').canPlayType: true <-(can play audio file)
Okay, moving on with the next few lines of code:
if(supportsAudio) {
var index = 0,
playing = false;
mediaPath = '/how_to/assets/media/audio/',
extension = '',
tracks = [
{"track":1,"name":"Happy Birthday Variation: In the style of Beethoven","length":"00:55","file":"01_Happy_Birthday_Variation_In_The"},
{"track":2,"name":"Wedding March Variation 1","length":"00:37","file":"02_Wedding_March_1"},
{"track":3,"name":"Happy Birthday Variation: In the style of Tango","length":"01:05","file":"03_Happy_Birthday_Variation_In_The"},
{"track":4,"name":"Wedding March Variation 2","length":"00:40","file":"04_Wedding_March_2"},
{"track":5,"name":"Random Classical","length":"00:59","file":"05_AFI_com"}
],
trackCount = tracks.length,
npAction = $('#npAction'),
npTitle = $('#npTitle'),
- Line 5: Use the variable ‘supportsAudio’ in an if block.
- Lines 6 - 10 and 17 - 19: Declare new variables.
- Line 8: ‘mediaPath’ is the path to your audio files.
- Lines 10 - 16: Declares a variable named ‘tracks’ and creates an array of JSON Objects.
- Line 17: Get the number of elements in the ‘tracks’ array and assign the value to ‘trackCount’.
- Lines 18 - 19: Creates a jQuery object of the DOM element and assigns it to the variable. This is similar to calling ‘document.getElementById("<id>")’ where “<id>” equals the html element id.
Moving on with more code.
audio = $('#audio1').bind('play', function() {
playing = true;
npAction.text('Now Playing:');
}).bind('pause', function() {
playing = false;
npAction.text('Paused:');
}).bind('ended', function() {
npAction.text('Paused:');
if((index + 1) < trackCount) {
index++;
loadTrack(index);
audio.play();
} else {
audio.pause();
index = 0;
loadTrack(index);
}
}).get(0),
This section of code is the most important part of the playlist example so I will explain it in more detail.
- Line 20:
audio = $('#audio1') - Set the variable ‘audio’ to the html element with the id of ‘audio1’. See Code Sample 2, line 8 above. HTML snippet: ‘<audio id="audio1" controls="controls" width="300">’
- Line 20 (continued):
.bind('play', function() { - This is a jQuery way of assigning an event listener. In this case we want to do something when the media event ‘play’ is sent from the audio control.
- Line 21:
playing = true; - Set the variable ‘playing’ to true because we are in the ‘play’ media event listener.
- Line 22:
npAction.text('Now Playing:'); - This is the jQuery way to set the text of the html element with the id of “npAction” (set on line 18 of Code Sample 4 above) to ‘Now Playing:’ because we are in the ‘play’ media event listener.
- Lines 23 - 25:
- The ‘})’, at the beginning of line 23, closes the ‘play’ event listener. We then chain the ‘paused’ media event listener just like we did the ‘play’ above, setting the variable and text appropriately.
- Lines 26 - 36:
- This is the magic code that makes a playlist possible. This creates the ‘ended’ media event listener. This event is triggered when the playing audio file reaches the end. This allows us to respond by loading the next track in the playlist or stop if that was the last file in the list. If the value of the variable ‘index’ plus 1 is less than the value of the variable ‘trackCount’, we increment the value of ‘index’, call the function ‘loadTrack’ passing ‘index’ as a parameter and call the audio control method ‘play()’ else we call the ‘pause()’ method, set ‘index’ to zero, and call the ‘loadTrack’ method with ‘index’ as a parameter.
- Line 37:
}).get(0), - Close the ‘ended’ event listener and chain the jQuery method ‘get(0)’ to allow us access to the DOM node under the jQuery object. Without this we would be listening to the events from the jQuery object instead of the actual audio control.
Just a few more lines of code to go.
btnPrev = $('#btnPrev').click(function() {
if((index - 1) > -1) {
index--;
loadTrack(index);
if(playing) {
audio.play();
}
} else {
audio.pause();
index = 0;
loadTrack(index);
}
}),
btnNext = $('#btnNext').click(function() {
if((index + 1) < trackCount) {
index++;
loadTrack(index);
if(playing) {
audio.play();
}
} else {
audio.pause();
index = 0;
loadTrack(index);
}
}),
- Lines 38 - 63: Create the ‘click’ event listeners for the html buttons, Prev and Next Track (see Code Sample 2, lines 12 - 14 above). These event listners are similar to the media event listners abaove.
Almost there.
li = $('#plUL li').click(function() {
var id = parseInt($(this).index());
if(id !== index) {
playTrack(id);
}
}),
loadTrack = function(id) {
$('.plSel').removeClass('plSel');
$('#plUL li:eq(' + id + ')').addClass('plSel');
npTitle.text(tracks[id].name);
index = id;
audio.src = mediaPath + tracks[id].file + extension;
},
playTrack = function(id) {
loadTrack(id);
audio.play();
};
if(audio.canPlayType('audio/ogg')) {
extension = '.ogg';
}
if(audio.canPlayType('audio/mpeg')) {
extension = '.mp3';
}
loadTrack(index);
}
});
});
</script>
</body>
</html>
- Lines 64 - 69: Create the ‘click’ event listener for any of the list items in the playlist.
- Line 65: Declare a variable named ‘id’ and set the value to the index number of the list item clicked. The jQuery selector ‘$(this)’ is used to find which list item has been clicked and ‘.index()’ returns the zero-based index (number series starting with zero) of that item.
- Lines 66 - 68: Check if the value of the variable ‘id’ does not equal the value of the variable ‘index’ then call the function ‘playTrack’ passing the variable ‘id’.
- Lines 70 - 76: Create the ‘loadTrack’ function. This functions has one parameter: ‘id’.
- Line 71: Remove the css class named ‘plSel’ from any element that has been asigned the class. The jQuery selector ‘$('.plSel')’ will select all elements that has the class name of ‘plSel’.
- Line 72: Add the css class name ‘plSel’ to the list item identified by the parameter ‘id’. We do this with the special jQuery selector directive ‘:eq()’, but we need to pass the value of the parameter variable ‘id’ with it. To do this we concatenate the code by using the plus sign so the jQuery selector looks like this: ‘$('#plUL li:eq(' + id + ')')’.
That's it.
Check out the HTML5 Audio Playlist example here.