I’ve already written articles demonstrating a couple of new HTML5 features and Bing Maps – notably, the <canvas> element and the geolocation API. In this post, I’ll have a look at one of the other new elements in the HTML5 specification, the <audio> tag.
Personally, I find webpages that play music in the background are right up there on the “annoying” list next to those that use the <blink> tag, or those riddled with popup banner adverts. However, there are some genuine use cases for audio in webpages:
- Discrete use of subtle sound effects can provide positive feedback for user interfaces. For example, consider touch keyboard inputs that emulate the “clicking” noise of a typewriter to confirm when a key has been pressed.
- Sound effects can also improve accessibility of a page, by providing audio cues for the elements of a user interface, in much the same way that a screenreader does.
I’m not an expert in UI design or in accessibility, so I’m not claiming that this article exhibits best practice in either of those areas, but at least I’d like to demonstrate what is technically possible using HTML5 <audio> and Bing Maps, by playing a simple sound effect when the mouse is placed over a polygon on the map.
Testing for Browser Audio Support
The HTML5 specification is still not fixed, and the level of support for HTML5 across different browsers is variable. At the time of writing, the most recent version of all major browsers support the <audio> tag itself, although the actual formats of audio file that can be played varies between browser. Rather frustratingly, there is no single file type supported across all browsers, as shown in the following table:
Format | IE9 | Firefox 3.6 /4 | Opera 10.6 | Chrome 10 | Safari 3 |
Ogg Vorbis | No | Yes | Yes | Yes | No |
MP3 | Yes | No | No | No | Yes |
Wav | Yes | Yes | Yes | No | Yes |
(information aggregated from http://html5doctor.com/native-audio-in-the-browser/ and http://thebrowsereview.com/html5/html5-audio-tag-and-format-support/)
Before using any of the new <audio> features, the first thing to do is therefore to check whether the user’s browser supports audio. This can be done in javascript by attempting to create a new audio element and calling the canPlayType function.
var supportsAudio = !!(document.createElement('audio').canPlayType);
This function will return a boolean result of true if the browser supports HTML5 audio, or false otherwise. If the browser does support audio, you can find out if a particular audio file format is supported by passing a parameter to canPlayType, representing the MIME type of an audio format. For example, to test whether the browser supports MP3 audio:
var supportsMP3 = (document.createElement('audio').canPlayType('audio/mpeg');
Note that, unlike the boolean response obtained when canPlayType is called with no parameters (which tests whether the browser implements audio at all), the response given when used to test whether a particular audio file type is supported is either “”, “maybe”, or “probably”.
Specifying a Source Audio File
Having determined the audio formats supported by the browser, you can then use a conditional statement to specify which source file should be used. For example:
var audio = document.createElement('audio'); // Create the source audio file element var source = document.createElement('source'); // Test if the browser supports MPEG audio if (audio.canPlayType('audio/mpeg') != "") { source.type = 'audio/mpeg'; source.src = 'soundfile.mp3'; } // Test if the browser supports OGG audio else if (audio.canPlayType('audio/ogg; codecs="vorbis"') != "") { source.type = 'audio/ogg'; source.src = 'soundfile.ogg'; } audio.appendChild(source);
If Music Be the Food of Love, Play On…. (Or stop, as appropriate)
The final step is to attach handlers to the map to listen for particular events, and then set these handlers to start or stop the audio as appropriate. For this example, I’m going to attach a handler to the mouseover event of a polygon, causing the audio file to play while the user hovers their cursor over the shape in question:
var Handler = Microsoft.Maps.Events.addHandler(polygon, 'mouseover', function(e) { audio.play(); });
And, when the user moves their mouse off the polygon, I want to stop the sound again. Note that the HTML5 audio standard doesn’t actually define a stop method, but rather a pause method to stop playback:
var Handler = Microsoft.Maps.Events.addHandler(polygon, 'mouseout', function(e) { audio.pause(); });
Putting It All Together
A full code listing demonstrating the audio functionality is shown following. This example has been tested and confirmed to work in Firefox 4, Internet Explorer 9 and Chrome
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> <title>Bing Maps HTML5 Audio</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script> <script type="text/javascript"> // Declare a shorthand alias for the Microsoft.Maps namespace var MM = Microsoft.Maps; function GetMap() { // Create a basic map var map = new MM.Map(document.getElementById("mapDiv"), { credentials: "YOUR BING MAPS KEY HERE", center: new Microsoft.Maps.Location(54, -2), mapTypeId: Microsoft.Maps.MapTypeId.birdseye, zoom: 5 }); // Create a polygon var polygon = new MM.Polygon([new MM.Location(50, -7),new MM.Location(52.5, 2),new MM.Location(59, -3),new MM.Location(57, -6),new MM.Location(50, -7)]); // Add the polygon to the map map.entities.push(polygon); // Try to create an audio element var audio = GetAudio('notify'); // If audio is supported if (audio) { // Play music when the mouse is over the polygon var Handler = Microsoft.Maps.Events.addHandler(polygon, 'mouseover', function(e) { audio.play(); }); // Stop audio when the mouse leaves the polygon var MouseOutHandler = Microsoft.Maps.Events.addHandler(polygon, 'mouseout', function(e) { audio.pause(); }); } } /* Tests for browser audio support, and specifies * the appropriate source file extension depending * on supported audio file types */ function GetAudio(filename) { // Try creating an <audio> tag var audio = document.createElement('audio'); // If the browser supports <audio> if (audio.canPlayType) { // Create the source audio file element var source = document.createElement('source'); // Test if the browser supports MPEG audio if (audio.canPlayType('audio/mpeg') != "") { source.type = 'audio/mpeg'; source.src = filename + '.mp3'; } // Test if the browser supports WAV audio else if (audio.canPlayType('audio/wav') != "") { source.type = 'audio/wav'; source.src = filename + '.wav'; } // Test if the browser supports OGG audio else if (audio.canPlayType('audio/ogg; codecs=vorbis') != "") { source.type = 'audio/ogg; codecs=vorbis'; source.src = filename + '.ogg'; } // Append the matching format file to the <audio> element audio.appendChild(source); return audio; } // If <audio> is not supported else { return null; } } </script> </head> <body onload="GetMap();"> <div id='mapDiv' style="position:relative; width:600px; height:800px;"></div> </body> </html>
If you can imagine audio in a screenshot, then it probably looks a bit like this:
And you an see a live demo by going to: http://a3uk.com/clients/bingmaps/v7/html5audio/html5audio.htm