Is it possible to get raw values of audio data using MediaRecorder()

Viewed 1672

I'm using MediaRecorder() with getUserMedia() to record audio data from the browser. It works, but recorded data is recorded in the Blob format. I want to get raw audio data (amplitudes), not the Blobs. Is it possible to do it?

My code looks like this:

  navigator.mediaDevices.getUserMedia({audio: true, video: false}).then(stream => {
    const recorder = new MediaRecorder(stream);
    recorder.ondataavailable = e => {
      console.log(e.data); // output: Blob { size: 8452, type: "audio/ogg; codecs=opus" }
    };
    recorder.start(1000); // send data every 1s
  }).catch(console.error);
3 Answers

MediaRecorder is useful to create files; if you want to do audio processing, Web Audio would be a better approach. See this HTML5Rocks tutorial which shows how to integrate getUserMedia with Web Audio using createMediaStreamSource from Web Audio.

No need for MediaRecorder. Use web audio to gain access to raw data values, e.g. like this:

navigator.mediaDevices.getUserMedia({audio: true})
.then(spectrum).catch(console.log);

function spectrum(stream) {
  const audioCtx = new AudioContext();
  const analyser = audioCtx.createAnalyser();
  audioCtx.createMediaStreamSource(stream).connect(analyser);

  const canvas = div.appendChild(document.createElement("canvas"));
  canvas.width = window.innerWidth - 20;
  canvas.height = window.innerHeight - 20;
  const ctx = canvas.getContext("2d");
  const data = new Uint8Array(canvas.width);
  ctx.strokeStyle = 'rgb(0, 125, 0)';

  setInterval(() => {
    ctx.fillStyle = "#a0a0a0";
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    analyser.getByteFrequencyData(data);
    ctx.lineWidth = 2;
    let x = 0;
    for (let d of data) {
      const y = canvas.height - (d / 128) * canvas.height / 4;
      const c = Math.floor((x*255)/canvas.width);
      ctx.fillStyle = `rgb(${c},0,${255-x})`;
      ctx.fillRect(x++, y, 2, canvas.height - y)
    }

    analyser.getByteTimeDomainData(data);
    ctx.lineWidth = 5;
    ctx.beginPath();
    x = 0;
    for (let d of data) {
      const y = canvas.height - (d / 128) * canvas.height / 2;
      x ? ctx.lineTo(x++, y) : ctx.moveTo(x++, y);
    }
    ctx.stroke();
  }, 1000 * canvas.width / audioCtx.sampleRate);
};

I used the following code to achieve an array of integers into console. As to what they mean, I assume they are amplitudes.

const mediaRecorder = new MediaRecorder(mediaStream);
mediaRecorder.ondataavailable = async (blob: BlobEvent) => console.log(await blob.data.arrayBuffer());
mediaRecorder.start(100);

If you were to want to draw them, then I found this example that I had forked on codepen: https://codepen.io/rhwilburn/pen/vYXggbN which pulses the circle once you click on it.

Related