HTML5 zeichnet Audio in Datei auf


123

Was ich letztendlich tun möchte, ist, vom Mikrofon des Benutzers aufzunehmen und die Datei auf den Server hochzuladen, wenn sie fertig sind. Bisher habe ich es geschafft, einen Stream zu einem Element mit dem folgenden Code zu erstellen:

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

Wie gehe ich von dort zur Aufnahme in eine Datei?


2
danml.com/js/recaudio.js ist eine wirklich kurze Einzeldateibibliothek (5 KB), die ich basierend auf diesem Blog-Beitrag aus dem Code entfernt habe: typedarray.org/wp-content/projects/WebAudioRecorder im Gegensatz zu den anderen, die ich gefunden habe (einige) hier verlinkt) die Verwendung ist ganz einfach: recorder.start () und recorder.stop (fnCallbackToCatchWAV_URL)
dandavis

Antworten:


105

Unter http://webaudiodemos.appspot.com/AudioRecorder/index.html ist eine ziemlich vollständige Aufnahmedemo verfügbar

Sie können Audio im Browser aufnehmen und anschließend die aufgenommenen Daten exportieren und herunterladen.

Sie können die Quelle dieser Seite anzeigen, um Links zum Javascript zu finden. Zusammenfassend gibt es jedoch ein RecorderObjekt, das eine exportWAVMethode und eine forceDownloadMethode enthält.


3
@ Fibreicon nicht mehr (: Stable Chrome jetzt auch (Version 28.0.1500.71 Mac).
JSmyth

6
Scheint unter Windows 8 nicht richtig zu funktionieren, die Audiowiedergabe ist stumm. Irgendwelche Ideen?
Mark Murphy

2
Es ist in Ordnung, wenn Sie online testen. Aber wenn ich alle HTML-Dateien (js, png, ...) speichere, funktioniert es nicht lokal.
Randy Tang

2
Ich habe die Demo getestet, sie funktioniert gut in Chrome und Opera, aber es gibt Probleme mit Firefox (das Mikrofon wird erkannt, aber nicht der Ton). Und für Safari und IE wissen sie nicht, wie sie mit diesem Code umgehen sollen
Tofandel

2
Wo kann ich den vollständigen Code haben? Ich habe versucht, es zu extrahieren, aber es funktioniert nicht auf meinem lokalen Server (xampp)
gadss

43

Der unten gezeigte Code ist für Matt Diamond urheberrechtlich geschützt und kann unter MIT-Lizenz verwendet werden. Die Originaldateien sind hier:

Speichern Sie diese Dateien und verwenden Sie

(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 Sie geben den Download-Code für diese Audioaufzeichnungsdatei an.
Iren Patel

2
@ Ankit Araynya das hilfreich für mich. Ich hielt an diesem Problem seit 3 ​​Tagen mit starkem Googeln
Hashir Sheikh

1
Ich muss den Namen des Blobs ändern, der speichert. weil ich Blob mit Ajax mit Formulardaten an den Server sende und beim Abrufen des Dateinamens seinen Blob gebe. Kannst du mir dabei helfen?
Jennifer

1
@ Jennifer Sie können den Namen auf der Serverseite ändern
Yassine Sedrani

1
Ich bin geneigt, heute hier eine Abwertung abzugeben, da ScriptProcessorNode die Verarbeitung im Hauptthread durchführt und durch Layoutberechnungen, GC und ähnliche Dinge blockiert wird, was selbst bei hohen Puffergrößen zu Störungen führt. Es ist in einer absolut einfachen Demo oder als Proof of Concept in Ordnung, aber nicht in einer einigermaßen komplexen realen App.
John Weisz

16

Update jetzt Chrome unterstützt auch MediaRecorder API von v47. Das Gleiche wäre, es zu verwenden (die native Aufzeichnungsmethode ist wahrscheinlich schneller als Umgehungen), die API ist wirklich einfach zu verwenden und Sie würden unzählige Antworten finden, wie Sie einen Blob für den Server hochladen .

Demo - würde in Chrome und Firefox funktionieren, absichtlich weggelassen, Blob auf Server zu schieben ...

Codequelle


Derzeit gibt es drei Möglichkeiten:

  1. Als wav[alle clientseitigen, unkomprimierten Code-Aufzeichnungen] können Sie -> Recorderjs auschecken . Problem: Die Dateigröße ist ziemlich groß, es ist mehr Upload-Bandbreite erforderlich.
  2. Als mp3[Client-seitige, komprimierte Code-Aufzeichnung] können Sie -> mp3Recorder auschecken . Problem: Ich persönlich finde die Qualität schlecht, auch gibt es dieses Lizenzproblem.
  3. Als ogg[client + server ( node.js) - Code, komprimierte Aufzeichnung, unendliche Stunden der Aufzeichnung ohne Browserabsturz] können Sie auschecken -> recordOpus , entweder nur clientseitige Aufzeichnung oder Client-Server-Bündelung. Sie haben die Wahl.

    Beispiel für eine Aufnahme (nur 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 für ogg Aufnahme.


1
Chromium "script.js: 33 Uncaught TypeError: navigator.mediaDevices.getUserMedia ist keine Funktion"
dikirill

@dikirill Sie müssen einen Server verwenden (es funktioniert lokal), es funktioniert nicht mit Dateien, es funktioniert auch nicht mit Arbeitern (ich hatte große Kopfschmerzen), wenn Sie nicht wissen, wie man einen Server zu Ihnen macht sollte chrome.google.com/webstore/detail/web-server-for-chrome/…
John Balvin Arias

ausgezeichnete Antwort, ich finde Ihr Skript einfach und unkompliziert. Ich habe jedoch versucht, die Startschaltfläche zu ändern, um auch die Aufgabe des Anforderungs-Streams zu erledigen. Irgendwelche Ideen? github.com/Mido22/MediaRecorder-sample/issues/6
Edo Edo

13

Dies ist ein einfacher JavaScript-Soundrekorder und -Editor. Du kannst es versuchen.

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

Kann von hier herunterladen

https://github.com/daaain/JSSoundRecorder


15
Beachten Sie, dass von Antworten nur mit Links abgeraten wird. SO-Antworten sollten der Endpunkt einer Suche nach einer Lösung sein (im Gegensatz zu einem weiteren Zwischenstopp von Referenzen, die im Laufe der Zeit veralten). Bitte fügen Sie hier eine eigenständige Zusammenfassung hinzu, wobei Sie den Link als Referenz behalten.
Kleopatra

1
Passenderweise handelt es sich bei dem ersten bereitgestellten Link um ein Problem mit der Umleitung von Subdomänen. Der aktualisierte Link ist http://www.danieldemmel.me/JSSoundRecorder/ aber das Beispiel nicht funktioniert sowieso (Chrome 60) , da die Website nicht HTTPS unterstützt. Wenn Sie zur sicheren Version wechseln und die Sicherheitswarnung umgehen, funktioniert die Demo jedoch.
Brichins

6

Hier ist ein gitHub-Projekt, das genau das tut.

Es zeichnet Audio vom Browser im MP3-Format auf und speichert es automatisch auf dem Webserver. https://github.com/Audior/Recordmp3js

Sie können auch eine detaillierte Erläuterung der Implementierung anzeigen: http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/


3
Basierend auf diesem Projekt und Artikel habe ich ein weiteres kleines Tool geschrieben, das den verwendeten Code überarbeitet und erweitert hat, um mehrere Rekorder auf einer Seite verwenden zu können. Es kann unter gefunden werden: github.com/icatcher-at/MP3RecorderJS
Vapire

6

Sie können mit Recordmp3js von GitHub Ihre Anforderungen zu erreichen. Sie können vom Mikrofon des Benutzers aufnehmen und die Datei dann als MP3 abrufen. Laden Sie es schließlich auf Ihren Server hoch.

Ich habe dies in meiner Demo verwendet. An dieser Stelle ist bereits ein Beispiel mit dem Quellcode des Autors verfügbar: https://github.com/Audior/Recordmp3js

Die Demo ist hier: http://audior.ec/recordmp3js/

Funktioniert derzeit aber nur unter Chrome und Firefox.

Scheint gut und ziemlich einfach zu funktionieren. Hoffe das hilft.


1
Ihre Demo funktioniert nicht in Chromium. Die Konsole zeigt eine Warnung an: getUserMedia () funktioniert nicht mehr bei unsicheren Ursprüngen.
dikirill

Versuchen Sie es auf http, über localhost oder auf einem Live-Server auszuführen?
Sagte

1
getUserMedia()funktioniert nur auf sicheren Ursprüngen (https, localhost) seit Chrome 47
Octavian Naicu

Demo-Link ist defekt.
Heitor

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.