使用amr.js播放"amr"格式的录音文件
2019-07-08 本文已影响3人
Nanayai
image
问题所在:做项目的时候,要求能在平台端播放app上传而来的录音文件,而安卓端目前只能录制"amr"、"3gp"格式,完美的避开了html支持的三种音频格式。
我们选择了每分钟约100kb的“amr”格式来完成录制和上传功能,而在html5中:
video 元素支持三种视频格式:
格式 | IE | Firefox | Opera | Chrome | Safari |
---|---|---|---|---|---|
Ogg | No | 3.5+ | 10.5+ | 5.0+ | No |
MPEG 4 | 9.0+ | No | No | 5.0+ | 3.0+ |
WebM | No | 4.0+ | 10.6+ | 6.0+ | No |
audio 元素支持三种音频格式:
格式 | IE 9 | Firefox 3.5 | Opera 10.5 | Chrome 3.0 | Safari 3.0 |
---|---|---|---|---|---|
Ogg Vorbis | √ | √ | √ | ||
MP3 | √ | √ | √ | ||
Wav | √ | √ | √ |
解决办法:我在github上找到了这个库 opencore-amr-js ,这个库使用amr.js对“amr”文件进行转码:AMR.decode(amr)
,再使用AudioContext
对象进行播放即可。各位可去github上看具体实现和作者的demo,下面是我整理的得小demo,实现了播放功能和兼容性处理,除了不支持AudioContext
的IE之外,其他桌面端浏览器基本都可以正常运行,移动端兼容性上我没有测试,据说ios端行不通,安卓端可以:
<!DOCTYPE html>
<html>
<head>
<title>AMR decode/encode tests</title>
<meta charset="utf-8">
<script src="amrnb.js" defer></script>
</head>
<body>
<button id="but">Play</button>
<script>
but.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.open('GET', "test.amr");
xhr.responseType = 'blob';
xhr.onload = function() {
readBlob(this.response, function(data) {
playAmrArray(data);
});
};
xhr.onerror = function() {
alert('Failed to fetch ' + url);
};
xhr.send();
}
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
function readBlob(blob, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var data = new Uint8Array(e.target.result);
callback(data);
};
reader.readAsArrayBuffer(blob);
}
function playAmrArray(array) {
var samples = AMR.decode(array);
if(!samples) {
alert('Failed to decode!');
return;
}
playPcm(samples);
}
function playPcm(samples) {
try {
var ctx = new AudioContext();
} catch(e) {
alert('您的浏览器暂不支持播放录音');
return;
}
var src = ctx.createBufferSource();
var buffer = ctx.createBuffer(1, samples.length, 8000);
if(buffer.copyToChannel) {
buffer.copyToChannel(samples, 0, 0);
} else {
var channelBuffer = buffer.getChannelData(0);
channelBuffer.set(samples);
}
src.buffer = buffer;
src.connect(ctx.destination);
src.start();
}
</script>
</body>
</html>
AudioContext相关以及兼容性请参考: AudioContext
更新:以上只是实现了简单的播放,如果想添加其他功能的话,可以使用wavesurfer-js 来实现炫酷的效果:
部分代码(ps:我们测试的效果蛮丑的,希望你可以弄得比上面这个还要漂亮):
var wavesurfer = Object.create(WaveSurfer);
// Init & load audio file
document.addEventListener("DOMContentLoaded", function() {
var options = {
container: document.querySelector("#waveform"),
waveColor: "violet",
progressColor: "purple",
loaderColor: "purple",
cursorColor: "navy"
};
if (location.search.match("scroll")) {
options.minPxPerSec = 100;
options.scrollParent = true;
}
// Init
wavesurfer.init(options);
// Load audio from URL
//wavesurfer.load("example/media/demo.wav");
// Regions
// if (wavesurfer.enableDragSelection) {
// wavesurfer.enableDragSelection({
// color: "rgba(0, 255, 0, 0.1)"
// });
// }
});
// Play at once when ready
// Won't work on iOS until you touch the page
wavesurfer.on("ready", function() {
wavesurfer.play();
});
// Report errors
wavesurfer.on("error", function(err) {
console.error(err);
});
// Do something when the clip is over
wavesurfer.on("finish", function() {
console.log("播放完成");
});
function readBlob(blob, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var data = new Uint8Array(e.target.result);
callback(data);
};
reader.readAsArrayBuffer(blob);
}
function playAmrArray(array) {
var samples = AMR.decode(array);
if (!samples) {
alert("解码失败!");
return;
}
wavesurfer.loadAMRDecodedBuffer(samples);
}
function playAmrContent(url) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.onload = function() {
readBlob(this.response, function(data) {
playAmrArray(data);
});
};
xhr.onerror = function() {
alert("加载资源失败");
};
xhr.send();
}
/* Progress bar */
document.addEventListener("DOMContentLoaded", function() {
var progressDiv = document.querySelector("#progress-bar");
var progressBar = progressDiv.querySelector(".progress-bar");
var showProgress = function(percent) {
progressDiv.style.display = "block";
progressBar.style.width = percent + "%";
};
var hideProgress = function() {
progressDiv.style.display = "none";
};
wavesurfer.on("loading", showProgress);
wavesurfer.on("ready", hideProgress);
wavesurfer.on("destroy", hideProgress);
wavesurfer.on("error", hideProgress);
var fileId = getQueryStringByName("file");
playAmrContent("/file/download?param=" + JSON.stringify({ id: fileId }));
});