Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play audio from firefox extension's data directory

I'm making a Firefox extension and I'm failing to play a sound that's located in add-on's data directory.

  1. 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.
    
  2. 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.

like image 772
Alexey Avatar asked May 08 '13 20:05

Alexey


1 Answers

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.

like image 167
Wladimir Palant Avatar answered Nov 15 '22 17:11

Wladimir Palant