I'm making a Firefox extension and I'm failing to play a sound that's located in add-on's data
directory.
The first thing I've tried was playing it in a content script this way:
var soundFile = self.options.soundFile;
(new Audio(soundFile)).play();
where self.options.soundFile
is an option that refers to a resource file in data
directory. But I meet security restrictions:
Security Error: Content at http://example.com may not load or link to resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/stackoverflow-reiew-helper/data/complete.oga.
Then I've found a way to play sounds in main.js
script (here: How to play audio in an extension?):
var data = require('sdk/self').data;
exports.main = function() {
var {Cc, Ci} = require("chrome");
var sound = Cc["@mozilla.org/sound;1"].createInstance(Ci.nsISound);
sound.play(data.url('complete.oga'));
};
This one fails with the following exception:
NS_ERROR_XPC_BAD_CONVERT_JS: Could not convert JavaScript argument arg 0 [nsISound.play]
undefined 8
Traceback (most recent call last):
File "resource://gre/modules/NetUtil.jsm", line 140, in null
aCallback(pipe.inputStream, aStatusCode, aRequest);
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/net/url.js", line 49, in null
resolve(data);
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 123, in then
else result.then(resolved, rejected)
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 55, in effort
try { return f(options) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 143, in resolve
while (pending.length) result.then.apply(result, pending.shift())
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 37, in then
return { then: function then(resolve) { resolve(value) } }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 117, in resolved
function resolved(value) { deferred.resolve(resolve(value)) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/core/promise.js", line 55, in effort
try { return f(options) }
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/addon/runner.js", line 90, in onLocalizationReady
run(options);
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/addon-sdk/lib/sdk/addon/runner.js", line 134, in run
quit: exit
File "resource://jid0-a02no8rrtu2pbize7g7sszzo0z8-at-jetpack/stackoverflow-reiew-helper/lib/main.js", line 8, in exports.main
sound.play(data.url('complete.oga'));
If I replace sound.play(...)
with sound.beep
, I get a nice default system sound. So, there should be something wrong with passing resource path to the function.
If it matters in any way, I'm using online Add-on Builder.
Please suggest a solution of playing a solution of playing extension audio resources.
nsISound.play()
takes an nsIURI
instance, not a string. You have to create it via nsIIOService.newURI()
first:
var uri = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(data.url('complete.oga'), null, null);
sound.play(uri);
I would recommend against this approach however, nsISound.play()
API is pretty much deprecated and IMHO not capable of playing ogg files anyway.
Audio
constructor requires access to a proper HTML document. Easiest way to get one in an SDK-based extension is using page-worker
module:
require("page-worker").Page({
contentScript: "new Audio('complete.oga').play()",
contentURL: data.url("blank.html")
});
Both your sound file and blank.html
(an empty HTML file) need to be located in the data/
directory of the extension - note how the audio file is loaded via a relative URL. Right now I don't see a way to avoid having an empty HTML file in the extension, HTML files outside the extension don't have access to extension files and cannot play them.