HTML5 registra audio su file


123

Quello che voglio fare alla fine è registrare dal microfono dell'utente e caricare il file sul server quando hanno finito. Finora sono riuscito a creare un flusso su un elemento con il codice seguente:

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);
}

Come posso passare da quello alla registrazione su un file?


2
danml.com/js/recaudio.js è una libreria a file singolo davvero breve (5kb) che ho ripulito dal codice in base a questo post del blog: typedarray.org/wp-content/projects/WebAudioRecorder a differenza degli altri che ho trovato (alcuni linkato qui) l'utilizzo è abbastanza semplice: recorder.start () e recorder.stop (fnCallbackToCatchWAV_URL)
dandavis

Risposte:


105

C'è una demo di registrazione abbastanza completa disponibile su: http://webaudiodemos.appspot.com/AudioRecorder/index.html

Ti consente di registrare l'audio nel browser, quindi ti dà la possibilità di esportare e scaricare ciò che hai registrato.

È possibile visualizzare l'origine di quella pagina per trovare collegamenti al javascript, ma per riassumere, c'è un Recorderoggetto che contiene un exportWAVmetodo e un forceDownloadmetodo.


3
@Fibericon non più (: Stable Chrome lo fa anche adesso (versione 28.0.1500.71 per Mac).
JSmyth

6
Non sembra funzionare correttamente su Windows 8, la riproduzione audio è silenziosa. Qualche idea?
Mark Murphy

2
Va bene quando si esegue il test online. Ma se salvo tutti i file html (js, png, ...), non funziona localmente.
Randy Tang

2
Ho testato la demo, funziona bene in Chrome e Opera ma ci sono problemi con Firefox (il microfono è riconosciuto ma non il suono) .. E per Safari e IE, non sanno come gestire quel codice
Tofandel

2
dove posso avere il codice completo? Ho provato a estrarlo ma non funzionava nel mio server locale (xampp)
gadss

43

Il codice mostrato di seguito è protetto da copyright di Matt Diamond e può essere utilizzato con licenza MIT. I file originali sono qui:

Salva questo file e usa

(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>


1
@ Ankit Araynya fornisci il codice di download per questo file di registrazione audio.
Iren Patel

2
@Ankit Araynya è utile per me. Sono rimasto bloccato su questo problema da 3 giorni con pesanti ricerche su
Google

1
ho bisogno di cambiare il nome del blob che sta salvando. perché sto inviando il blob al server utilizzando ajax con i dati del modulo e mentre ottengo il nome del file è il blob che dà. C'è qualcosa che puoi aiutarmi in questo.
Jennifer

1
@ Jennifer puoi cambiare il nome sul lato server
Yassine Sedrani

1
Sono propenso a rilasciare un downvote qui oggi, perché ScriptProcessorNode esegue l'elaborazione sul thread principale e sarà bloccato dai calcoli del layout, GC e altre cose simili, portando a problemi anche con dimensioni del buffer elevate. Va bene in una demo semplice o come una prova di concetto, ma non in un'app reale ragionevolmente complessa.
John Weisz

16

Aggiornamento ora Chrome supporta anche MediaRecorder API da V47. La stessa cosa da fare sarebbe usarlo (supponendo che il metodo di registrazione nativo sia destinato ad essere più veloce del work around), l'API è davvero facile da usare e troverai tonnellate di risposte su come caricare un blob per il server .

Demo : funzionerebbe in Chrome e Firefox, omettendo intenzionalmente di spingere il blob al server ...

Codice sorgente


Attualmente ci sono tre modi per farlo:

  1. come wav[tutto il codice lato client, registrazione non compressa], puoi controllare -> Recorderjs . Problema: la dimensione del file è abbastanza grande, è necessaria una maggiore larghezza di banda per il caricamento.
  2. come mp3[tutto il codice lato client, registrazione compressa], puoi controllare -> mp3Recorder . Problema: personalmente trovo la qualità pessima, inoltre c'è questo problema di licenza.
  3. come ogg[ node.jscodice client + server ( ), registrazione compressa, infinite ore di registrazione senza crash del browser], puoi controllare -> recordOpus , solo la registrazione lato client o il raggruppamento client-server, a te la scelta.

    esempio di registrazione ogg (solo 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.
    }

    Fiddle Demo per la registrazione ogg.


1
Chromium "script.js: 33 Uncaught TypeError: navigator.mediaDevices.getUserMedia non è una funzione"
dikirill

@dikirill devi usare un server (funziona localmente), non funzionerà con i file, inoltre non funziona sui lavoratori (ho avuto molto mal di testa in questo), se non sai come creare un server tu dovrebbe installare chrome.google.com/webstore/detail/web-server-for-chrome/…
John Balvin Arias

ottima risposta, trovo il tuo script facile e semplice. tuttavia, stavo cercando di cambiare il pulsante di avvio per eseguire anche il lavoro di flusso di richieste, qualche idea? github.com/Mido22/MediaRecorder-sample/issues/6
Edo Edo

13

Questo è un semplice registratore ed editor di suoni JavaScript. Puoi provarlo.

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

Può scaricare da qui

https://github.com/daaain/JSSoundRecorder


15
Si noti che le risposte di solo collegamento sono scoraggiate, quindi le risposte dovrebbero essere il punto finale di una ricerca di una soluzione (rispetto a un'altra sosta di riferimenti, che tendono a diventare obsoleti nel tempo). Si prega di considerare l'aggiunta di una sinossi indipendente qui, mantenendo il collegamento come riferimento.
kleopatra

1
In modo appropriato, il primo collegamento fornito è un problema di reindirizzamento del sottodominio morto. Il collegamento aggiornato è http://www.danieldemmel.me/JSSoundRecorder/ ma l'esempio non funziona comunque (Chrome 60) perché il sito non supporta HTTPS. Tuttavia, passare alla versione sicura e ignorare l'avviso di sicurezza consente alla demo di funzionare.
brichins

6

Ecco un progetto gitHub che fa proprio questo.

Registra l'audio dal browser in formato mp3 e lo salva automaticamente sul server web. https://github.com/Audior/Recordmp3js

Puoi anche visualizzare una spiegazione dettagliata dell'implementazione: http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/


3
Sulla base di quel progetto e articolo ho scritto un altro piccolo strumento che ha refactoring il codice utilizzato e migliorato per poter utilizzare più registratori su una pagina. Può essere trovato sotto: github.com/icatcher-at/MP3RecorderJS
Vapire

6

Puoi utilizzare Recordmp3js da GitHub per soddisfare le tue esigenze. È possibile registrare dal microfono dell'utente e quindi ottenere il file come mp3. Infine caricalo sul tuo server.

L'ho usato nella mia demo. C'è già un esempio disponibile con il codice sorgente dell'autore in questa posizione: https://github.com/Audior/Recordmp3js

La demo è qui: http://audior.ec/recordmp3js/

Ma attualmente funziona solo su Chrome e Firefox.

Sembra funzionare bene e piuttosto semplice. Spero che questo ti aiuti.


1
La tua demo non funziona in Chromium, la console mostra un avviso: getUserMedia () non funziona più su origini non sicure.
dikirill

Prova a eseguirlo su http, tramite localhost o su un server live?
Detto

1
getUserMedia()funziona solo su origini sicure (https, localhost) da Chrome 47
Octavian Naicu

Il collegamento demo è interrotto.
Heitor

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.