2014-12-01 30 views
5

웹 사이트 사용자의 오디오를 녹음하고 내 서버에 오디오를 저장하려고합니다. 지금까지 내가 연구 한 많은 게시물은 Matt Diamond의 레코더를 참조했습니다. 내 브라우저를 통해 소스 코드를 열어서 http://webaudiodemos.appspot.com/AudioRecorder/index.html에서 데모를 다시 만들려고했습니다. html "audiodisplay.js", "recorder.js"및 "main.js"를 복사하여 내 서버에 저장했습니다. GitHub 사이트에서 "recorderWorker.js"파일도 추가했습니다. recorder.js 파일에서 var WORKER_PATH = 'js/recorderjs/recorderWorker.js'를 var WORKER_PATH = 'recorderWorker.js'로 변경했습니다.사용자의 오디오를 녹음하고 서버에 저장

설정 한 데모를 실행하면 "마이크를 공유하고 싶습니까?"라는 경고 메시지가 나타나며 오른쪽의 마이크 아이콘을 눌러 녹음을 시작할 수 있습니다. 그러나 녹음을 중지하면 Matt의 데모처럼 오디오 파형이 아래에 나타나지 않고 저장 아이콘이 활성화되지 않습니다.

데모를 실행하면 다음 문제는 로컬로 데모 대신 서버에 wav 파일을 저장하는 것입니다. XMLHttpRequest()를 사용하는 몇 가지 게시물을 발견했지만, 실제로 이러한 예제를 레코더에 연결하는 방법을 알 수는 없습니다. Saving WAV File Recorded in Chrome to ServerHTML5 & getUserMedia - Record Audio & Save to Web Server after Certain TimeRecorderJS uploading recorded blob via AJAX

답변

4

나는 하나의 해결책을 알아 냈지만, 여전히 레코더와 관련된 다른 것들을 환영한다. 나는 https://github.com/icatcher-at/MP3RecorderJS에 MP3RecorderJS를 사용했다. 데모 html은 html의 맨 위를 src = "js/jquery.min.js"에서 src = "js/mp3recorder.js"에서 서버에있는 모든 위치로 변경하면 작동합니다. 저에게 src = "jquery.min.js"이고 src = "mp3recorder.js"입니다. "mp3recorder.js"파일에도 똑같은 작업을해야합니다 : var RECORDER_WORKER_PATH = 'js/recorderWorker.js'; var ENCODER_WORKER_PATH = 'js/mp3Worker.js'; var로 변경되었습니다. RECORDER_WORKER_PATH = 'recorderWorker.js'; var ENCODER_WORKER_PATH = 'mp3Worker.js';

이 프로그램은 mp3와 wav를 모두 기록하도록 설정되어 있습니다. 나는 wav를 원했기 때문에 html 파일을 좀 더 조정했다. 라인 55에서 찾을 수 있습니다 :

recorderObject.exportWAV(function(base64_wav_data) { 
     var url = 'data:audio/wav;base64,' + base64_wav_data; 
     var au = document.createElement('audio'); 

데모는 새로운 선수 녹음 할 때마다 추가 :

recorderObject.exportMP3(function(base64_mp3_data) { 
     var url = 'data:audio/mp3;base64,' + base64_mp3_data; 
     var au = document.createElement('audio'); 

나는 것을 변경되었습니다. 이를 방지하기 위해 $ recorder.append (au)를 삭제 (주석 처리)했습니다. 오디오 플레이어를 저장하기 위해 새 div를 만든 다음 오디오 플레이어가 만들어지기 전에 매번 div를 지 웁니다. 내 서버에 업로드하려면 이미지를 서버에 업로드 할 때 배운 기술을 사용했습니다. save canvas image to server 기본적으로 56 행의 "url"변수는 필요한 것이지만 범용 변수에 넣는 방법을 알아낼 수 없었습니다 다른 기능으로 그래서, 숨겨진 div를 만들고 그 내용을 "url"과 동일하게 만들었습니다. 그런 다음 div를 "업로드"라는 새로운 기능으로 참조했습니다. 나는 "uploadWav.php"라는 PHP 파일을 사용했다. 아직 업로드 버튼을 활성화하거나 비활성화하여 녹화 전에 빈 파일을 업로드하지 못하도록하는 방법을 찾아야하지만 또 다른 문제입니다.

<!DOCTYPE html> 
<html> 
    <head> 
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 
    <title>MP3 Recorder test</title> 
    </head> 
    <body id="index" onload=""> 

    <script type="text/javascript" src="jquery.min.js"></script> 
    <script type="text/javascript" src="mp3recorder.js"></script> 
    <script type="text/javascript"> 
    var audio_context; 

    function __log(e, data) { 
     log.innerHTML += "\n" + e + " " + (data || ''); 
    } 

    $(function() { 

     try { 
    // webkit shim 
    window.AudioContext = window.AudioContext || window.webkitAudioContext; 
    navigator.getUserMedia = (navigator.getUserMedia || 
        navigator.webkitGetUserMedia || 
        navigator.mozGetUserMedia || 
        navigator.msGetUserMedia); 
    window.URL = window.URL || window.webkitURL; 

    var audio_context = new AudioContext; 
    __log('Audio context set up.'); 
    __log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!')); 
    } catch (e) { 
    alert('No web audio support in this browser!'); 
    } 

    $('.recorder .start').on('click', function() { 
    $this = $(this); 
    $recorder = $this.parent(); 

    navigator.getUserMedia({audio: true}, function(stream) { 
     var recorderObject = new MP3Recorder(audio_context, stream, { statusContainer: $recorder.find('.status'), statusMethod: 'replace' }); 
     $recorder.data('recorderObject', recorderObject); 

     recorderObject.start(); 
    }, function(e) { }); 
    }); 

    $('.recorder .stop').on('click', function() { 
    $this = $(this); 
    $recorder = $this.parent(); 

    recorderObject = $recorder.data('recorderObject'); 
    recorderObject.stop(); 

    recorderObject.exportWAV(function(base64_wav_data) { 
     var url = 'data:audio/wav;base64,' + base64_wav_data; 
     var au = document.createElement('audio'); 

     document.getElementById("playerContainer").innerHTML = ""; 
     //console.log(url) 

     var duc = document.getElementById("dataUrlcontainer"); 
     duc.innerHTML = url; 

     au.controls = true; 
     au.src = url; 
     //$recorder.append(au); 
     $('#playerContainer').append(au); 

     recorderObject.logStatus(''); 
    }); 

    }); 

    }); 
    </script> 


<script> 
    function upload(){ 

    var dataURL = document.getElementById("dataUrlcontainer").innerHTML; 

     $.ajax({ 
     type: "POST", 
     url: "uploadWav.php", 
     data: { 
      wavBase64: dataURL 
     } 
    }).done(function(o) { 
     console.log('saved'); 

     }); 

    }  
    </script> 


<div class="recorder"> 
    Recorder 1 
    <input type="button" class="start" value="Record" /> 
    <input type="button" class="stop" value="Stop" /> 
    <pre class="status"></pre> 
</div> 

<div><button onclick="upload()">Upload</button></div> 

<div id="playerContainer"></div> 

<div id="dataUrlcontainer" hidden></div> 

<pre id="log"></pre> 

</body> 
</html> 

하고 "uploadWav.php"파일 :

<?php 
// requires php5 
define('UPLOAD_DIR', 'uploads/'); 
$img = $_POST['wavBase64']; 
$img = str_replace('data:audio/wav;base64,', '', $img); 
$img = str_replace(' ', '+', $img); 
$data = base64_decode($img); 
$file = UPLOAD_DIR . uniqid() . '.wav'; 
$success = file_put_contents($file, $data); 
print $success ? $file : 'Unable to save the file.'; 
?> 
+0

죽은 GitHub의 링크를 여기에 최종 HTML과 PHP는 나를 위해 일한입니다. – Ael

0
//**Server Side Code** 
package myPack; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 

import javax.servlet.ServletException; 
import javax.servlet.annotation.MultipartConfig; 
import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.apache.commons.codec.binary.Base64; 

@WebServlet("/MyServlet") 
@MultipartConfig 
public class MyServlet extends HttpServlet { 
    private static final long serialVersionUID = 1L; 

    public MyServlet() { 
     super(); 
    } 

    protected void doGet(HttpServletRequest request, 
      HttpServletResponse response) throws ServletException, IOException { 
    } 

    protected void doPost(HttpServletRequest request, 
      HttpServletResponse response) throws ServletException, IOException { 
     try { 
      String name = request.getParameter("fname"); 
      String url = request.getParameter("myUrl"); 
      url = url.replace("data:audio/wav;base64,", ""); 
      url = url.replace(" ", "+"); 
      byte[] bytes = url.getBytes(); 
      byte[] valueDecoded = Base64.decodeBase64(bytes); 
      FileOutputStream os = new FileOutputStream(new File("D://" + name 
        + ".wav")); 
      os.write(valueDecoded); 
      os.close(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 
} 

**Client Side Code** 


<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html; charset=utf-8"> 
<title>MP3 Recorder test</title> 
</head> 
<body id="index" onload=""> 

    <script type="text/javascript" src="js/jquery.min.js"></script> 
    <script type="text/javascript" src="js/recorder.js"></script> 
    <script type="text/javascript"> 
    var audio_context; 

    function __log(e, data) { 
     log.innerHTML += "\n" + e + " " + (data || ''); 
    } 

    $(function() { 

     try { 
     // webkit shim 
     window.AudioContext = window.AudioContext || window.webkitAudioContext; 
     navigator.getUserMedia = (navigator.getUserMedia || 
         navigator.webkitGetUserMedia || 
         navigator.mozGetUserMedia || 
         navigator.msGetUserMedia); 
     window.URL = window.URL || window.webkitURL; 

     var audio_context = new AudioContext; 
     __log('Audio context set up.'); 
     __log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!')); 
     } catch (e) { 
     alert('No web audio support in this browser!'); 
     } 

     $('.recorder .start').on('click', function() { 
     $this = $(this); 
     $recorder = $this.parent(); 

     navigator.getUserMedia({audio: true}, function(stream) { 
      var recorderObject = new MP3Recorder(audio_context, stream, { statusContainer: $recorder.find('.status'), statusMethod: 'replace' }); 
      $recorder.data('recorderObject', recorderObject); 

      recorderObject.start(); 
     }, function(e) { }); 
     }); 

     $('.recorder .stop').on('click', function() { 
     $this = $(this); 
     $recorder = $this.parent(); 

     recorderObject = $recorder.data('recorderObject'); 
     recorderObject.stop(); 

     recorderObject.exportWAV(function(base64_wav_data) { 
      var url = 'data:audio/wav;base64,' + base64_wav_data; 
      var au = document.createElement('audio'); 
      document.getElementById("playerContainer").innerHTML = ""; 
      //console.log(url) 

      var duc = document.getElementById("dataUrlcontainer"); 
      duc.innerHTML = url; 

      au.controls = true; 
      au.src = url; 
      //$recorder.append(au); 
      $('#playerContainer').append(au); 

      var fd = new FormData(); 
      fd.append('fname', 'test.wav'); 
      fd.append('myUrl', duc.innerHTML); 
     $.ajax({ 
       type: "POST", 
       url: "/audioPart2/MyServlet", 
       data: fd, 
       processData: false, 
       contentType: false 
      }); 
      recorderObject.logStatus(''); 
     }); 

     }); 

    }); 
    </script> 

    <div class="recorder"> 
     Recorder 1 <input type="button" class="start" value="Record" /> <input 
      type="button" class="stop" value="Stop" /> 
     <div id="playerContainer"></div> 
     <div id="dataUrlcontainer" hidden></div> 
     <pre class="status"></pre> 
    </div> 

<!-- <div class="recorder"> --> 
<!--  Recorder 2 <input type="button" class="start" value="Record" /> <input --> 
<!--   type="button" class="stop" value="Stop" /> --> 
<!--  <pre class="status"></pre> --> 
<!-- </div> --> 

    <pre id="log"></pre> 
</body> 
</html> 

**// Required JS 
1)jquery.min.js 
2) recorder.js** 


**recorder.js is below** 
(function(window){ 

    var RECORDER_WORKER_PATH = 'js/recorderWorker.js'; 
    var ENCODER_WORKER_PATH = 'js/mp3Worker.js'; 


    var MP3Recorder = function(context, stream, cfg) { 
    var config  = cfg || { statusContainer: null, statusMethod: 'append' } 

    var bufferLen = 4096; 
    var recording = false; 

    this.source  = context.createMediaStreamSource(stream); 
    this.node  = (context.createScriptProcessor || context.createJavaScriptNode).call(context, bufferLen, 1, 1); 

    var recorderWorker = new Worker(RECORDER_WORKER_PATH); 
    var encoderWorker = new Worker(ENCODER_WORKER_PATH); 
    var exportCallback; 


    // initialize the Recorder Worker 
    recorderWorker.postMessage({ cmd: 'init', sampleRate: context.sampleRate }); 

    // the recording loop 
    this.node.onaudioprocess = function(e) { 
     if(!recording) return; 
     recorderWorker.postMessage({ cmd: 'record', buffer: e.inputBuffer.getChannelData(0) }); 
    } 


    this.start = function() { 
     recording = true; 
     this.logStatus('recording...'); 
    } 
    this.stop = function() { 
     recording = false; 
     this.logStatus('stopping...'); 
    } 
    this.destroy = function() { recorderWorker.postMessage({ cmd: 'destroy' }); } 

    this.logStatus = function(status) { 
     if(config.statusContainer) { 
     if(config.statusMethod == 'append') { 
      config.statusContainer.text(config.statusContainer.text + "\n" + status); 
     } else { 
      config.statusContainer.text(status); 
     } 
     } 
    } 

    this.exportBlob = function(cb) { 
     exportCallback = cb; 
     if (!exportCallback) throw new Error('Callback not set'); 
     recorderWorker.postMessage({ cmd: 'exportBlob' }); 
    } 

    this.exportWAV = function(cb) { 
     // export the blob from the worker 
     this.exportBlob(function(blob) { 
     var fileReader = new FileReader(); 

     // read the blob as array buffer and convert it 
     // to a base64 encoded WAV buffer 
     fileReader.addEventListener("loadend", function() { 
      var resultBuffer = new Uint8Array(this.result); 
      cb(encode64(resultBuffer)); 
     }); 
     fileReader.readAsArrayBuffer(blob); 
     }); 
    } 

    this.exportMP3 = function(cb) { 
     this.logStatus('converting...'); 

     // export the blob from the worker 
     this.exportBlob(function(blob) { 
     var fileReader = new FileReader(); 

     fileReader.addEventListener("loadend", function() { 
      var wavBuffer = new Uint8Array(this.result); 
      var wavData = parseWav(wavBuffer); 

      encoderWorker.addEventListener('message', function(e) { 
      if (e.data.cmd == 'data') { 
       cb(encode64(e.data.buffer)); 
      } 
      }); 

      encoderWorker.postMessage({ cmd: 'init', config: { mode: 3, channels: 1, samplerate: wavData.sampleRate, bitrate: wavData.bitsPerSample } }); 
      encoderWorker.postMessage({ cmd: 'encode', buf: Uint8ArrayToFloat32Array(wavData.samples) }); 
      encoderWorker.postMessage({ cmd: 'finish' }); 
     }); 

     fileReader.readAsArrayBuffer(blob); 
     }); 
    } 




    // event listener for return values of the recorderWorker 
    recorderWorker.addEventListener('message', function(e) { 
     switch(e.data.from) { 
     case 'exportBlob': 
      exportCallback(e.data.blob); 
      break; 
     }; 
    }); 


    // HELPER FUNCTIONS 

    function encode64(buffer) { 
     var binary = ''; 
     var bytes = new Uint8Array(buffer); 
     var len  = bytes.byteLength; 

     for(var i = 0; i < len; i++) { 
      binary += String.fromCharCode(bytes[i]); 
     } 
     return window.btoa(binary); 
    } 

    function parseWav(wav) { 
     function readInt(i, bytes) { 
      var ret = 0, shft = 0; 

      while(bytes) { 
       ret += wav[i] << shft; shft += 8; 
       i++; bytes--; 
      } 
      return ret; 
     } 
     if(readInt(20, 2) != 1) throw 'Invalid compression code, not PCM'; 
     if(readInt(22, 2) != 1) throw 'Invalid number of channels, not 1'; 

     return { sampleRate: readInt(24, 4), bitsPerSample: readInt(34, 2), samples: wav.subarray(44) }; 
    } 

    function Uint8ArrayToFloat32Array(u8a){ 
     var f32Buffer = new Float32Array(u8a.length); 
     for (var i = 0; i < u8a.length; i++) { 
      var value = u8a[i<<1] + (u8a[(i<<1)+1]<<8); 
      if (value >= 0x8000) value |= ~0x7FFF; 
      f32Buffer[i] = value/0x8000; 
     } 
     return f32Buffer; 
    } 


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

    window.MP3Recorder = MP3Recorder; 

})(window); 
+0

이 코드는 Java로 잘 작동합니다 ...... 테스트 됨 – user2164096