jsHtml5AudioRecorder – Record live audio stream in html5 with echo cancellation

Today, I will tell you about an html5 object i’ve developped, jsHtml5AudioRecorder.
This html5 plugin helps you record live audio, directly from your browser (Chrome, firefox and Safari), without echo.

Before that, let’s learn how html5 audio works.
This is a good article that will help you learn the basics http://www.html5rocks.com/en/tutorials/webaudio/intro/

Ok, let’s go!

First, we must check that navigator.getUserMedia is supported by our browser.

if (!navigator.getUserMedia) {
    navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
} 

try {
    this.audioContext    = new AudioContext();
    console.log('Audio context set up.');
    console.log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
            
} catch (e) {
    alert('No web audio support in this browser!');
}

window.onload = this.onLoad();

Now, we can initiate the navigator.getUserMedia api, with audio config to true, and a stream function.

navigator.getUserMedia({audio:true}, this.startStream.bind(this), function(e) {
    alert('No audio stream!');
    console.log(e);
});

This is the heart of our plugin, how we create the stream from the input to the output

//Create virtual input from empty amplification factor object
var virtualInput        = this.audioContext.createGain();
       
//Assign stream source to html5 audio context object
var microphone         = this.audioContext.createMediaStreamSource(stream);
        
//Connect media source output to virtualInput input
//So, virtualInput now equals microphone input
microphone.connect(virtualInput);

//Set audio quality and assign it to virtualInput
var analyserNode        = this.audioContext.createAnalyser();
analyserNode.fftSize    = this.fftSize;
virtualInput.connect( analyserNode );

//Set the stream to RecorderJs from Matt Diamond
this.Recorder           = new Recorder( virtualInput );

//Set volume to zero
var amplificationFactor = this.audioContext.createGain();
amplificationFactor.gain.value     = 0.0;
        
//We set volume to zero to output, so we cancel echo
amplificationFactor.connect( this.audioContext.destination );

Notice in this function, the “new Recorder” method.
Effectively, we use the wonderful RecoderJs from Matt Diamond here, to record the input stream.
https://github.com/mattdiamond/Recorderjs.

Ok, we have setted our stream to html5 audio object, we can now define our “start record” and “stop record” methods.

Start recording method

//Delete audio element if already exists to avoid element duplication and cache
var audioElement = document.getElementById(this.audioTagId);
if (audioElement) {
    audioElement.remove();
}

this.Recorder && this.Recorder.record();        
console.log('Recording audio...');

Stop recording method, we also choose different output methods

this.Recorder && this.Recorder.stop();

this.Recorder && this.Recorder.exportWAV(function(blob) {
    console.log(blob);
            
    if (method === 'save') {
        this.save(blob, false);
    } else if (method === 'download') {
        this.downmload(blob, false);
    } else if (method === 'stream') {
        this.stream(blob);
    } else if (method === 'saveAndStream') {
        this.save(blob, true);
    } else if (method === 'downloadAndStream') {
        this.download(blob, true);
    } else {
        this.save(blob, false);
    }
            
}.bind(this));

this.Recorder.clear();
console.log('Stop Recording audio!');

Right, now we can specify our “download”, “save” and “stream” methods.

Save method

var datas       = 'path='+this.mediaPath+'&format=.wav';                  

var client = new XMLHttpRequest();
client.onreadystatechange = function() 
{
    if (client.readyState === 4 && client.status === 200) 
    {
        console.log(client.response);
        if (stream) {
            this.stream(blob);
        }
    }
}.bind(this);
client.open("post", this.phpFile+'?'+datas, true);
client.setRequestHeader("X-Requested-With", "XMLHttpRequest");
client.setRequestHeader("cache-Control", "no-store, no-cache, must-revalidate");
client.setRequestHeader("cache-Control", "post-check=0, pre-check=0");
client.setRequestHeader("cache-Control", "max-age=0");
client.setRequestHeader("Pragma", "no-cache");            
client.setRequestHeader("X-File-Name", encodeURIComponent('1'));
client.setRequestHeader("Content-Type", "application/octet-stream");
client.send(blob);

Download method

var url             = window.URL.createObjectURL(blob);
//Create a link
var hf              = document.createElement('a');

var temporaryId     = new Date().toISOString();

//Define link attributes
hf.href             = url;
hf.id               = temporaryId;
hf.download         = temporaryId + '.wav';
hf.innerHTML        = hf.download;
hf.style.display    = 'none';
hf.style.visibility = 'hidden';
//Append the link inside html code
document.body.appendChild(hf);

//Simulate click on link to download file, and instantly delete link
document.getElementById(hf.id).click();
document.getElementById(hf.id).remove();

if (stream) {
    this.stream(blob);
}

And finally we define the stream method

var url             = window.URL.createObjectURL(blob);
        
//Create audio tag
var audio           = document.createElement('audio');
        
//Define audio tag attributes
audio.src               = url;
audio.id                = this.audioTagId;
audio.style.display     = 'visible';
audio.style.visibility  = 'block'; 
document.body.appendChild(audio);
        
audio.setAttribute('autoplay', false);         
audio.setAttribute('controls', true);
audio.pause();

Thank you for reading this article.
 
To download the full code, click here: https://github.com/edouardkombo/jsHtml5AudioRecorder
 
To see a live demo, it’s here: https://edouardkombo.github.io/jsHtml5AudioRecorder/demo
 
To download directly from bower:

bower install js-html5-audio-recorder
Advertisements
jsHtml5AudioRecorder – Record live audio stream in html5 with echo cancellation

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s