javascript Web 浏览器中的高质量音频录制
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16240459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
High Quality Audio Recording in Web Browser
提问by thatidiotguy
One line version:
一行版本:
What open source software (WAMI-Recorder)/web browser (via getUserMedia) will give me the best quality audio recordings?
什么开源软件(WAMI-Recorder)/网络浏览器(通过 getUserMedia)可以给我最好的录音质量?
High quality would be defined as (44.1 or 48 sample rate) and 16 bit sample size.
高质量将定义为(44.1 或 48 采样率)和 16 位样本大小。
More Information:
更多信息:
So currently my solution is WAMI-Recorder, but I am wondering if the HTML5 specification has matured to a point in browser such that I can record without Flash and get equal or higher quality audio recordings. Currently it looks like WAMI maxes out at 22050.
所以目前我的解决方案是 WAMI-Recorder,但我想知道 HTML5 规范是否已经成熟到浏览器中的某个点,以便我可以在没有 Flash 的情况下进行录制并获得同等或更高质量的录音。目前看起来 WAMI 的最大值是 22050。
I do not need cross browser support as this is for internal business use.
我不需要跨浏览器支持,因为这是供内部业务使用的。
A non-Flash solution would also be preferred.
非闪存解决方案也将是首选。
回答by Chamika Sandamal
I found something here. hope it will help you to record audio
我在这里找到了一些东西。希望它能帮助你录制音频
<html>
<body>
<audio controls autoplay></audio>
<script type="text/javascript" src="recorder.js"> </script>
<input onclick="startRecording()" type="button" value="start recording" />
<input onclick="stopRecording()" type="button" value="stop recording and play" />
<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>
download the sample https://github.com/rokgregoric/html5record/archive/master.zip
下载示例https://github.com/rokgregoric/html5record/archive/master.zip
回答by Ankit Aranya
Save this files and use
保存此文件并使用
//HTML FILE
//HTML文件
<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>
//JS FILES RECORDER.JS
(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.createJavaScriptNode(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;
}
回答by Paulo Fidalgo
Check this tutorial on how to capture audio and video using HTML5.
查看本教程,了解如何使用 HTML5 捕获音频和视频。
http://www.html5rocks.com/en/tutorials/getusermedia/intro/
http://www.html5rocks.com/en/tutorials/getusermedia/intro/
I don't see any reference about the sample rate or the sample size in the API's, but I would assume that will be possible.
我在 API 中没有看到任何关于采样率或样本大小的参考,但我认为这是可能的。
Your major problem could be the implementation status by different browser vendors.
您的主要问题可能是不同浏览器供应商的实施状态。
回答by Four_lo
The WebRTC project is the only available solution for high quality audio that I know of. There is currently a stable version for chrome. I believe firefox is still in the beta stage. As WebRTC matures I am sure all browsers will provide support for this.
WebRTC 项目是我所知道的唯一可用的高质量音频解决方案。目前有一个稳定的 chrome 版本。我相信 firefox 仍处于测试阶段。随着 WebRTC 的成熟,我相信所有浏览器都会为此提供支持。
回答by A STEFANI
If you use Chrome Web Browser, and as you ask for High Quality Audio Recording, you probably be better to build a native client module, you may take a look here(chrome developper native client dev guide):
如果您使用 Chrome 网络浏览器,并且当您要求高质量音频录制时,您可能最好构建一个本地客户端模块,您可以查看这里(chrome developer native client dev guide):
Selecting a sample frame count for an audio stream involves a tradeoff between latency and CPU usage. If you want your module to have short audio latency so that it can rapidly change what's playing in the audio stream, you should request a small sample frame count.
为音频流选择样本帧计数涉及延迟和 CPU 使用率之间的权衡。如果您希望您的模块具有较短的音频延迟,以便它可以快速更改音频流中正在播放的内容,您应该请求一个小的样本帧数。
[...]
[...]
After the module obtains a sample frame count, it can create an audio configuration resource. Currently the Pepper audio API supports audio streams with the configuration settings shown above
模块获得样本帧数后,可以创建音频配置资源。目前,胡椒音频API支持与所示的配置设置的音频流以上
And here you will find audio configuration which fit your requirements
在这里您会找到符合您要求的音频配置
The Pepper audio API currently lets Native Client modules play audio streams with the following configurations:
sample rate: 44,100 Hz or 48,000 Hz
bit depth: 16
channels: 2 (stereo)
Pepper 音频 API 目前允许 Native Client 模块播放具有以下配置的音频流:
采样率:44,100 Hz 或 48,000 Hz
位深度:16
通道:2(立体声)
This official linkcould be also helpful.
这个官方链接也可能有帮助。
Regards
问候