Back

Enregistrement audio dans le navigateur avec l'API Web Audio

Enregistrement audio dans le navigateur avec l'API Web Audio

La plupart des développeurs supposent que l’API Web Audio gère l’enregistrement. Ce n’est pas le cas — du moins pas directement. L’API Web Audio est un moteur de traitement et de routage. La tâche d’enregistrement à proprement parler revient à l’API MediaRecorder. Comprendre cette distinction est le moyen le plus rapide d’arrêter de construire la mauvaise chose.

Cet article présente l’architecture actuellement recommandée pour l’enregistrement audio dans le navigateur : capture de l’entrée microphone avec getUserMedia(), routage facultatif de l’audio à travers un graphe Web Audio, puis encodage avec MediaRecorder.

Points clés à retenir

  • L’API Web Audio traite et route l’audio, mais c’est MediaRecorder qui l’enregistre réellement dans un fichier.
  • Un pipeline d’enregistrement complet comporte trois étapes : capture avec getUserMedia(), traitement facultatif avec des nœuds Web Audio, et encodage avec MediaRecorder.
  • getUserMedia() nécessite un contexte sécurisé (HTTPS ou localhost) ainsi qu’une autorisation explicite du microphone par l’utilisateur.
  • Utilisez AudioWorklet pour les traitements DSP personnalisés ; ScriptProcessorNode est obsolète et provoque des artefacts en charge.
  • Vérifiez toujours la prise en charge du type MIME avec MediaRecorder.isTypeSupported() avant d’enregistrer, car Safari et Chrome diffèrent quant aux formats pris en charge.

Comment fonctionne réellement l’enregistrement audio dans le navigateur

Le pipeline d’enregistrement moderne comporte trois étapes distinctes :

  1. CapturegetUserMedia() demande l’accès au microphone et renvoie un MediaStream.
  2. Traitement (facultatif) — L’API Web Audio inspecte ou transforme le flux à travers des nœuds audio.
  3. EnregistrementMediaRecorder encode le flux dans un fichier.

Vous n’avez pas besoin de l’API Web Audio pour un enregistrement basique. Mais si vous souhaitez du filtrage de bruit, du contrôle de gain, de la visualisation ou des effets personnalisés via AudioWorklet, elle s’intègre parfaitement au milieu de cette chaîne.

Un détail subtil mais important : MediaRecorder enregistre directement un MediaStream. Si vous voulez enregistrer la sortie traitée d’un graphe Web Audio, vous devrez réinjecter le graphe dans un flux à l’aide de audioContext.createMediaStreamDestination() et passer la propriété .stream de ce nœud à MediaRecorder.

Étape 1 : Demander l’accès au microphone avec getUserMedia

getUserMedia() nécessite un contexte sécurisé (HTTPS ou localhost) et une autorisation explicite de l’utilisateur avant que le navigateur n’accorde l’accès au microphone.

try {
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: {
      echoCancellation: true,
      noiseSuppression: true,
      sampleRate: 44100
    }
  });
} catch (err) {
  console.error('Microphone access failed:', err.name, err.message);
}

Encapsulez toujours cet appel dans un try/catch. Les utilisateurs peuvent refuser l’autorisation, et certains environnements (comme les pages HTTP) rejetteront purement et simplement l’appel avec une erreur NotAllowedError ou SecurityError. Notez que les contraintes telles que sampleRate sont des indications — les navigateurs peuvent les ignorer selon le matériel sous-jacent.

Étape 2 : Router via l’API Web Audio (facultatif)

Si vous devez analyser ou traiter l’audio avant l’enregistrement, créez un AudioContext et faites passer le flux à travers celui-ci :

const audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(stream);

// Example: connect to an AnalyserNode for visualization
const analyser = audioContext.createAnalyser();
source.connect(analyser);

// To record the processed output, route to a MediaStreamDestination
const destination = audioContext.createMediaStreamDestination();
analyser.connect(destination);
// destination.stream is what you pass to MediaRecorder

Pour des traitements personnalisés — comme une porte de bruit ou un vumètre en temps réel — utilisez AudioWorklet plutôt que le ScriptProcessorNode désormais obsolète. AudioWorklet s’exécute hors du thread principal, ce qui signifie qu’il ne bloquera pas votre interface ni ne perdra d’échantillons audio en charge.

Remarque : Sur iOS Safari, AudioContext démarre dans un état suspendu jusqu’à ce qu’il soit déclenché par une interaction directe de l’utilisateur. Créez-le (ou appelez audioContext.resume()) à l’intérieur d’un gestionnaire de clic sur un bouton, et non au chargement de la page.

Étape 3 : Enregistrer et exporter avec MediaRecorder

MediaRecorder prend un MediaStream et l’encode. Ne codez pas en dur un type MIME — vérifiez d’abord la prise en charge :

function pickMimeType() {
  const candidates = [
    'audio/webm;codecs=opus',
    'audio/ogg;codecs=opus',
    'audio/mp4'
  ];
  return candidates.find(type => MediaRecorder.isTypeSupported(type)) || '';
}

const mimeType = pickMimeType();
const recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined);
const chunks = [];

recorder.ondataavailable = (e) => {
  if (e.data.size > 0) chunks.push(e.data);
};

recorder.onstop = () => {
  const blob = new Blob(chunks, {
    type: recorder.mimeType || mimeType || chunks[0]?.type || 'audio/webm'
  });

  const url = URL.createObjectURL(blob);
  document.querySelector('audio').src = url;
};

recorder.start();

WebM/Opus est généralement le meilleur choix par défaut pour les navigateurs modernes — petite taille de fichier, excellente qualité. Safari préfère souvent audio/mp4. Parcourir une liste de types candidats et laisser le navigateur choisir le premier qu’il prend en charge est la stratégie la plus fiable. Vous pouvez vérifier la prise en charge actuelle de MediaRecorder et des formats associés sur Can I Use.

MediaRecorder vs API Web Audio : référence rapide

BesoinÀ utiliser
Enregistrement microphone simplegetUserMedia + MediaRecorder
Effets ou filtres en temps réelNœuds de l’API Web Audio
Traitement DSP personnaliséAudioWorklet
Visualisation audioAnalyserNode
Encodage dans un fichierMediaRecorder

Ce qu’il faut éviter

  • ScriptProcessorNode — obsolète, s’exécute sur le thread principal, provoque des artefacts audio en charge.
  • Types MIME codés en dur — échouent silencieusement sur Safari et les anciennes versions de Firefox.
  • Création d’AudioContext au chargement de la page — les navigateurs le suspendent jusqu’à un geste de l’utilisateur ; reprenez-le donc dans un gestionnaire d’événements.
  • Oublier d’arrêter le flux — appelez stream.getTracks().forEach(t => t.stop()) une fois terminé, sinon l’indicateur de microphone restera allumé.

Conclusion

L’enregistrement audio dans le navigateur est une affaire de deux API : getUserMedia() et MediaRecorder gèrent la capture et l’encodage, tandis que l’API Web Audio s’occupe de tout ce qui se passe entre les deux. Commencez par le pipeline le plus simple répondant à vos besoins, ajoutez du traitement Web Audio uniquement quand c’est nécessaire, et vérifiez toujours la prise en charge du type MIME avant de configurer MediaRecorder. Voilà toute l’architecture résumée en une phrase.

FAQ

Non. Pour un enregistrement basique, getUserMedia() et MediaRecorder suffisent. L'API Web Audio ne devient nécessaire que lorsque vous devez traiter, analyser ou transformer l'audio avant l'enregistrement, par exemple pour appliquer des filtres, créer des visualisations ou exécuter du DSP personnalisé via un AudioWorklet.

Safari et Chrome prennent en charge des formats d'enregistrement différents. Safari préfère souvent audio/mp4, tandis que Chrome utilise généralement WebM/Opus. Si vous codez en dur un type MIME non pris en charge, MediaRecorder peut générer une erreur ou produire une sortie inutilisable. Utilisez toujours MediaRecorder.isTypeSupported() pour détecter un format compatible à l'exécution.

Créez un MediaStreamAudioDestinationNode à l'aide de audioContext.createMediaStreamDestination(), connectez le nœud final de votre graphe audio à celui-ci et transmettez sa propriété .stream à MediaRecorder. Cela capture l'audio post-traité plutôt que le flux microphone brut provenant de getUserMedia().

iOS Safari exige que AudioContext soit créé ou repris dans le cadre d'un geste utilisateur direct, comme un événement de clic ou de toucher. Si vous l'instanciez lors du chargement de la page, il reste suspendu. Déplacez la création de AudioContext dans un gestionnaire de bouton, ou appelez audioContext.resume() à l'intérieur de celui-ci pour débloquer la lecture et le traitement.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay