I worked out a testing function for Web Audio API
to play url blob:
// trigger takes a sound play function
function loadSound(url, trigger) {
let context = new (window.AudioContext || window.webkitAudioContext)();
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
trigger(()=>{
// play sound
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
source.start();
});
}, e=>{
console.log(e);
});
}
request.send();
}
loadSound(url, fc=>{
window.addEventListener('click', fc);
});
this is just for test, actually, I need a function to call to directly play the sound from url, if any current playing, quit it.
let ac;
function playSound(url) {
if(ac){ac.suspend()}
let context = new (window.AudioContext || window.webkitAudioContext)();
let request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
// play sound
let source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
// source.noteOn(0); // play the source now
ac = context;
source.start();
}, e=>{
console.log(e);
});
}
request.send();
}
window.addEventListener('click',()=>{
playSound(url);
});
I did not do much modification, however, the second version, triggers works fine, but always produces no sound.
I suspect it may be this
variable scope issue, I will be very glad if you can help me debug it.
since the blob url is too long, I put two versions in code pen.
Instead of calling supsend
on the stored AudioContext
, save a reference to the AudioBufferSourceNode
that is currently playing. Then check if the reference exits and call stop()
whenever you play a new sound.
const context = new AudioContext();
let bufferSource = null;
function playSound(url) {
if (bufferSource !== null) {
bufferSource.stop();
bufferSource = null;
}
let request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
context.decodeAudioData(request.response, (buffer) => {
bufferSource = context.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.connect(context.destination);
bufferSource.start();
bufferSource.addEventListener('ended', () => {
bufferSource = null;
});
}, (error) => {
console.log(error);
});
}
request.send();
}
window.addEventListener('click', () => {
playSound(url);
});