Tuesday, May 19, 2009

How to play a sound in a Firefox extension

What if you are working on a Firefox extension that needs to play a sound when an event occurs? Do you know what libraries to use or what you should do to accomplish this simple task? I am going to answer these questions for you!

Let's assume that the sound that we are going to play is in our content folder inside the extension, how do we retrieve the file path dynamically, i.e, depending on where the extension was installed?

First of all you have to know that Mozilla has a service called nsIExtensionManager that provides you with functions to execute tasks related to the extension like for example getting the path to the extension installation folder, so how do we use it?

We need to first instantiate the extension manager interface this way:

var em = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager);

Then to get the installation folder of our extension we do this:

var installationLocation = em.getInstallLocation(EXTENSION_ID);

As you can see in this code we are using a constant called EXTENSION_ID, you need to set this constant in your code with the ID of your extension. The ID of your extension is the ID you defined in your install.rdf file.

OK, we now have the installation location of our extension, so we now have to get the full location of the sound file we want to use and for that we are going to use the getItemFile function.

installationLocation.getItemFile(EXTENSION_ID, "chrome/chromeFiles/content/sound.wav");

As you can see here, we are looking for the file based on the extension installation location and we are indicating where in the extension to look. We said before we have our file in the content folder of the extension, so we pass that path as a parameter.

Until now what we have is the file location inside the extension, but we still need to create a file object to play the sound, right? Well, to create a file we use the Mozilla interface nsILocalFile and we instantiate and set the path contained in the fileLocation object like this:

var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);

file.initWithPath(fileLocation.path);


We can double check and make sure that the file really exists:

if (!file.exists()) {
// If the file doesn't exists, then return null
return null;
}

Now, if the file exists we can then play it, but how? Mozilla provides with an interface to play sounds, it is called nsISound and we instantiate it like this:

var player = Components.classes["@mozilla.org/sound;1"].createInstance(Components.interfaces.nsISound);

When playing a sound, the player needs to receive the location of the file as a nsIURI object, so we still need to convert our file into a nsIURI object and we do this by using the nsIIOService interface.

var ios = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
var sound = ios.newFileURI(file);

Now we just need to play it!

player.play(sound);


...and that is it! Very simple!!