HTML5 오디오를 파일로 기록


123

내가 궁극적으로하고 싶은 것은 사용자의 마이크에서 녹음하고 완료되면 파일을 서버에 업로드하는 것입니다. 지금까지 다음 코드를 사용하여 요소에 대한 스트림을 만들었습니다.

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

여기서 파일에 녹음하려면 어떻게해야합니까?


2
danml.com/js/recaudio.js 는이 블로그 게시물을 기반으로 코드에서 정리 한 매우 짧은 단일 파일 라이브러리 (5kb)입니다. typedarray.org/wp-content/projects/WebAudioRecorder 는 내가 찾은 다른 파일 (일부 여기에 링크 됨) 사용법은 매우 간단합니다. recorder.start () 및 recorder.stop (fnCallbackToCatchWAV_URL)
dandavis

답변:


105

다음 사이트에서 상당히 완전한 레코딩 데모를 사용할 수 있습니다. http://webaudiodemos.appspot.com/AudioRecorder/index.html .

브라우저에서 오디오를 녹음 한 다음 녹음 한 내용을 내보내고 다운로드 할 수있는 옵션을 제공합니다.

해당 페이지의 소스를보고 자바 스크립트에 대한 링크를 찾을 수 있지만 요약 Recorder하면 exportWAV메서드와 메서드 를 포함하는 개체가 있습니다 forceDownload.


3
@Fibericon 더 이상은 (:. 안정 크롬 지금 너무 않습니다 (버전 28.0.1500.71 맥)
JSmyth

6
Windows 8에서 제대로 작동하지 않는 것 같고 오디오 재생이 조용합니다. 어떤 아이디어?
Mark Murphy

2
온라인으로 테스트 할 때는 괜찮습니다. 그러나 모든 html 파일 (js, png, ...)을 저장하면 로컬에서 작동하지 않습니다.
Randy Tang

2
데모를 테스트했는데 Chrome과 Opera에서 잘 작동하지만 파이어 폭스에 문제가 있습니다 (마이크는 인식되지만 소리는 아님). Safari와 IE의 경우 해당 코드를 처리하는 방법을 모릅니다
Tofandel

2
완전한 코드는 어디에 있습니까? 추출을 시도했지만 로컬 서버 (xampp)에서 작동하지 않습니다
gadss

43

아래에 표시된 코드는 Matt Diamond에게 저작권이 있으며 MIT 라이센스에 따라 사용할 수 있습니다. 원본 파일은 다음과 같습니다.

이 파일을 저장하고 사용

(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는이 오디오 녹음 파일에 대한 다운로드 코드를 제공합니다.
Iren Patel 2014

2
@Ankit Araynya 이것은 나를 위해 도움이되었습니다. 나는 무거운의 인터넷 검색로 3 때부터이 문제에 붙어
Hashir 셰이크에게

1
저장중인 blob의 이름을 변경해야합니다. 양식 데이터와 함께 ajax를 사용하고 파일 이름을 가져 오는 동안 blob을 서버에 보내고 있기 때문입니다. 저를 도울 수있는 것이 있습니까?
Jennifer

1
@Jennifer 당신은 서버 측에서 이름을 변경할 수 있습니다
Yassine Sedrani

1
ScriptProcessorNode가 메인 스레드에서 처리를 수행하고 레이아웃 계산, GC 및 기타 유사한 작업에 의해 차단되어 높은 버퍼 크기에서도 결함이 발생하기 때문에 오늘 여기에서 반대표를 떨어 뜨리는 경향이 있습니다. 죽은 간단한 데모 나 개념 증명으로는 괜찮지 만 합리적으로 복잡한 실제 앱에서는 괜찮습니다.
John Weisz

16

지금 업데이트 Chrome 은 v47의 MediaRecorder API 도 지원합니다 . 해야 할 똑같은 일은 그것을 사용하는 것입니다 (기본 녹음 방법이 해결 방법보다 빠르다고 추측), API는 정말 사용하기 쉽고 서버에 blob을 업로드하는 방법에 대한 많은 답변을 찾을 수 있습니다 .

데모 -Chrome 및 Firefox에서 작동하며 의도적으로 blob을 서버에 푸시하지 않았습니다.

코드 소스


현재이를 수행하는 세 가지 방법이 있습니다.

  1. 으로 wav[모든 코드 클라이언트 측, 비 압축 레코딩], 당신은 체크 아웃 할 수있다 -> Recorderjs을 . 문제 : 파일 크기가 상당히 커서 더 많은 업로드 대역폭이 필요합니다.
  2. mp3> - [모든 코드 클라이언트 측 압축 레코딩], 당신은 체크 아웃 할 수 mp3Recorder을 . 문제 : 개인적으로 품질이 나쁘고 라이선스 문제도 있습니다.
  3. ogg[클라이언트 + 서버 ( node.js) 코드, 압축 녹화, 브라우저 충돌없이 기록 무한한 시간, 당신은 체크 아웃 할 수있다 -> recordOpus , 중 유일한 클라이언트 측 녹음, 또는 클라이언트 - 서버 번들은, 선택은 당신입니다.

    ogg 녹음 예제 (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 녹음을위한 바이올린 데모 .


1
크롬 "script.js : 33 catch되지 않은 형식 오류 navigator.mediaDevices.getUserMedia는 함수가 아닙니다"
dikirill

@dikirill 서버를 사용하고 있어야합니다 (로컬로 작동 함), 파일로 작동하지 않으며, 또한 작업자에서 작동하지 않습니다 (나는 이것에 많은 두통이있었습니다), 서버를 만드는 방법을 모른다면 chrome.google.com/webstore/detail/web-server-for-chrome/…
John Balvin Arias

훌륭한 대답입니다. 귀하의 스크립트는 쉽고 간단합니다. 그러나 요청 스트림 작업을 수행하기 위해 시작 버튼을 변경하려고했는데 어떤 아이디어가 있습니까? github.com/Mido22/MediaRecorder-sample/issues/6
에도에도

13

이것은 간단한 JavaScript 녹음기 및 편집기입니다. 시도해 볼 수 있습니다.

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

다운로드여기에서

https://github.com/daaain/JSSoundRecorder


15
참고 것을 링크 전용 답변 낙심, SO 응답 솔루션 (대 아직 시간이 지남에 따라 부패하는 경향 참조의 다른 경유지)에 대한 검색의 엔드 포인트이어야한다. 링크를 참조로 유지하면서 여기에 독립형 개요를 추가하는 것을 고려하십시오.
kleopatra

1
적절하게, 제공된 첫 번째 링크는 죽은-하위 도메인 재 라우팅 문제입니다. 업데이트 된 링크는 http://www.danieldemmel.me/JSSoundRecorder/ 이지만 사이트가 HTTPS를 지원하지 않기 때문에 예제가 작동하지 않습니다 (Chrome 60). 에가는 보안 버전 과 보안 경고를 우회하는 것처럼 작업에 대한 데모를 허용한다.
brichins

6

이를 수행하는 gitHub 프로젝트가 있습니다.

브라우저의 오디오를 mp3 형식으로 녹음하고 자동으로 웹 서버에 저장합니다. https://github.com/Audior/Recordmp3js

구현에 대한 자세한 설명을 볼 수도 있습니다. http://audior.ec/blog/recording-mp3-using-only-html5-and-javascript-recordmp3-js/


3
이 프로젝트와 기사를 기반으로 사용 된 코드를 리팩토링하고 한 페이지에서 여러 레코더를 사용할 수 있도록 개선하는 또 다른 작은 도구를 작성했습니다. 다음에서 찾을 수 있습니다. github.com/icatcher-at/MP3RecorderJS
Vapire 2014-08-14

6

Recordmp3js 를 사용할 수 있습니다.GitHub의 를 하여 요구 사항을 충족 할 수 있습니다. 사용자의 마이크에서 녹음 한 다음 파일을 mp3로 가져올 수 있습니다. 마지막으로 서버에 업로드하십시오.

내 데모에서 이것을 사용했습니다. 다음 위치에 작성자가 소스 코드와 함께 사용할 수있는 샘플이 이미 있습니다. https://github.com/Audior/Recordmp3js

데모는 여기에 있습니다 : http://audior.ec/recordmp3js/

그러나 현재는 Chrome 및 Firefox에서만 작동합니다.

잘 작동하고 매우 간단합니다. 도움이 되었기를 바랍니다.


1
데모가 Chromium에서 작동하지 않고 콘솔에 경고가 표시됩니다. getUserMedia ()가 더 이상 안전하지 않은 출처에서 작동하지 않습니다.
dikirill

http, localhost 또는 라이브 서버에서 실행 해 보시겠습니까?
사예드

1
getUserMedia()전용 (HTTPS, 로컬 호스트) 보안 기원에서 작동 이후 크롬 47
옥타 Naicu

데모 링크가 끊어졌습니다.
Heitor

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.