Using the html5 audio element from javascript

By | May 23, 2013

Sometime back I was making a browser based game in the html5 canvas tag which had some audio too. The html5 audio tag is an easy option to add sound/music to any webpage. It can play variety of formats like wav, ogg and mp3. However format support itself varies across browsers.

The audio element can be directly added to html in the form of a tag

<audio src="sound.mp3" controls></audio>

The src attribute holds the path/url to the sound file to play. This by default would bring up a ui element on the webpage which will have buttons to play/pause and control the volume. But such an audio player is not always needed or necessary, like in a game, where we need to dynamically or rather programmatically load sound files in the background and play them on a certain event.

The Audio element has a javascript class that can be used to do this in a purely html independant way. Lets see how.

Audio Object

Audio objects can be created in javascript like this.

var aud = new Audio();
aud.src = 'sound.ogg';

//You could also do
var aud = new Audio('sound.ogg');

//Now lets play the music
aud.play();

That way we do not need to create any html elements on the webpage and can modify things easily at runtime.

Stop, Pause etc

Other basic functions needed are stopping, pausing and unpausing the audio. The audio element has a direct function to pause, but no functions for stopping or unpausing.

//Now lets play the music
aud.play();

aud.pause();

aud.play();

That is the way to pause and play. What about stop and an unpause. Unpause means to start playing only it was previously paused. Calling play however just starts the playing from whatever current position the audio element is at.

Stop

To stop the audio, pause the audio and reset its time.

aud.pause();
aud.currentTime = 0.0;

Check out another post on html5 audio hacks to see how to implement functions for stop, unpause etc.

Events

When loading audio inside javascript there is often a need to get a notification when a large sound file has finished loading (downloading). The audio tag comes with a handy event called loadeddata for that.

var loaded = false;
var aud = new Audio();

aud.addEventListener('loadeddata', function() 
{
	loaded = true;
	aud.play();
}, false);

aud.src = 'background.ogg';

So now the play will trigger after the loading is complete. Note that the src is set after adding the event handler. This is important, since the loading starts rightaway on specifying the src and event handlers must be available as early as possible.

If the audio fails to load for some reason, then there is an event to notify that too. Its the error event and is used like this

var loaded = false;
var aud = new Audio();

aud.addEventListener('loadeddata', function() 
{
	loaded = true;
	aud.play();
}, false);

aud.addEventListener('error' , function() 
{
	alert('error loading audio');
}, false);

aud.src = 'background.ogg';

Change the src to something invalid to trigger the error event. It will notify the application that the audio did not load.

Muting the audio

The audio tag allows various properties to be set on it like volume and mute. Muting an audio is a good thing to do if the window goes out of focus. Simply setting the muted property does the job

<html>
<body>
<script>

var loaded = false;
var aud = new Audio();

aud.addEventListener('loadeddata', function() 
{
	loaded = true;
	aud.play();
}, false);

aud.addEventListener('error' , function() 
{
	alert('error loading audio');
}, false);

aud.src = 'background.ogg';

</script>

<input type="button" onclick="aud.muted = true" value="Mute" />
<input type="button" onclick="aud.muted = false" value="Unmute" />
</body>
</html>

There is a special behaviour of the muted property to note. Lets say if you need to load a file and play it in the background, but it should be muted because the user wants so. Then you might do something like this

var loaded = false;
var aud = new Audio();
aud.src = 'background.ogg';
aud.muted = true;
aud.play();

This will play the music inspite of setting muted to true. Why ? Because muted must be set only after the src has loaded completely. Before that, it has no effect or may be is over written.

So the correct way to set muted at load time is inside the loadeddata event like this

var loaded = false;
var aud = new Audio();

aud.addEventListener('loadeddata', function() 
{
	aud.muted = true;
}, false);

aud.src = 'background.ogg';
aud.play();

Now the sound would be muted properly.

Detecting Audio support

So far we tried to play ogg files. All browsers do not support all formats. For example firefox does not support mp3 due to patent issues and safari would not play the ogg format. Google Chrome supports most of the formats. For the latest format support status check the wikipedia article on audio element. Older browsers do not have Audio element at all.

IF audio code is written in javascript just like that, then non-supporting browsers would just throw an error and the whole application would hang. Instead if the application can continue without audio support it should do that gracefully.

So the solution is to detect support for audio element and formats.

function check_audio() 
{
  var elem = document.createElement('audio'), bool = false;
  
  try 
  {
    if ( bool = !!elem.canPlayType ) 
    {
      bool = new Boolean(bool);
      bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
      bool.mp3 = elem.canPlayType('audio/mpeg;').replace(/^no$/,'');
      bool.wav = elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/,'');
      bool.m4a = (elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;')).replace(/^no$/,'');
    }
  } 
  catch(e) 
  { 
  }
  
  return bool;
}

var b = check_audio();

if(!b)
{
  document.write('No Audio support');
}
else
{
  var formats = ['ogg', 'mp3', 'wav', 'm4a'];
  for(var i = 0; i < formats.length; i++)
  {
    document.write(formats[i] + ' support status ' + b[formats[i]] + '<br />');
  }
}

The check_audio function checks both for audio support, and support for each of the 4 major formats. If the return value is false, then audio element is not supported by the browser. If true, then can check the member variables ogg, mp3, wav, and m4a for support of each of those formats. If the value is empty string or blank then no support. If its 'probably' or 'maybe' then support is present. Try this jsfiddle to check your browser.

Resources

http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#the-audio-element
About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

6 Comments

Using the html5 audio element from javascript
  1. Richard Dickinson

    Hi nice article….thanks

    I have to say the first point is wrong though afaik… HTML5 audio controls only display if the ‘controls’ attribute is present in the audio tag. In your example you have left this out! Your example needs javascript / html/css controls added (unless you want autoplay where you simply add attribute ‘autoplay’ to the audio tag). Best wishes :-)

  2. Richard Dickinson

    Hi thanks for this post- I especially wanted a js file format check but the result makes me want to laugh or cry!

    Eg:
    ogg support status probably
    mp3 support status maybe
    wav support status probably
    m4a support status maybe

    What’s with probably/maybe? Yes or no would be good! :-) :-(

    1. Silver Moon

      The canPlayType() method can return one of the following values :

      “probably” – the browser most likely supports this audio/video type and will be able to play it.
      “maybe” – the browser might support this audio/video type.
      “” – (empty string) the browser does not support this audio/video type

      empty string clearly indicates that the media type cannot be played. so it can be used to detect support for a given format or type.

Leave a Reply

Your email address will not be published. Required fields are marked *