Les navigateurs fournissent de plus en plus d’API ce qui permet de faire des applications avec toujours plus de fonctionnalités. Dans cette article nous allons voir comment enregistrer le son du microphone.

La première chose est de demander le consentement de l’utilisateur pour utiliser le microphone :

navigator.getUserMedia = navigator.getUserMedia ||     
   navigator.webkitGetUserMedia ||     
   navigator.mozGetUserMedia ||     
   navigator.msGetUserMedia;    
navigator.getUserMedia(     
{     
   audio: true     
},     
function (e) {     
   // success     
},     
function (e) {     
   // error     
   console.error(e);     
});

Ces lignes permettent d’afficher cette popup :

popup

Une fois accepté, on peut créer le code permettant le lire le flux audio :

navigator.getUserMedia({ audio: true },     
  function (e) {     
   // creates the audio context  
   window.AudioContext = window.AudioContext || window.webkitAudioContext;     
   context = new AudioContext();     
   
   // creates an audio node from the microphone incoming stream     
   mediaStream = context.createMediaStreamSource(e);    
   // https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createScriptProcessor     
   var bufferSize = 2048;     
   var numberOfInputChannels = 2;     
   var numberOfOutputChannels = 2;     
   if (context.createScriptProcessor) {     
   recorder = context.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels);     
   } else {     
   recorder = context.createJavaScriptNode(bufferSize, numberOfInputChannels, numberOfOutputChannels);     
   }    
   recorder.onaudioprocess = function (e) {     
   console.log("on audio progress");     
   }    
   // we connect the recorder with the input stream     
   mediaStream.connect(recorder);     
   recorder.connect(context.destination);     
  }

Dans l’évènement onaudioprogress on peut simplement stocker le contenu lu dans un tableau

var leftchannel = [];     
var rightchannel = [];     
var recordingLength = 0;     
    
recorder.onaudioprocess = function (e) {     
   leftchannel.push(new Float32Array(e.inputBuffer.getChannelData(0)));     
   rightchannel.push(new Float32Array(e.inputBuffer.getChannelData(1)));     
   recordingLength += bufferSize;     
}

Une fois l’enregistrement terminé (par exemple via un clique sur un bouton), on peut créer un fichier audio au format WAV. Ce format est très simple d’où son choix. Il se compose d’un header suivi des données.

// stop recording     
recorder.disconnect(context.destination);     
mediaStream.disconnect(recorder);    
  
// we flat the left and right channels down     
// Float32Array[] => Float32Array     
var leftBuffer = flattenArray(leftchannel, recordingLength); // flattenArray is on GitHub (see below)     
var rightBuffer = flattenArray(rightchannel, recordingLength);    
    
// we interleave both channels together     
// [left[0],right[0],left[1],right[1],...]     
var interleaved = interleave(leftBuffer, rightBuffer); // interleave is on GitHub (see below)    
  
// we create our wav file     
var buffer = new ArrayBuffer(44 + interleaved.length * 2);     
var view = new DataView(buffer);    
  
// RIFF chunk descriptor     
writeUTFBytes(view, 0, 'RIFF');     
view.setUint32(4, 44 + interleaved.length * 2, true);     
writeUTFBytes(view, 8, 'WAVE');    
    
// FMT sub-chunk     
writeUTFBytes(view, 12, 'fmt ');     
view.setUint32(16, 16, true); // chunkSize     
view.setUint16(20, 1, true); // wFormatTag     
view.setUint16(22, 2, true); // wChannels: stereo (2 channels)     
view.setUint32(24, sampleRate, true); // dwSamplesPerSec     
view.setUint32(28, sampleRate * 4, true); // dwAvgBytesPerSec     
view.setUint16(32, 4, true); // wBlockAlign     
view.setUint16(34, 16, true); // wBitsPerSample    
    
// data sub-chunk     
writeUTFBytes(view, 36, 'data');     
view.setUint32(40, interleaved.length * 2, true);    
  
// write the PCM samples     
var index = 44;     
var volume = 1;     
for (var i = 0; i < interleaved.length; i++) {     
   view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);     
   index += 2;     
}    
  
// our final blob     
var blob = new Blob([view], { type: 'audio/wav' });

Et voilà. Il est ensuite possible de jouer le son directement dans le navigateur :

var url = window.URL.createObjectURL(blob);     
var audio = new Audio(url);     
audio.play();

Ou de télécharger le fichier :

var url = URL.createObjectURL(blob);    
var a = document.createElement("a");     
document.body.appendChild(a);     
a.style = "display: none";     
a.href = url;     
a.download = "sample.wav";     
a.click();     
window.URL.revokeObjectURL(url);

Vous pouvez trouver l’exemple fonctionnel sur GitHub : https://gist.github.com/meziantou/edb7217fddfbb70e899e.

Note : Le format wav est non compressé. Avant de transférer le fichier il est préférable de le compresser par exemple en mp3, cela peut se faire en JS avec https://github.com/akrennmair/libmp3lame-js.

Ne ratez plus aucunes actualités avec la newsletter mensuelle de SoftFluent