Audio recording in JavaScript on Chrome, always sends video/ogg to the server

Viewed 749

I have been trying to record audio in OGG format on Chrome and send it back to the server, but it always gets their in video/ogg format. Here is what I have:

Capturing audio:

let chunks = [];
let recording = null;

let mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();

mediaRecorder.onstop = function() {
    recording = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
}

mediaRecorder.ondataavailable = function(e){
    chunks.push(e.data);
}

Sending it to the server:

let data = new FormData();
data.append('audio', recording);

jQuery.ajax(...);

The blob gets to the backend, but always in video/ogg!

3 Answers

You need to remove the VideoTrack from your MediaStream:

const input = document.querySelector("video");
const stop_btn = document.querySelector("button");
input.onplaying = (evt) => {
  input.onplaying = null;
  console.clear();
  const stream = input.captureStream ? input.captureStream() : input.mozCaptureStream();
  // get all video tracks (usually a single one)
  stream.getVideoTracks().forEach( (track) => {
    track.stop(); // stop that track, so the browser doesn't feed it for nothing
    stream.removeTrack( track ); // remove it from the MediaStream
  } );
  const data = [];
  const recorder = new MediaRecorder( stream, { mimeType: "audio/webm" } );
  recorder.ondataavailable = (evt) => data.push( evt.data );
  recorder.onstop = (evt) => exportFile( new Blob( data ) );
  
  stop_btn.onclick = (evt) => recorder.stop();
  stop_btn.disabled = false;
  recorder.start();  
};
console.log( "play the video to start recording" );


function exportFile( blob ) {
  stop_btn.remove();
  input.src = URL.createObjectURL( blob );
  console.log( "video element now playing recoded file" );
}
video { max-height: 150px; }
<video src="https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm" controls crossorigin></video>
<button disabled>stop recording</button>

And since StackOverflow's null origined iframes don't allow for safe download links, here is a fiddle with a download link.

You need to set the mimeType of the MediaRecorder. Otherwise the browser will pick whatever format it likes best to encode the media.

let mediaRecorder = new MediaRecorder(stream, { mimeType: 'my/mimetype' });

To be sure that the browser can actually encode the format you want you could use isTypeSupported().

console.log(MediaRecorder.isTypeSupported('my/mimetype'));

Chrome for example doesn't support "audio/ogg; codecs=opus" but supports "audio/webm; codecs=opus". Firefox supports both. Safari none of them.

Once you've configured the MediaRecorder you can use its mimeType when creating the blob.

recording = new Blob(chunks, { 'type' : mediaRecorder.mimeType });
Related