Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

remove createMediaElementSource

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?

like image 478
Sebastian Olsen Avatar asked Feb 18 '16 21:02

Sebastian Olsen


2 Answers

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.

like image 159
ActiveObject Avatar answered Nov 11 '22 23:11

ActiveObject


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);
like image 21
guest271314 Avatar answered Nov 11 '22 21:11

guest271314