I've google all over for this issue, but couldn't find anything.
I am in a situation where I need to remove a source = createMediaElementSource
so that I can create it again. I am using an audio analyzer which has to load each time you load a specified track using ajax. As soon as you go to another page, and then back, the analyzer is gone. Therefore I need to re-initialize it somehow.
My code:
var analyserElement = document.getElementById('analyzer');
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x,
bar_width, bar_height;
function analyzerSetElements() {
var analyserElement = document.getElementById('analyzer');
}
function analyzerInitialize() {
if (context == undefined) {
context = new AudioContext();
}
analyser = context.createAnalyser();
canvas = analyserElement;
ctx = canvas.getContext('2d');
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frameLooper();
}
function analyzerStop(){
context = undefined;
analyser = undefined;
source = undefined;
}
function frameLooper() {
canvas.width = canwidth;
canvas.height = canheight;
ctx.imageSmoothingEnabled = false;
fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array);
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
ctx.fillStyle = "white"; // Color of the bars
function valBetween(v, min, max) {
return (Math.min(max, Math.max(min, v)));
}
var beatc = fbc_array[2] / 4;
var beatround = Math.round(beatc);
//if (beatround < 10) {
// ctx.globalAlpha = '0.1125';
//}
//else {
// ctx.globalAlpha = '0.' + beatround;
//}
bars = canbars;
for (var i = 0; i < bars; i += canmultiplier) {
bar_x = i * canspace;
bar_width = 2;
bar_height = -3 - (fbc_array[i] / 2);
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
window.requestAnimationFrame(frameLooper);
console.log('Looped')
}
So when I run analyzerInitialize()
after running analyzerStop()
I still get this error:
audio.js:179 Uncaught DOMException: Failed to execute 'createMediaElementSource' on 'AudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode
How can I make it so running analyzerInitialize()
will never fail?
I've faced the same issue. Unfortunately I didn't find how to get already created MediaElementSourceNode
from an audio element. Nevertheless it's possible to workaround this issue by using WeakMap
to remember MediaElementSourceNode
:
var MEDIA_ELEMENT_NODES = new WeakMap();
function analyzerInitialize() {
if (context == undefined) {
context = new AudioContext();
}
analyser = context.createAnalyser();
canvas = analyserElement;
ctx = canvas.getContext('2d');
if (MEDIA_ELEMENT_NODES.has(audio)) {
source = MEDIA_ELEMENT_NODES.get(audio);
} else {
source = context.createMediaElementSource(audio);
MEDIA_ELEMENT_NODES.set(audio, source);
}
source.connect(analyser);
analyser.connect(context.destination);
frameLooper();
}
By using WeakMap
I avoid memory issues.
You can set the context
and source
to the globally defined variable instead of redefining the variables
context = context || new AudioContext();
source = source || context.createMediaElementSource(audio);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With