audio
and video
elements, which allow audio and video to be played natively in the browser. Before this innovation, people wanting to offer video or audio on their websites had to rely on third party software like Flash.
Fortunately for us, audio
and video
have solved this problem, at least partially. I say partially for two main reasons. The first is that not all the browsers that developers are asked to support have implemented these elements, like some old mobile browsers and old versions of Internet Explorer. The second reason is that browsers haven’t reached agreement on the formats to implement, so today we have different browsers supporting different formats. This happened due to “political” reasons rather than technical ones, but whatever the cause, we have to face these two issues.
With this in mind, if you want to use either of these elements in a website, not only do you have to provide different formats for each audio or video you want to play, but you also need to offer a fallback for browsers not supporting audio
and video
. To achieve this goal, you can either use the native methods and then install a library that offers you a Flash-based player with its own features and APIs, or you can use an all-in-one library that exposes the same APIs and provides a native solution or a Flash-based solution depending on the capabilities of the browser.
In this article, we’ll look into the second option, by discussing one such all-in-one library called SoundManager 2.
What is SoundManager 2?
As described on the SoundManager 2 website, this libraryprovides simple, reliable cross-platform audio under a single JavaScript API.SoundManager 2 is compatible with an incredible number of browsers, and I bet with all of those you have to support. To give you an idea, here is the list of the tested browsers and platforms:
- Firefox (all versions), Windows/Mac
- Safari 1.3+ (Mac) / All Windows versions
- Mobile Webkit: iOS 4.0 devices, iPad 3.2 (original iPad iOS release) and newer
- Android (2.3+, confirmed on 2.3.3.)
- Google Chrome (all versions/OSes)
- Internet Explorer 5.0+, Windows
- Opera 9.10 (slightly buggy, 9.5+ ideal), Windows/Mac
- Netscape 8.0+, Windows/Mac
- Firefox 1.5+, Linux (Flash 9 beta).
Creating a Simple Audio Player with SoundManager 2
In this section, we’ll develop a simple yet functional audio player using HTML, CSS, and JavaScript with the support of SoundManager 2. To keep things as simple as possible, our player will allow a user to play a given audio file that we’ll hard code into the source. You can easily modify the source to allow users to choose what audio they want to play, perhaps using a select menu. Without further ado, let’s start writing the markup that powers our player.The Markup
Our player gives a user the ability to:- play and stop an audio file
- pause and resume an audio file
- turn up and down the volume
- move the current position of the audio file 30 seconds back and forth
- know the duration of the file audio and the time elapsed since its start
- know the current volume.
<div class="player">
<div class="player__audio-info">
<div>
Played
<span class="player__time-elapsed">-</span> of
<span class="player__time-total">-</span>
<button class="player__previous button button--small">Move back</button>
<button class="player__next button button--small">Move forth</button>
</div>
<div>
Volume: <span class="player__volume-info">100</span>
<button class="player__volume-down button button--small">Volume down</button>
<button class="player__volume-up button button--small">Volume up</button>
</div>
</div>
<button class="player__play button button--large">Play</button>
<button class="player__stop button button--large">Stop</button>
</div>
As you can see, I’ve used the BEM notation to name the classes used to style the elements of the markup. Some of you may argue that for such a simple example it’s overkill. While this is surely true, I’m a strong believer that good habits start by using a technology or a methodology with simple examples and then building upon them. My opinion is that starting with a complex project is not ideal for someone who has just started learning. This explains why I’ve used it in this project.
In addition to the BEM notation, you may have observed that I’ve employed the button
element to mark up the buttons. This may seem pretty obvious, but it isn’t. Many developers, in this situation, would have used a
elements or span
s; but a
elements should lead the user to somewhere, while a button
is the element to use when an element should do something. And our player needs to do something.
Now that we have the markup in place, let’s style it.
Adding a Bit of Style
I’ll keep the styles for this project pretty simple. The player will have a gray background, and a black border to highlight its boundaries. I’ll also “reset” the default style of thebutton
s so that they won’t look like typical buttons but will show the associated icons instead. Lastly, to switch from the “play” button to the “pause” button, I’ll create an is-playing
class that clearly marks the state of the audio file by changing the icon displayed.
The complete styles for our player are shown below:
.player
{
display: inline-block;
width: 300px;
padding: 5px;
background-color: #E3E3E3;
border: 1px solid #000000;
}
.player span
{
font-weight: bold;
}
.button
{
text-indent: 200%;
white-space: nowrap;
overflow: hidden;
border: none;
padding: 0;
background: rgba(255,255,255,0);
cursor: pointer;
vertical-align: bottom;
}
.button--small
{
width: 19px;
height: 19px;
}
.button--large
{
width: 48px;
height: 48px;
}
.player__audio-info
{
padding-bottom: 5px;
border-bottom: 1px dotted #000000;
}
.player__audio-info div + div
{
margin-top: 10px;
}
.player__volume-info
{
display: inline-block;
width: 1.5em;
}
.player__play
{
background-image: url("http://i60.tinypic.com/14mbep2.png");
}
.player__play.is-playing
{
background-image: url("http://i57.tinypic.com/idyhd2.png");
}
.player__stop
{
background-image: url("http://i61.tinypic.com/35mehdz.png");
}
.player__previous
{
background-image: url("http://i60.tinypic.com/sdihc5.png");
}
.player__next
{
background-image: url("http://i57.tinypic.com/2s1nm77.png");
}
.player__volume-down
{
background-image: url("http://i60.tinypic.com/331nom0.png");
}
.player__volume-up
{
background-image: url("http://i60.tinypic.com/ekkc1t.png");
}
Developing the Behavior
We’ve finally arrived at the core of our project, the business logic. As you’ll see, it isn’t very complex, but in order to have more maintainable code, we’ll create a support function calledformatMilliseconds
, and an object called player
. As the name implies, the function is used to convert a given amount of milliseconds into a string. More specifically, the string will be formatted as “H:MM:SS:mmm” as we’ll use it to show the total duration of the audio file and the time elapsed. The player
object will be used to store the elements of the player so that we don’t have to retrieve them every time. This allows us to improve the performance of our project. Finally, we’ll use an audio
variable to store the instance of the object that represents our audio file, created using SoundManager 2.
The function and the variables we’ve just described are shown below:
function formatMilliseconds(milliseconds) {
var hours = Math.floor(milliseconds / 3600000);
milliseconds = milliseconds % 3600000;
var minutes = Math.floor(milliseconds / 60000);
milliseconds = milliseconds % 60000;
var seconds = Math.floor(milliseconds / 1000);
milliseconds = Math.floor(milliseconds % 1000);
return (hours > 0 ? hours : '0') + ':' +
(minutes < 10 ? '0' : '') + minutes + ':' +
(seconds < 10 ? '0' : '') + seconds + ':' +
(milliseconds < 100 ? '0' : '') + (milliseconds < 10 ? '0' : '') + milliseconds;
}
var player = {
btnPlay: document.querySelector('.player__play'),
btnStop: document.querySelector('.player__stop'),
btnPrevious: document.querySelector('.player__previous'),
btnNext: document.querySelector('.player__next'),
btnVolumeDown: document.querySelector('.player__volume-down'),
btnVolumeUp: document.querySelector('.player__volume-up'),
timeElapsed: document.querySelector('.player__time-elapsed'),
timeTotal: document.querySelector('.player__time-total'),
volume: document.querySelector('.player__volume-info')
};
var audio = null;
At this point, we have to create a new object that represents our audio file, which means we have to assign a value to our audio
variable. We’ll do that by using the createSound()
method provided by the library. It allows us to define several properties, but the most important are id
, which assigns an identifier to the audio file, and url
, where you can set the URL to the audio file.
The creation of this object is performed inside an anonymous function that is executed when the ready
event of the library is fired, which means the library has performed all its actions and is ready to be used. We can specify what to do when the ready
event is fired, and other settings, by passing an object literal to the setup()
method.
This is also where you should point to the Flash-based player of SoundManager 2, to use as a fallback. It’s set in the code below:
soundManager.setup({
useFastPolling: true,
useHighPerformance: true,
onready: function() {
audio = soundManager.createSound({
id: 'audio',
url: 'http://freshly-ground.com/data/audio/mpc/20090119%20-%20Untitled%20Groove.mp3',
whileloading: function() {
player.timeTotal.textContent = formatMilliseconds(audio.durationEstimate);
},
whileplaying: function() {
player.timeElapsed.textContent = formatMilliseconds(audio.position);
},
onload: function() {
player.timeTotal.textContent = formatMilliseconds(audio.duration);
},
onfinish: function() {
var event;
try {
// Internet Explorer does not like this statement
event = new Event('click');
} catch (ex) {
event = document.createEvent('MouseEvent');
event.initEvent('click', true, false);
}
player.btnStop.dispatchEvent(event);
}
});
}
});
Once we have instantiated the object that represents the audio file, we have to add an event listener to each of the buttons of our player. Here is where our player
object comes into play. Using it, we can refer to the buttons and the other elements of the player without performing a new selection every time. This is also where the SoundManager 2 library shows how easy it is to use.For example, let’s say that you want to play the audio: what method do you think the library exposes? play()
, of course! And what if we want to stop the audio? For that we have stop()
. Now, what if we want to know if the audio file is paused or not? The library provides a Boolean property called paused
. For the total duration, we have a duration
property instead. Very easy, isn’t it?
To change the volume and to move the current position of the audio we have two methods: setVolume()
and setPosition()
. Each of them accepts a single number that updates the value you want to change. For example, if you want to set the volume to 50 (the scale ranges from 0 to 100), you can write:
audio.setVolume(50);
If you want to move the position to 10 seconds from the start you can write:
audio.setPosition(10000);
The value provided is 10000 because the method accepts milliseconds.
The remaining part of code that implements the features we have described is presented below:
player.btnPlay.addEventListener('click', function() {
if (audio === null) {
return;
}
if (audio.playState === 0 || audio.paused === true) {
audio.play();
this.classList.add('is-playing');
} else {
audio.pause();
this.classList.remove('is-playing');
}
});
player.btnStop.addEventListener('click', function() {
if (audio === null) {
return;
}
audio.stop();
document.querySelector('.player__time-elapsed').textContent = formatMilliseconds(0);
player.btnPlay.classList.remove('is-playing');
});
player.btnVolumeDown.addEventListener('click', function() {
if (audio === null) {
return;
}
var volume = audio.volume - 10 < 0 ? 0 : audio.volume - 10;
audio.setVolume(volume);
player.volume.textContent = volume;
});
player.btnVolumeUp.addEventListener('click', function() {
if (audio === null) {
return;
}
var volume = audio.volume + 10 > 100 ? 100 : audio.volume + 10;
audio.setVolume(volume);
player.volume.textContent = volume;
});
player.btnPrevious.addEventListener('click', function() {
if (audio === null) {
return;
}
var position = audio.position - 30000 < 0 ? 0 : audio.position - 30000;
audio.setPosition(position);
player.timeElapsed.textContent = formatMilliseconds(audio.position);
});
player.btnNext.addEventListener('click', function() {
if (audio === null) {
return;
}
var position = audio.position + 30000 > audio.duration ? audio.duration : audio.position + 30000;
if (position === audio.duration) {
var event;
try {
// Internet Explorer does not like this statement
event = new Event('click');
} catch (ex) {
event = document.createEvent('MouseEvent');
event.initEvent('click', true, false);
}
player.btnStop.dispatchEvent(event);
} else {
audio.setPosition(position);
player.timeElapsed.textContent = formatMilliseconds(audio.position);
}
});
The Result
We’ve completed our task, but before we can see the player in action, we have to include the SoundManager 2 library. You can do that by downloading the library and all its files from the SoundManager 2 website, or alternatively from a CDN. Remember that, in order to have the Flash-based player as a fallback, you have to include the SWF file that comes with the SoundManager 2 library. Once you have done that, you are ready to see the player live. The result of our project is shown below in the following JSFiddle:Conclusion
In this tutorial, I’ve described SoundManager 2 – a library that allows you to use a unique set of APIs to deal with browsers that support theaudio
element and its API and those that don’t. As you have seen, SoundManager 2 supports an incredible number of browsers (including Internet Explorer 5!), so you can reliably use it in your projects.
We’ve put some of SoundManager 2’s methods into action by creating a simple player that can perform basic tasks like playing and pausing an audio file, modifying the volume, and moving the audio back and forth. If you want to learn more about SoundManager 2, I suggest you read its extensive documentation. I hope you liked the library and the demo, and that you’ll share your opinions with us.
Frequently Asked Questions (FAQs) about Creating an Audio Player with SoundManager
How can I customize the appearance of the audio player using SoundManager?
SoundManager allows you to customize the appearance of your audio player using CSS. You can modify the player’s size, color, and layout to match your website’s design. You can also add custom buttons and controls. To do this, you need to edit the CSS file associated with the SoundManager player. This file is usually named ‘soundmanager2.css’. You can change the properties of the player and its elements in this file. Remember to save your changes and refresh your webpage to see the effects.
Can I use SoundManager to play multiple audio files simultaneously?
Yes, SoundManager allows you to play multiple audio files simultaneously. You can create multiple SoundManager instances and assign a different audio file to each instance. Each instance operates independently, so you can control the playback of each audio file separately. This feature is useful for creating complex audio experiences, such as playing background music while also playing sound effects or voiceovers.
How can I control the volume of the audio player using SoundManager?
SoundManager provides a setVolume() function that you can use to control the volume of the audio player. This function takes a value between 0 and 100, where 0 is mute and 100 is the maximum volume. You can call this function on a SoundManager instance to set the volume for that instance. For example, if you have a SoundManager instance named ‘mySound’, you can set its volume to 50% like this: mySound.setVolume(50).
Can I use SoundManager to play audio files from external sources?
Yes, SoundManager can play audio files from external sources. You can specify the URL of the audio file when creating a SoundManager instance. The audio file will be streamed from the specified URL. Please note that the server hosting the audio file must allow cross-origin requests for this to work.
How can I loop an audio file using SoundManager?
SoundManager provides a loop() function that you can use to loop an audio file. You can call this function on a SoundManager instance to make the associated audio file play in a loop. For example, if you have a SoundManager instance named ‘mySound’, you can make its audio file loop like this: mySound.loop().
Can I use SoundManager on mobile devices?
Yes, SoundManager is compatible with most modern mobile devices. It uses HTML5 audio on devices that support it, and falls back to Flash on devices that don’t. However, please note that some mobile devices have restrictions on audio playback, such as not allowing audio to play without user interaction.
How can I add a progress bar to the audio player using SoundManager?
You can add a progress bar to the audio player by using the whileplaying() function of SoundManager. This function is called repeatedly during playback, and you can use it to update the position of the progress bar. You will need to create a progress bar element in your HTML and update its width in the whileplaying() function.
Can I use SoundManager to play audio files in a specific order?
Yes, you can use SoundManager to play audio files in a specific order. You can create a playlist of SoundManager instances and play them in sequence. You can use the onfinish() function of each instance to start the next instance when the current one finishes playing.
How can I preload audio files using SoundManager?
SoundManager provides a load() function that you can use to preload audio files. You can call this function on a SoundManager instance to load the associated audio file into memory. This can help to reduce the delay before the audio starts playing, especially for large audio files or slow network connections.
Can I use SoundManager to play audio files in the background?
Yes, you can use SoundManager to play audio files in the background. You can create a SoundManager instance and start playing an audio file, and the audio will continue to play even if the user navigates away from the page. However, please note that some browsers and devices may pause or stop background audio to save battery or bandwidth.
I'm a (full-stack) web and app developer with more than 5 years' experience programming for the web using HTML, CSS, Sass, JavaScript, and PHP. I'm an expert of JavaScript and HTML5 APIs but my interests include web security, accessibility, performance, and SEO. I'm also a regular writer for several networks, speaker, and author of the books jQuery in Action, third edition and Instant jQuery Selectors.