Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add predefined length to audio recorded from MediaRecorder in Chrome?

I am in the process of replacing RecordRTC with the built in MediaRecorder for recording audio in Chrome. The recorded audio is then played in the program with audio api. I am having trouble getting the audio.duration property to work. It says

If the video (audio) is streamed and has no predefined length, "Inf" (Infinity) is returned.

With RecordRTC, I had to use ffmpeg_asm.js to convert the audio from wav to ogg. My guess is somewhere in the process RecordRTC sets the predefined audio length. Is there any way to set the predefined length using MediaRecorder?

like image 739
Tom Chen Avatar asked Jul 18 '16 17:07

Tom Chen


People also ask

Can you record audio from website?

One of the best ways to record audio on a website is to use a Chrome Extension like Audio Capture. This tool can be easily installed on the browser, ready to use whenever you need to record audio on any tab. It also allows you to mute all other tabs to avoid accidently recording them as well.


2 Answers

This is a chrome bug.

FF does expose the duration of the recorded media, and if you do set the currentTimeof the recorded media to more than its actual duration, then the property is available in chrome...

var recorder,   chunks = [],   ctx = new AudioContext(),   aud = document.getElementById('aud');  function exportAudio() {   var blob = new Blob(chunks);   aud.src = URL.createObjectURL(new Blob(chunks));    aud.onloadedmetadata = function() {     // it should already be available here     log.textContent = ' duration: ' + aud.duration;     // handle chrome's bug     if (aud.duration === Infinity) {       // set it to bigger than the actual duration       aud.currentTime = 1e101;       aud.ontimeupdate = function() {         this.ontimeupdate = () => {           return;         }         log.textContent += ' after workaround: ' + aud.duration;         aud.currentTime = 0;       }     }   } }  function getData() {   var request = new XMLHttpRequest();   request.open('GET', 'https://upload.wikimedia.org/wikipedia/commons/4/4b/011229beowulf_grendel.ogg', true);   request.responseType = 'arraybuffer';   request.onload = decodeAudio;   request.send(); }   function decodeAudio(evt) {   var audioData = this.response;   ctx.decodeAudioData(audioData, startRecording); }  function startRecording(buffer) {    var source = ctx.createBufferSource();   source.buffer = buffer;   var dest = ctx.createMediaStreamDestination();   source.connect(dest);    recorder = new MediaRecorder(dest.stream);   recorder.ondataavailable = saveChunks;   recorder.onstop = exportAudio;   source.start(0);   recorder.start();   log.innerHTML = 'recording...'   // record only 5 seconds   setTimeout(function() {     recorder.stop();   }, 5000); }  function saveChunks(evt) {   if (evt.data.size > 0) {     chunks.push(evt.data);   }  }  // we need user-activation document.getElementById('button').onclick = function(evt){   getData();   this.remove(); }
<button id="button">start</button> <audio id="aud" controls></audio><span id="log"></span>

So the advice here would be to star the bug report so that chromium's team takes some time to fix it, even if this workaround can do the trick...

like image 101
Kaiido Avatar answered Sep 22 '22 13:09

Kaiido


Thanks to @Kaiido for identifying bug and offering the working fix.

I prepared an npm package called get-blob-duration that you can install to get a nice Promise-wrapped function to do the dirty work.

Usage is as follows:

// Returns Promise<Number> getBlobDuration(blob).then(function(duration) {   console.log(duration + ' seconds'); }); 

Or ECMAScript 6:

// yada yada async const duration = await getBlobDuration(blob) console.log(duration + ' seconds') 
like image 40
Ezekiel Victor Avatar answered Sep 19 '22 13:09

Ezekiel Victor