我正在尝试录制来自网站用户的音频并将音频保存到我的服务器。 到目前为止,我研究的许多帖子都引用了Matt Diamond的recorderjs。 我试图通过浏览器打开源代码来重新创建演示 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((,但是我真的不知道如何将这些示例连接到recorderjs。将Chrome中录制的WAV文件保存到服务器HTML5和getUserMedia - 录制音频并在一定时间后保存到Web服务器 记录器JS通过AJAX上传录制的blob
使用 XMLHttpRequest
将 wav 或 mp3 blob 发布到服务器很简单。
只需在可以访问 blob
元素的任何位置运行此代码:
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("audio_data",blob, "filename");
xhr.open("POST","upload.php",true);
xhr.send(fd);
我更喜欢XMLHttpRequest
而不是$.ajax()
,因为它不需要jQuery。
在服务器端,upload.php
非常简单:
$input = $_FILES['audio_data']['tmp_name']; //temporary name that PHP gave to the uploaded file
$output = $_FILES['audio_data']['name'].".wav"; //letting the client control the filename is a rather bad idea
//move the file from temp name to local folder using $output name
move_uploaded_file($input, $output)
来源: https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/现场演示:https://addpipe.com/simple-recorderjs-demo/
出了一个解决方案,但仍然欢迎其他与 recorderjs 相关的解决方案。 我在 https://github.com/icatcher-at/MP3RecorderJS 使用了MP3RecorderJS。 如果您将 html 的顶部从 src="js/jquery.min.js" 和 src="js/mp3recorder.js" 更改为它们在服务器中的任何位置,则演示 html 有效。 对我来说,它是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 = '记录员工人.js'; var ENCODER_WORKER_PATH = 'mp3Worker.js';
该程序设置为录制mp3和wav。 我想要wav,所以我对html文件做了一些调整。 在第 55 行,您会发现:
recorderObject.exportMP3(function(base64_mp3_data) {
var url = 'data:audio/mp3;base64,' + base64_mp3_data;
var au = document.createElement('audio');
我将其更改为:
recorderObject.exportWAV(function(base64_wav_data) {
var url = 'data:audio/wav;base64,' + base64_wav_data;
var au = document.createElement('audio');
每次录制时,演示都会附加一个新播放器。 为了防止这种情况,我删除(注释掉($recorder.append(au(;part,制作了一个新的div 来存储音频播放器,然后我每次在创建音频播放器之前清除该div。 为了上传到我的服务器,我使用了将图像上传到服务器时学到的技术 将画布图像保存到服务器 基本上,第 56 行中的"url"变量是我需要的,但无法弄清楚如何将其放入通用变量中以供另一个函数使用。 因此,我制作了一个隐藏的div,并将其内容等于"url"。 然后,我在一个名为"upload"的新函数中引用了该div。 然后我使用了一个名为"uploadWav.php"的php文件。 我仍然需要想办法激活和停用上传按钮,以防止用户在录制前上传空白文件,但这是另一个问题。这是对我有用的最终 html 和 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>
和"上传Wav.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.';
?>
//**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);