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 :
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.