3

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!

Dewan159
  • 2,984
  • 7
  • 39
  • 43
  • It seems you're using jQuery.ajax(). so is your problem with jquery? please add the details of that call to the question. – eis Apr 03 '21 at 07:35
  • also, have you considered using native javascript like explained [here](https://stackoverflow.com/a/56006818/365237) – eis Apr 03 '21 at 07:38
  • and as a third comment, why does it matter? ogg is just a container so it's the same ogg file regardless. – eis Apr 03 '21 at 07:41
  • @eis I think the ajax code is irrelevant, be it jQuery or something else, it's the FormData object that gets sent, jQuery wouldn't change the mime type of the file ... or so I belive. – Dewan159 Apr 03 '21 at 08:10
  • @eis It matters because the audio is sent to a seconds service that requires the mime to be audio/ogg not video/ogg. I though a bout converting the file on server, but that would be worse solution to a probably fixable issue on the front end. – Dewan159 Apr 03 '21 at 08:13
  • 1
    is the problem just mime type sent or is there issue with contents as well? how do you see it's in video/ogg and not audio/ogg? – eis Apr 03 '21 at 08:26
  • In fact I have not tested that. If you are saying that the content is what matters and I can change the mime to whatever works that would be great, but can I?! – Dewan159 Apr 03 '21 at 08:32
  • not sure, but please test. :) – eis Apr 03 '21 at 08:34

3 Answers3

2

I ended up using kbumsik/opus-media-recorder, solved the issue for me. A drop-in replacement for MediaRecorder.

Dewan159
  • 2,984
  • 7
  • 39
  • 43
2

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.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
1

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 });
chrisguttandin
  • 7,025
  • 15
  • 21
  • Great, I will give it a try. But is there anyway to get audio/ogg out of chrome?! The 3rd party service I use requires OGG – Dewan159 Apr 03 '21 at 10:55
  • Not that I know of. But it should be possible to write some code which unwraps the webm container to extract the opus audio. – chrisguttandin Apr 03 '21 at 14:14
  • 1
    Still sends it out as "video/webm"! This is just weird! – Dewan159 Apr 04 '21 at 19:29
  • 1
    Sad but true: The MIME types MediaRecorder generates come from a small list. Chrome only does webm. Safari only does mp4. It's a real electropolitical mess. – O. Jones Apr 08 '21 at 11:06