让前端飞超有趣的JSjavaScript学习

使用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 }));
});
上一篇下一篇

猜你喜欢

热点阅读