HTML5 enregistre l'audio dans un fichier

123

Ce que je veux en fin de compte, c'est enregistrer à partir du microphone de l'utilisateur et télécharger le fichier sur le serveur quand ils ont terminé. Jusqu'à présent, j'ai réussi à créer un flux vers un élément avec le code suivant:

var audio = document.getElementById("audio_preview");

navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
navigator.getUserMedia({video: false, audio: true}, function(stream) {
   audio.src = window.URL.createObjectURL(stream);
}, onRecordFail);

var onRecordFail = function (e) {
   console.log(e);
}

Comment puis-je passer de cela à l'enregistrement dans un fichier?

Fibreicon
la source
2
danml.com/js/recaudio.js est une très courte bibliothèque à fichier unique (5 ko) que j'ai nettoyée du code basé sur ce billet de blog: typedarray.org/wp-content/projects/WebAudioRecorder contrairement aux autres que j'ai trouvés (certains lié ici) l'utilisation est assez simple: recorder.start () et recorder.stop (fnCallbackToCatchWAV_URL)
dandavis
1
À partir de 2016: stackoverflow.com/questions/34820578/…
Bennett Brown

Réponses:

105

Une démo d'enregistrement assez complète est disponible sur: http://webaudiodemos.appspot.com/AudioRecorder/index.html

Il vous permet d'enregistrer de l'audio dans le navigateur, puis vous donne la possibilité d'exporter et de télécharger ce que vous avez enregistré.

Vous pouvez afficher la source de cette page pour trouver des liens vers le javascript, mais pour résumer, il existe un Recorderobjet qui contient une exportWAVméthode et une forceDownloadméthode.

Brad Montgomery
la source
3
@Fibericon plus (: Chrome stable aussi maintenant (Version 28.0.1500.71 Mac).
JSmyth
6
Ne semble pas fonctionner correctement sous Windows 8, la lecture audio est silencieuse. Des idées?
Mark Murphy
2
C'est bien lors des tests en ligne. Mais si je sauvegarde tous les fichiers html (js, png, ...), cela ne fonctionne pas localement.
Randy Tang
2
J'ai testé la démo, cela fonctionne bien dans Chrome et Opera mais il y a des problèmes avec Firefox (le microphone est reconnu mais pas le son) .. Et pour Safari et IE, ils ne savent pas comment gérer ce code
Tofandel
2
où puis-je avoir le code complet? J'ai essayé de l'extraire mais ne fonctionne pas sur mon serveur local (xampp)
gadss
43

Le code ci-dessous est la propriété de Matt Diamond et peut être utilisé sous licence MIT. Les fichiers originaux sont ici:

Enregistrez ces fichiers et utilisez

(function(window){

      var WORKER_PATH = 'recorderWorker.js';
      var Recorder = function(source, cfg){
        var config = cfg || {};
        var bufferLen = config.bufferLen || 4096;
        this.context = source.context;
        this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
        var worker = new Worker(config.workerPath || WORKER_PATH);
        worker.postMessage({
          command: 'init',
          config: {
            sampleRate: this.context.sampleRate
          }
        });
        var recording = false,
          currCallback;

        this.node.onaudioprocess = function(e){
          if (!recording) return;
          worker.postMessage({
            command: 'record',
            buffer: [
              e.inputBuffer.getChannelData(0),
              e.inputBuffer.getChannelData(1)
            ]
          });
        }

        this.configure = function(cfg){
          for (var prop in cfg){
            if (cfg.hasOwnProperty(prop)){
              config[prop] = cfg[prop];
            }
          }
        }

        this.record = function(){
       
          recording = true;
        }

        this.stop = function(){
        
          recording = false;
        }

        this.clear = function(){
          worker.postMessage({ command: 'clear' });
        }

        this.getBuffer = function(cb) {
          currCallback = cb || config.callback;
          worker.postMessage({ command: 'getBuffer' })
        }

        this.exportWAV = function(cb, type){
          currCallback = cb || config.callback;
          type = type || config.type || 'audio/wav';
          if (!currCallback) throw new Error('Callback not set');
          worker.postMessage({
            command: 'exportWAV',
            type: type
          });
        }

        worker.onmessage = function(e){
          var blob = e.data;
          currCallback(blob);
        }

        source.connect(this.node);
        this.node.connect(this.context.destination);    //this should not be necessary
      };

      Recorder.forceDownload = function(blob, filename){
        var url = (window.URL || window.webkitURL).createObjectURL(blob);
        var link = window.document.createElement('a');
        link.href = url;
        link.download = filename || 'output.wav';
        var click = document.createEvent("Event");
        click.initEvent("click", true, true);
        link.dispatchEvent(click);
      }

      window.Recorder = Recorder;

    })(window);

    //ADDITIONAL JS recorderWorker.js
    var recLength = 0,
      recBuffersL = [],
      recBuffersR = [],
      sampleRate;
    this.onmessage = function(e){
      switch(e.data.command){
        case 'init':
          init(e.data.config);
          break;
        case 'record':
          record(e.data.buffer);
          break;
        case 'exportWAV':
          exportWAV(e.data.type);
          break;
        case 'getBuffer':
          getBuffer();
          break;
        case 'clear':
          clear();
          break;
      }
    };

    function init(config){
      sampleRate = config.sampleRate;
    }

    function record(inputBuffer){

      recBuffersL.push(inputBuffer[0]);
      recBuffersR.push(inputBuffer[1]);
      recLength += inputBuffer[0].length;
    }

    function exportWAV(type){
      var bufferL = mergeBuffers(recBuffersL, recLength);
      var bufferR = mergeBuffers(recBuffersR, recLength);
      var interleaved = interleave(bufferL, bufferR);
      var dataview = encodeWAV(interleaved);
      var audioBlob = new Blob([dataview], { type: type });

      this.postMessage(audioBlob);
    }

    function getBuffer() {
      var buffers = [];
      buffers.push( mergeBuffers(recBuffersL, recLength) );
      buffers.push( mergeBuffers(recBuffersR, recLength) );
      this.postMessage(buffers);
    }

    function clear(){
      recLength = 0;
      recBuffersL = [];
      recBuffersR = [];
    }

    function mergeBuffers(recBuffers, recLength){
      var result = new Float32Array(recLength);
      var offset = 0;
      for (var i = 0; i < recBuffers.length; i++){
        result.set(recBuffers[i], offset);
        offset += recBuffers[i].length;
      }
      return result;
    }

    function interleave(inputL, inputR){
      var length = inputL.length + inputR.length;
      var result = new Float32Array(length);

      var index = 0,
        inputIndex = 0;

      while (index < length){
        result[index++] = inputL[inputIndex];
        result[index++] = inputR[inputIndex];
        inputIndex++;
      }
      return result;
    }

    function floatTo16BitPCM(output, offset, input){
      for (var i = 0; i < input.length; i++, offset+=2){
        var s = Math.max(-1, Math.min(1, input[i]));
        output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
      }
    }

    function writeString(view, offset, string){
      for (var i = 0; i < string.length; i++){
        view.setUint8(offset + i, string.charCodeAt(i));
      }
    }

    function encodeWAV(samples){
      var buffer = new ArrayBuffer(44 + samples.length * 2);
      var view = new DataView(buffer);

      /* RIFF identifier */
      writeString(view, 0, 'RIFF');
      /* file length */
      view.setUint32(4, 32 + samples.length * 2, true);
      /* RIFF type */
      writeString(view, 8, 'WAVE');
      /* format chunk identifier */
      writeString(view, 12, 'fmt ');
      /* format chunk length */
      view.setUint32(16, 16, true);
      /* sample format (raw) */
      view.setUint16(20, 1, true);
      /* channel count */
      view.setUint16(22, 2, true);
      /* sample rate */
      view.setUint32(24, sampleRate, true);
      /* byte rate (sample rate * block align) */
      view.setUint32(28, sampleRate * 4, true);
      /* block align (channel count * bytes per sample) */
      view.setUint16(32, 4, true);
      /* bits per sample */
      view.setUint16(34, 16, true);
      /* data chunk identifier */
      writeString(view, 36, 'data');
      /* data chunk length */
      view.setUint32(40, samples.length * 2, true);

      floatTo16BitPCM(view, 44, samples);

      return view;
    }
<html>
    	<body>
    		<audio controls autoplay></audio>
    		<script type="text/javascript" src="recorder.js"> </script>
                    <fieldset><legend>RECORD AUDIO</legend>
    		<input onclick="startRecording()" type="button" value="start recording" />
    		<input onclick="stopRecording()" type="button" value="stop recording and play" />
                    </fieldset>
    		<script>
    			var onFail = function(e) {
    				console.log('Rejected!', e);
    			};

    			var onSuccess = function(s) {
    				var context = new webkitAudioContext();
    				var mediaStreamSource = context.createMediaStreamSource(s);
    				recorder = new Recorder(mediaStreamSource);
    				recorder.record();

    				// audio loopback
    				// mediaStreamSource.connect(context.destination);
    			}

    			window.URL = window.URL || window.webkitURL;
    			navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

    			var recorder;
    			var audio = document.querySelector('audio');

    			function startRecording() {
    				if (navigator.getUserMedia) {
    					navigator.getUserMedia({audio: true}, onSuccess, onFail);
    				} else {
    					console.log('navigator.getUserMedia not present');
    				}
    			}

    			function stopRecording() {
    				recorder.stop();
    				recorder.exportWAV(function(s) {
                                
                                 	audio.src = window.URL.createObjectURL(s);
    				});
    			}
    		</script>
    	</body>
    </html>

Ankit Aranya
la source
1
@ Ankit Araynya vous fournissez le code de téléchargement pour ce fichier d'enregistrement audio.
Iren Patel
2
@Ankit Araynya cela m'aide. Je suis coincé sur ce problème depuis 3 jours avec une recherche intensive sur Google
Hashir Sheikh
1
j'ai besoin de changer le nom du blob qui enregistre. parce que j'envoie le blob au serveur en utilisant ajax avec des données de formulaire et en obtenant le nom du fichier, il donne le blob. Pouvez-vous m'aider quelque chose.
Jennifer
1
@Jennifer vous pouvez changer le nom côté serveur
Yassine Sedrani
1
Je suis enclin à abandonner un vote défavorable ici aujourd'hui, car ScriptProcessorNode effectue le traitement sur le thread principal et sera bloqué par les calculs de disposition, GC et autres éléments similaires, ce qui entraînera des problèmes même avec des tailles de tampon élevées. C'est bien dans une démo simple ou comme une preuve de concept, mais pas dans une application réelle raisonnablement complexe.
John Weisz
16

Mise à jour maintenant Chrome prend également en charge MediaRecorder API de v47. La même chose à faire serait de l'utiliser (en supposant que la méthode d'enregistrement native est forcément plus rapide que les contournements), l'API est vraiment facile à utiliser et vous trouverez des tonnes de réponses sur la façon de télécharger un objet blob pour le serveur. .

Démo - fonctionnerait dans Chrome et Firefox, volontairement laissé de côté en poussant le blob vers le serveur ...

Source du code


Actuellement, il existe trois façons de procéder:

  1. comme wav[tout le code client, enregistrement non compressé], vous pouvez vérifier -> Recorderjs . Problème: la taille du fichier est assez grande, plus de bande passante de téléchargement est requise.
  2. comme mp3[tout le code client, enregistrement compressé], vous pouvez vérifier -> mp3Recorder . Problème: personnellement, je trouve la qualité mauvaise, il y a aussi ce problème de licence.
  3. comme ogg[ node.jscode client + serveur ( ), enregistrement compressé, heures infinies d'enregistrement sans plantage du navigateur], vous pouvez vérifier -> recordOpus , soit uniquement l'enregistrement côté client, soit le regroupement client-serveur, le choix vous appartient.

    Exemple d'enregistrement ogg (uniquement Firefox):

    var mediaRecorder = new MediaRecorder(stream);
    mediaRecorder.start();  // to start recording.    
    ...
    mediaRecorder.stop();   // to stop recording.
    mediaRecorder.ondataavailable = function(e) {
        // do something with the data.
    }
    

    Démo Fiddle pour l'enregistrement ogg.

mido
la source
1
Chromium "script.js: 33 Uncaught TypeError: navigator.mediaDevices.getUserMedia n'est pas une fonction"
dikirill
@dikirill vous devez utiliser un serveur (cela fonctionne localement), cela ne fonctionnera pas avec les fichiers, et cela ne fonctionne pas non plus sur les travailleurs (j'ai eu beaucoup de mal à la tête), si vous ne savez pas comment créer un serveur vous devrait installer chrome.google.com/webstore/detail/web-server-for-chrome/…
John Balvin Arias
excellente réponse, je trouve votre script facile et simple. cependant, j'essayais de changer le bouton de démarrage pour faire le travail de flux de demande également, des idées? github.com/Mido22/MediaRecorder-sample/issues/6
Edo Edo
13

Il s'agit d'un simple enregistreur et éditeur de sons JavaScript. Tu peux l'essayer.

https://www.danieldemmel.me/JSSoundRecorder/

Peut télécharger à partir d'ici

https://github.com/daaain/JSSoundRecorder

jhpratt
la source
15
Notez que les réponses liées uniquement aux liens sont déconseillées, les réponses SO devraient être le point final de la recherche d'une solution (par rapport à une autre escale de références, qui ont tendance à devenir obsolètes avec le temps). Veuillez envisager d'ajouter un synopsis autonome ici, en gardant le lien comme référence.
kleopatra
1
De manière appropriée, le premier lien fourni est mort - problème de réacheminement de sous-domaine. Le lien mis à jour est http://www.danieldemmel.me/JSSoundRecorder/ mais l'exemple ne fonctionne pas de toute façon (Chrome 60) car le site ne prend pas en charge HTTPS. Passer à la version sécurisée et contourner l'avertissement de sécurité permet cependant à la démo de fonctionner.
brichins
6

Voici un projet gitHub qui fait exactement cela.

Il enregistre l'audio du navigateur au format mp3 et l'enregistre automatiquement sur le serveur Web. https://github.com/Audior/Recordmp3js

Vous pouvez également consulter une explication détaillée de l'implémentation: http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/

Remus Negrota
la source
3
Sur la base de ce projet et de cet article, j'ai écrit un autre petit outil qui a remanié le code utilisé et l'a amélioré pour pouvoir utiliser plusieurs enregistreurs sur une page. Il peut être trouvé sous: github.com/icatcher-at/MP3RecorderJS
Vapire
6

Vous pouvez utiliser Recordmp3js de GitHub pour répondre à vos besoins. Vous pouvez enregistrer à partir du microphone de l'utilisateur, puis obtenir le fichier au format mp3. Enfin, téléchargez-le sur votre serveur.

J'ai utilisé ceci dans ma démo. Il existe déjà un exemple disponible avec le code source par l'auteur à cet emplacement: https://github.com/Audior/Recordmp3js

La démo est ici: http://audior.ec/recordmp3js/

Mais ne fonctionne actuellement que sur Chrome et Firefox.

Semble bien fonctionner et assez simple. J'espère que cela t'aides.

Adithya Kumaranchath
la source
1
Votre démo ne fonctionne pas dans Chromium, la console affiche un avertissement: getUserMedia () ne fonctionne plus sur les origines non sécurisées.
dikirill
Essayez de l'exécuter sur http, via localhost ou sur un serveur en direct?
Dit
1
getUserMedia()ne fonctionne que sur les origines sécurisées (https, localhost) depuis Chrome 47
Octavian Naicu
Le lien de démonstration est rompu.
Heitor