6
var audioPlayer = new Audio("http://URLTOMYSOUND/ping.mp3");
audioPlayer.play();

I get this error upon loading the audio:

Content Security Policy: The page's settings blocked the loading of a resource at...

How do I get around this? I don't care where the sound is, I just want to play it. It could be local, but my impression was that local file access would be a no-no as well.

1 Answer 1

8

It is not possible(at the moment) to play a sound from file if you are running into the Content Security Policy(CSP) issues as of Greasemonkey 2.3. If you can modify the HTTP headers of the site you want to run on, it is possible. See Using Content Security Policy and CSP policy directives.

Using GM_xmlhttpRequest which "allows these requests to cross the same origin policy boundaries", does not work because of a bug in the current GM 2.3. See issue #2045. The problem stems from not being able to copy the ArrayBuffer into the sandbox land to get the proper permissions to decode, etc.

The snippet below should work in future GM versions.

// ==UserScript==
// @name        Testing Web Audio: Load from file
// @namespace   http://ericeastwood.com/
// @include     http://example.com/
// @version     1
// @grant       GM_xmlhttpRequest
// ==/UserScript==
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
// Note: this is not an actual reference to a real mp3
var url = 'http://example.com/some.mp3';

var soundLoadedPromise = new Promise(function(resolve, reject) {
    // This will get around the CORS issue
    //      http://wiki.greasespot.net/GM_xmlhttpRequest
    var req = GM_xmlhttpRequest({
        method: "GET",
        url: url,
        responseType: 'arraybuffer',
        onload: function(response) {
            try {
                context.decodeAudioData(response.response, function(buffer) { 
                    resolve(buffer)
                }, function(e) {
                    reject(e);
                }); 
            }
            catch(e) {
                reject(e);
            }
        }
    });
});

soundLoadedPromise.then(function(buffer) {
    playSound(buffer);
}, function(e) {
    console.log(e);
});

function playSound(buffer) {
    // creates a sound source
    var source = context.createBufferSource();
    // tell the source which sound to play
    source.buffer = buffer;
    // connect the source to the context's destination (the speakers)
    source.connect(context.destination);
    // play the source now
    // note: on older systems, may have to use deprecated noteOn(time);
    source.start(0);
}

For now, if you only need some sound, I would just procedurally generate it with an oscillator. The demo below uses AudioContext.createOscillator.

Demo: jsFiddle

// ==UserScript==
// @name        Test Web Audio: Oscillator - Web Audio
// @namespace   http://ericeastwood.com/
// @include     http://example.com/
// @version     1
// @grant       none
// ==/UserScript==
window.AudioContext = window.AudioContext || window.webkitAudioContext;

context = new AudioContext();

var o = context.createOscillator();
o.type = 'sine';
o.frequency.value = 261.63;
o.connect(context.destination);

// Start the sound
o.start(0);
// Play the sound for a second before stopping it
setTimeout(function() {
    o.stop(0);
}, 1000);
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.