HTML5 sesi dosyaya kaydet


123

Nihayetinde yapmak istediğim şey, kullanıcının mikrofonundan kayıt yapmak ve iş bittiğinde dosyayı sunucuya yüklemek. Şimdiye kadar, aşağıdaki kodla bir öğeye akış yapmayı başardım:

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

Bundan bir dosyaya kaydetmeye nasıl geçebilirim?


2
danml.com/js/recaudio.js , bu blog gönderisine dayanarak koddan temizlediğim gerçekten kısa bir tek dosyalı kitaplıktır (5kb): typedarray.org/wp-content/projects/WebAudioRecorder , bulduğum diğerlerinin aksine (bazıları burada bağlantılı) kullanım oldukça basittir: kaydedici.start () ve kaydedici.stop (fnCallbackToCatchWAV_URL)
dandavis

Yanıtlar:


105

Şu adreste oldukça eksiksiz bir kayıt demosu mevcuttur: http://webaudiodemos.appspot.com/AudioRecorder/index.html

Tarayıcıda ses kaydetmenize olanak tanır, ardından kaydettiklerinizi dışa aktarma ve indirme seçeneği sunar.

Javascript bağlantılarını bulmak için bu sayfanın kaynağını görüntüleyebilirsiniz, ancak özetlemek gerekirse, Recorderbir exportWAVyöntem içeren bir nesne ve bir forceDownloadyöntem vardır.


3
@Fibericon artık değil (: Stable Chrome da artık (Sürüm 28.0.1500.71 Mac).
JSmyth

6
Windows 8'de düzgün çalışmıyor gibi görünüyor, ses çalma sessiz. Herhangi bir fikir?
Mark Murphy

2
Çevrimiçi test ederken sorun yok. Ancak tüm html dosyalarını (js, png, ...) kaydedersem, yerel olarak çalışmaz.
Randy Tang

2
Demoyu test ettim, Chrome ve Opera'da gayet iyi çalışıyor ancak firefox ile ilgili sorunlar var (mikrofon tanınıyor ama ses değil) .. Ve Safari ve IE için bu kodu nasıl kullanacaklarını bilmiyorlar
Tofandel

2
tam kodu nereden alabilirim? Onu çıkarmaya çalıştım ama yerel sunucumda (xampp)
çalışmıyor

43

Aşağıda gösterilen kodun telif hakkı Matt Diamond'a aittir ve MIT lisansı altında kullanılabilir. Orijinal dosyalar burada:

Bu dosyaları kaydedin ve kullanın

(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 bu ses kayıt dosyası için indirme kodunu vermişsinizdir.
Iren Patel

2
@Ankit Araynya bu benim için faydalı. 3 günden beri yoğun bir şekilde googling ile bu soruna takılı
kaldım

1
Tasarruf eden blobun adını değiştirmem gerekiyor. çünkü ajax kullanarak sunucuya blob gönderiyorum ve dosya adını alırken blob veriyor. Bana yardımcı olabileceğin bir şey var mı?
Jennifer

1
@Jennifer, sunucu tarafında adı değiştirebilirsiniz
Yassine Sedrani

1
Bugün burada bir aşağı oy verme eğilimindeyim, çünkü ScriptProcessorNode ana iş parçacığı üzerinde işlem yapıyor ve düzen hesaplamaları, GC ve diğer benzer şeyler tarafından engellenecek ve yüksek arabellek boyutlarında bile hatalara yol açacak. Son derece basit bir demoda veya bir kavram kanıtı olarak sorun değil, ancak makul derecede karmaşık gerçek uygulamalarda değil.
John Weisz

17

Şimdi güncelle Chrome , v47'deki MediaRecorder API'yi de destekler . Yapılması gereken aynı şey, onu kullanmak olacaktır (yerel kayıt yöntemini tahmin etmek, geçici çözümlerden daha hızlıdır), API'nin kullanımı gerçekten kolaydır ve sunucu için bir blobun nasıl yükleneceğine dair tonlarca yanıt bulacaksınız. .

Demo - Chrome ve Firefox'ta çalışacak, kasıtlı olarak blob'u sunucuya göndermeyecekti ...

Kod Kaynağı


Şu anda bunu yapmanın üç yolu var:

  1. olarak wav> - [Tüm kod istemci tarafında, sıkıştırılmamış kayıt], göz atmanız için Recorderjs . Sorun: dosya boyutu oldukça büyük, daha fazla yükleme bant genişliği gerekiyor.
  2. olarak mp3> - [Tüm kod istemci tarafında, sıkıştırılmış kayıt], göz atmanız için MP3Recorder . Sorun: Şahsen ben kaliteyi kötü buluyorum, bir de bu lisans sorunu var.
  3. olarak ogg[istemci + sunucu ( node.js) kodu, sıkıştırılmış kayıt, tarayıcı çökmesi olmadan kayıt sonsuz saat], sen kontrol edebilirsiniz -> recordOpus , ya sadece istemci tarafı kayıt veya istemci-sunucu Paket oluşturma, seçim sizin.

    ogg kayıt örneği (yalnızca 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.
    }
    

    Ogg kaydı için Fiddle Demo .


1
Chromium "script.js: 33 Yakalanmamış TypeError: navigator.mediaDevices.getUserMedia bir işlev değil"
dikirill

@dikirill bir sunucu kullanıyor olmalısınız (yerel olarak çalışıyor), dosyalarla çalışmıyor, ayrıca işçiler üzerinde çalışmıyor (bu konuda çok başım ağrıyor), nasıl sunucu yapacağınızı bilmiyorsanız chrome.google.com/webstore/detail/web-server-for-chrome/…
John Balvin Arias

mükemmel cevap, senaryonuzu kolay ve basit buluyorum. ancak, istek akışı işini de yapmak için başlat düğmesini değiştirmeye çalışıyordum, herhangi bir fikriniz var mı? github.com/Mido22/MediaRecorder-sample/issues/6
Edo Edo

13

Bu, basit bir JavaScript ses kaydedici ve düzenleyicidir. Deneyebilirsin.

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

Can indirmek buradan

https://github.com/daaain/JSSoundRecorder


15
Not o bağlantı sadece cevaplar tavsiye edilmez, SO cevaplar çözüm (vs. henüz zamanla bayat almak eğilimindedir referanslar, başka mola) için bir aramanın son nokta olmalıdır. Lütfen bağlantıyı referans olarak koruyarak buraya bağımsız bir özet eklemeyi düşünün.
kleopatra

1
Uygun şekilde, sağlanan ilk bağlantı ölü - alt alan yeniden yönlendirme sorunu. Güncellenen bağlantı http://www.danieldemmel.me/JSSoundRecorder/, ancak site HTTPS'yi desteklemediği için örnek yine de çalışmıyor (Chrome 60). Güvenli sürüme geçmek ve güvenlik uyarısını atlamak, demonun çalışmasına izin verir.
brichins

6

İşte tam da bunu yapan bir gitHub projesi.

Tarayıcıdan gelen sesi mp3 formatında kaydeder ve otomatik olarak web sunucusuna kaydeder. https://github.com/Audior/Recordmp3js

Ayrıca uygulamanın ayrıntılı bir açıklamasını da görüntüleyebilirsiniz: http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/


3
Bu proje ve makaleye dayanarak, kullanılan kodu yeniden düzenleyen ve bir sayfada birden fazla kaydedici kullanabilmek için geliştiren başka bir küçük araç yazdım. Şurada
Vapire

6

Gereksinimlerinize ulaşmak için GitHub'daki Recordmp3j'leri kullanabilirsiniz . Kullanıcının mikrofonundan kayıt yapabilir ve ardından dosyayı mp3 olarak alabilirsiniz. Sonunda sunucunuza yükleyin.

Bunu demomda kullandım. Bu konumda yazar tarafından kaynak koduyla zaten mevcut bir örnek var: https://github.com/Audior/Recordmp3js

Demo burada: http://audior.ec/recordmp3js/

Ancak şu anda yalnızca Chrome ve Firefox'ta çalışıyor.

İyi ve oldukça basit çalışıyor gibi görünüyor. Bu yardımcı olur umarım.


1
Demonuz Chromium'da çalışmıyor, konsol uyarı gösteriyor: getUserMedia () artık güvenli olmayan kaynaklar üzerinde çalışmıyor.
dikirill

Http'de, localhost aracılığıyla veya canlı bir sunucuda çalıştırmayı deneyin.
Sayed


Demo bağlantısı koptu.
Heitor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.