Search code examples
javascriptweb-audio-api

audio issue related to slicer


I am trying to execute a function related to analyzer upon different elements in slicer selection.

After Page load, when I make first selection there is no issue but on subsequent selection, I am getting error in console.

I can't figure out why.

This is what I have tried and the console prints out the error from 2nd selection onwards.

// Audio DB
const audioDB = [
  { index: 0, src: 'https://s.cdpn.io/1202/Star_Wars_original_opening_crawl_1977.mp3' },
  { index: 1, src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/128337/ongoing-thing-crop.ogg' }
];

const indexString = ['Please select a track', ...audioDB.map(a => a.index.toString())];

let audioCtx;
let analyzer;
let audioSourceNode;

const audio = document.querySelector('audio');
const select = document.querySelector('.slicer');

select.addEventListener('change', function () {
  if (audioCtx && audioCtx.state !== 'closed') {
    audioCtx.close().then(function () {
      createNewContextAndPlay();
    });
  } else {
    createNewContextAndPlay();
  }

  function createNewContextAndPlay() {
    audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    play();
  }

  function play() {
    const index = select.selectedIndex;
    if (audioSourceNode) {
      audioSourceNode.disconnect();
    }

    if (index !== 0) {
      const managedIndex = index - 1;
      const val = audioDB.find(a => a.index === managedIndex)?.src;

      if (val) {
        audio.src = val;
        audio.play();

        if (audioSourceNode) {
          audioSourceNode.disconnect();
        }

        if (audioCtx && audioCtx.state !== 'closed') {
          audioSourceNode = audioCtx.createMediaElementSource(audio);
          analyzer = audioCtx.createAnalyser();

          if (audioSourceNode && analyzer) {
            audioSourceNode.connect(analyzer);
            analyzer.connect(audioCtx.destination);

            console.log(1);
          }
        }
      }
    }
  }
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Document</title>
  </head>
  <body>
    <audio id="audio" crossorigin="anonymous"></audio>
    <div class="slcr">
      <label for="Tracks" style="font-size: 16px; font-family: Oswald, sans-serif; color: red;"> Tracks :- <select class="slicer" id="slicer" style="font-family: Oswald, sans-serif; background-color: aqua;">
          <option>Please select a track</option>
          <option>Track1</option>
          <option>Track2</option>          
        </select>
      </label>
    </div>
  </body>  
</html>

I am getting this error enter image description here on enter image description here


Solution

  • As the error says createMediaElementSource() can only be called once with the same <audio/> element on the same AudioContext.

    Re-using the existing MediaElementAudioSourceNode should fix the problem. Just make sure to only call createMediaElementSource() if audioSourceNode is still undefined.

    if (audioSourceNode === undefined) {
        audioSourceNode = audioCtx.createMediaElementSource(audio);
    }