Cross-Browser Event-Driven Audio: A Lightweight Solution
The Problem:
As a general rule, you don’t see event-based audio in the browser, or at least not outside of some embedded flash object or popup ad. Gone are the days when you’d hear that crisp IE “click” sound every time you clicked a link. No more do we jump for the volume controls when we mistakenly navigate to a page with a MIDI rendition of “Eye of the Tiger” set to auto play in the background. Most sites don’t even set embedded videos to start automatically. You can see why the question of how best to implement it doesn’t come up very often.
A recent client project centered around gamifying the college entrance process called for event-driven audio in some of the interactive activities. This is one of the few contexts where I would argue audio events have a place. Music and sound effects play a big role in conveying information about the game state to the player. Still, building games in the browser with native code is still a touchy process, and the more browsers you try to support the touchier it gets. In this case, we wanted it all. Everything from iPad to IE8 had to provide the same interactive experience.
Normally the obvious option would be to throw one of the myriad Flash-based audio players on the page and be done with it, but the iPad can’t stomach Flash. Besides, we like to live on the bleeding edge here and I didn’t want to submit to the <embed> tag unless it was the only option.
The HTML5 <audio> element is still messy at best. Browser audio APIs are improving and moving towards a unified spec but the chart of compatible formats still reads like a pick-three of audio file extensions, with no two browsers picking the same three.
What’s Out There:
In doing research for this project I came across a lot of tutorials, snippets and plugins that claimed to allow you to use the <audio> tag with impunity. Almost all of these were built using multiple file formats for each audio file and a Flash fallback for older browsers. Most were also meant to be used for embedding songs, podcasts and the like. Of the ones I tested out, the simplest implementations didn’t provide a way to control the player programmatically and the more complex packages took a lot of configuration and had a lot of moving pieces.
The Flash fallback route was really the only option for supporting such a wide range of browsers but I wanted a middle-of-the-road solution that would bark on command but wouldn’t attempt to manage my entire MP3 collection for me. Enter audio.js.
The audio.js package consists of four files:
- audio.min.js
- audiojs.swf
- player-graphics.gif
- index.css
It’s lightweight to say the least and was the quickest to get up and running. It works by creating a JavaScript wrapper around the <audio> element that handles all browser discrepancies and allows you to use code like this:
<audio src="/mp3/juicy.mp3" preload="auto" />
For browsers without <audio> support of some kind, it defaults to the Flash player as expected, but the UI is all built with HTML and CSS and updated via JavaScript, so the user will see the same player no matter what their browser supports. Player appearance was admittedly not the biggest issue here since it would be hidden most of the time but it was one less thing to worry about.
What about browser support? The audio.js site claims
- Mobile Safari (iOS 3+)
- Android (2.2+, w/Flash)
- Safari (4+)
- Chrome (7+)
- Firefox (3+, w/ Flash)
- Opera (10+, w/ Flash)
- IE (6, 7, 8, w/ Flash)
An impressive list given the API fragmentation. Flash is listed as caveat more often than not but with JavaScript hooks to control the player instance I didn’t have to worry about what type of player was being loaded in order to play a file.
It was love on $(document).ready(). But that doesn’t mean we didn’t have our occasional fights. It took me a little while to get my head around the available methods because there is no detailed documentation available (though the annotated source is clean and concise). When testing in IE, I was plagued with an “Object doesn’t support this property or method” error for a while that had to do with how I was procedurally loading the audio files. A few hurdles, but nothing to put me off for good.
There may be better audio solutions out there but this is one of the simplest and most functional I’ve seen. It plays the audio by hook or by crook with minimal markup and access to player controls in JavaScript when needed. audio.js is definitely going in the resources folder for now.
Thanks for you post about cross browser audio player.
I am running into the same issue with the flash fallback for audio.js where you were receiving the “Object doesn’t support this property or method” error message in IE.
Any chance you could share your working solution?
Hey Peter,
Unfortunately I was using Audio.js as part of a more complex audio event system so my working solution would probably be in excess to your requirement and difficult to reduce.
I spent a lot of time with the Audio.js annotated source code, which is excellent by the way. This section in particular mentions an issue IE has with having a .play() method exposed, though Audio.js should be abstracting those kinds of differences away if you’re not dynamically modifying its objects with JS.
Beyond that, test Audio.js with the desired files in a page by itself first. I ran into some strange side effects when trying to drop Audio.js into the middle of a Javascript-heavy application.
Hopefully that helps. If you can tell me your browser version I may be able to narrow things down a bit more.
Thanks for the reply – I literally tried every solution I could think of to no avail so unfortunately I have reverted back to mediaelement.js for the work around.