Created
January 5, 2017 03:33
-
-
Save jerrybendy/4edb552f8414dd86e3989e9315a81adc to your computer and use it in GitHub Desktop.
一个使用 HTML5 录音的例子(网上看到的,收藏下)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title></title> | |
</head> | |
<body> | |
<div> | |
<audio controls autoplay></audio> | |
<input onclick="startRecording()" type="button" value="录音" /> | |
<input onclick="stopRecording()" type="button" value="停止" /> | |
<input onclick="playRecording()" type="button" value="播放" /> | |
<input onclick="uploadAudio()" type="button" value="提交" /> | |
</div> | |
<script type="text/javascript" src="HZRecorder.js"></script> | |
<script> | |
var recorder; | |
var audio = document.querySelector('audio'); | |
function startRecording() { | |
HZRecorder.get(function (rec) { | |
recorder = rec; | |
recorder.start(); | |
}); | |
} | |
function stopRecording() { | |
recorder.stop(); | |
} | |
function playRecording() { | |
recorder.play(audio); | |
} | |
function uploadAudio() { | |
recorder.upload("Handler1.ashx", function (state, e) { | |
switch (state) { | |
case 'uploading': | |
//var percentComplete = Math.round(e.loaded * 100 / e.total) + '%'; | |
break; | |
case 'ok': | |
//alert(e.target.responseText); | |
alert("上传成功"); | |
break; | |
case 'error': | |
alert("上传失败"); | |
break; | |
case 'cancel': | |
alert("上传被取消"); | |
break; | |
} | |
}); | |
} | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function (window) { | |
//兼容 | |
window.URL = window.URL || window.webkitURL; | |
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; | |
var HZRecorder = function (stream, config) { | |
config = config || {}; | |
config.sampleBits = config.sampleBits || 8; //采样数位 8, 16 | |
config.sampleRate = config.sampleRate || (44100 / 6); //采样率(1/6 44100) | |
var context = new (window.webkitAudioContext || window.AudioContext)(); | |
var audioInput = context.createMediaStreamSource(stream); | |
var createScript = context.createScriptProcessor || context.createJavaScriptNode; | |
var recorder = createScript.apply(context, [4096, 1, 1]); | |
var audioData = { | |
size: 0 //录音文件长度 | |
, buffer: [] //录音缓存 | |
, inputSampleRate: context.sampleRate //输入采样率 | |
, inputSampleBits: 16 //输入采样数位 8, 16 | |
, outputSampleRate: config.sampleRate //输出采样率 | |
, oututSampleBits: config.sampleBits //输出采样数位 8, 16 | |
, input: function (data) { | |
this.buffer.push(new Float32Array(data)); | |
this.size += data.length; | |
} | |
, compress: function () { //合并压缩 | |
//合并 | |
var data = new Float32Array(this.size); | |
var offset = 0; | |
for (var i = 0; i < this.buffer.length; i++) { | |
data.set(this.buffer[i], offset); | |
offset += this.buffer[i].length; | |
} | |
//压缩 | |
var compression = parseInt(this.inputSampleRate / this.outputSampleRate); | |
var length = data.length / compression; | |
var result = new Float32Array(length); | |
var index = 0, j = 0; | |
while (index < length) { | |
result[index] = data[j]; | |
j += compression; | |
index++; | |
} | |
return result; | |
} | |
, encodeWAV: function () { | |
var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate); | |
var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits); | |
var bytes = this.compress(); | |
var dataLength = bytes.length * (sampleBits / 8); | |
var buffer = new ArrayBuffer(44 + dataLength); | |
var data = new DataView(buffer); | |
var channelCount = 1;//单声道 | |
var offset = 0; | |
var writeString = function (str) { | |
for (var i = 0; i < str.length; i++) { | |
data.setUint8(offset + i, str.charCodeAt(i)); | |
} | |
} | |
// 资源交换文件标识符 | |
writeString('RIFF'); offset += 4; | |
// 下个地址开始到文件尾总字节数,即文件大小-8 | |
data.setUint32(offset, 36 + dataLength, true); offset += 4; | |
// WAV文件标志 | |
writeString('WAVE'); offset += 4; | |
// 波形格式标志 | |
writeString('fmt '); offset += 4; | |
// 过滤字节,一般为 0x10 = 16 | |
data.setUint32(offset, 16, true); offset += 4; | |
// 格式类别 (PCM形式采样数据) | |
data.setUint16(offset, 1, true); offset += 2; | |
// 通道数 | |
data.setUint16(offset, channelCount, true); offset += 2; | |
// 采样率,每秒样本数,表示每个通道的播放速度 | |
data.setUint32(offset, sampleRate, true); offset += 4; | |
// 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8 | |
data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true); offset += 4; | |
// 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8 | |
data.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2; | |
// 每样本数据位数 | |
data.setUint16(offset, sampleBits, true); offset += 2; | |
// 数据标识符 | |
writeString('data'); offset += 4; | |
// 采样数据总数,即数据总大小-44 | |
data.setUint32(offset, dataLength, true); offset += 4; | |
// 写入采样数据 | |
if (sampleBits === 8) { | |
for (var i = 0; i < bytes.length; i++, offset++) { | |
var s = Math.max(-1, Math.min(1, bytes[i])); | |
var val = s < 0 ? s * 0x8000 : s * 0x7FFF; | |
val = parseInt(255 / (65535 / (val + 32768))); | |
data.setInt8(offset, val, true); | |
} | |
} else { | |
for (var i = 0; i < bytes.length; i++, offset += 2) { | |
var s = Math.max(-1, Math.min(1, bytes[i])); | |
data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); | |
} | |
} | |
return new Blob([data], { type: 'audio/wav' }); | |
} | |
}; | |
//开始录音 | |
this.start = function () { | |
audioInput.connect(recorder); | |
recorder.connect(context.destination); | |
} | |
//停止 | |
this.stop = function () { | |
recorder.disconnect(); | |
} | |
//获取音频文件 | |
this.getBlob = function () { | |
this.stop(); | |
return audioData.encodeWAV(); | |
} | |
//回放 | |
this.play = function (audio) { | |
audio.src = window.URL.createObjectURL(this.getBlob()); | |
} | |
//上传 | |
this.upload = function (url, callback) { | |
var fd = new FormData(); | |
fd.append("audioData", this.getBlob()); | |
var xhr = new XMLHttpRequest(); | |
if (callback) { | |
xhr.upload.addEventListener("progress", function (e) { | |
callback('uploading', e); | |
}, false); | |
xhr.addEventListener("load", function (e) { | |
callback('ok', e); | |
}, false); | |
xhr.addEventListener("error", function (e) { | |
callback('error', e); | |
}, false); | |
xhr.addEventListener("abort", function (e) { | |
callback('cancel', e); | |
}, false); | |
} | |
xhr.open("POST", url); | |
xhr.send(fd); | |
} | |
//音频采集 | |
recorder.onaudioprocess = function (e) { | |
audioData.input(e.inputBuffer.getChannelData(0)); | |
//record(e.inputBuffer.getChannelData(0)); | |
} | |
}; | |
//抛出异常 | |
HZRecorder.throwError = function (message) { | |
alert(message); | |
throw new function () { this.toString = function () { return message; } } | |
} | |
//是否支持录音 | |
HZRecorder.canRecording = (navigator.getUserMedia != null); | |
//获取录音机 | |
HZRecorder.get = function (callback, config) { | |
if (callback) { | |
if (navigator.getUserMedia) { | |
navigator.getUserMedia( | |
{ audio: true } //只启用音频 | |
, function (stream) { | |
var rec = new HZRecorder(stream, config); | |
callback(rec); | |
} | |
, function (error) { | |
switch (error.code || error.name) { | |
case 'PERMISSION_DENIED': | |
case 'PermissionDeniedError': | |
HZRecorder.throwError('用户拒绝提供信息。'); | |
break; | |
case 'NOT_SUPPORTED_ERROR': | |
case 'NotSupportedError': | |
HZRecorder.throwError('浏览器不支持硬件设备。'); | |
break; | |
case 'MANDATORY_UNSATISFIED_ERROR': | |
case 'MandatoryUnsatisfiedError': | |
HZRecorder.throwError('无法发现指定的硬件设备。'); | |
break; | |
default: | |
HZRecorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name)); | |
break; | |
} | |
}); | |
} else { | |
HZRecorder.throwErr('当前浏览器不支持录音功能。'); return; | |
} | |
} | |
} | |
window.HZRecorder = HZRecorder; | |
})(window); |
你好 我发现你的代码可以完成录音,音频文件的格式也符合要求,但是音调会变低,我希望采样样本与原声是一样的,请问有什么解决方案吗?谢谢
你好,你的代码可以在手机上运行吗
我也发现录音的音调会变低,请问是怎么解决的?
音调变低是因为这份代码的采样算法不对,不要采样,直接用44100返回,然后用其他采样算法可以解决问题
`
import javax.sound.sampled.*;
import java.io.File;
public static void changeBitrate(File source, File output){
try{
AudioFormat format=new AudioFormat(16000,16,1,true,true);
AudioInputStream in=AudioSystem.getAudioInputStream(source);
AudioInputStream convert=AudioSystem.getAudioInputStream(format,in);
AudioSystem.write(convert,AudioFileFormat.Type.WAVE,output);
}catch (Exception e){
e.printStackTrace();
}
}`
返回44100 然后通过java转16khz
点击上传,显示成功,但没有生成文件啊
因为同源政策所以无法生成文件
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
fd.append("audioData", this.getBlob(), 'audio.wav'); 多加一个参数可以解决上传的文件,php端获取不到扩展名的问题