H5音视频方面的总结
前言
最近因为公司的项目要求,接触到了前端H5视频直播和实时语音识别这块的内容,由于我们项目的人都是第一次接触,开发的过程中踩了不少的坑,好在最后加班加点的还是完成了任务,所以写下这篇博客总结一下这次开发过程中的一些不足和收获。
recorder.js
实时语音这块使用的是recorder.js.使用了navigator.mediaDevices.getUserMedia来调取设备的麦克风,当开始录音后,浏览器会不断的触发onaudioprocess,在这个函数中可以获取到音频数据,然后再对获取到的音频数据进行转码,最终转成ArrayBuffer格式的字节数组。
recorder.js最后生成的是一个mp3文件,可以直接在页面上播放,但项目中的需求是利用websocket将音频数据实时的传输给后台,后台调用讯飞接口再实时生成文字返回给前端页面。所以需要生成arraybuffer来传给后台,并且采样率和采样数位需要设置成:
config.sampleBits = 16 //config.sampleBits || 8 采样数位 8, 16
config.sampleRate = 16000 //采样率(1/6 44100)
这样讯飞才能准确的识别出来,不然识别出来的错误率会非常高。
讯飞不支持实时的英文语音识别,所有项目后面又调用了百度的接口进行英文语音的识别,这边比较坑的就是百度传arraybuffer过去是不行的,必须再转一手才行:
let array = Array.prototype.slice.call(new Uint8Array(arrayBuffer))
如果需要将音频ArrayBuffer转为base64格式发送给服务端的话,需要将流转换为可操作的Uint8Array,再用自带的方法window.btoa转为base64格式:
transformArrayBufferToBase64 (buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
for (var len = bytes.byteLength, i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
需要注意的几点:1、getUserMedia只支持在https环境中调用,如果不是https的话,在localhost环境下是没有问题的,但在http环境下谷歌浏览器会报环境不安全不让你调用麦克风,当时就是因为忽略了这一点,后面在部署https环境时耽误了一点时间。2、getUserMedia方法不支持IE浏览器,支持ios12以上的Safari,好像不支持UC内核的浏览器,也就是说不支持国内大部分的国产手机自带的浏览器,这点其实不太确定,不过我测试过华为手机自带手机确实是不支持的,三星手机自带的浏览器没有问题,微信网页浏览器也没有问题。在谷歌和火狐上的兼容性还是不错的。
项目开发过程中遇到的问题: 1、recorder.js是网上有人封装的一个比较简陋的音频的一个脚本,跟我们公司的需求还是有点不符合,所以我改了挺多的,特别是音频转码这块,我也没有接触过,而网上关于实时语音的资料也比较少,与后端一起联调了很久–音频的格式、音频的码率等问题,也算是自己的一个知识储备,还有就是前后端的沟通也很重要。2、https的问题,其实我在一开始是知道获取麦克风权限是需要在https环境下才可以的,但是我当时并没有太重视,在沟通的时候也只是稍微的提了一下,并没有强调,结果到最后部署的时候才发现在https环境下,所有的请求都必须是https,而公司的部署环境中又不支持多个端口,导致视频推流和拉流这块出了问题,在这里耗费了很多不必要的时间。
视频直播:Flv.js
视频直播前端采用的是哔哩哔哩的某位大神开源的Flv.js框架,一个实现了在 HTML5 视频中播放 FLV 格式视频的 JavaScript 库。它的工作原理是将 FLV 文件流转码复用成 ISO BMFF(MP4 碎片)片段,然后通过 Media Source Extensions 将 MP4 片段喂进浏览器。
flv.js 是使用 ECMAScript 6 编写的,然后通过 Babel Compiler 编译成 ECMAScript 5,使用 Browserify 打包。
功能:
FLV 容器,具有 H.264 + AAC 编解码器播放功能
多部分分段视频播放
HTTP FLV 低延迟实时流播放
FLV 通过 WebSocket 实时流播放
兼容 Chrome, FireFox, Safari 10, IE11 和 Edge
十分低开销,并且通过你的浏览器进行硬件加速
使用:
他的使用也非常简单:
let player = this.refs.myVieo
if (flvjs.isSupported()) {
var flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive: true,
url: FlvRequet,
hasVideo: true,
hasAudio: true
},{
enableWorker: true,
lazyLoadMaxDuration: 1*60,
enableStashBuffer: false,
fixAudioTimestampGap: false,
autoCleanupSourceBuffer: true,
})
flvPlayer.attachMediaElement(player)
flvPlayer.load() //
player
.play()
.then(() => {
})
.catch(err => {
console.error(err)
})
}
需要注意的地方: 1、flv.js只支持h264+aac的格式。2、flv.js不支持IE浏览器。3、chrom现在取消了视频自动播放的支持,如果你想要自动播放的话,必须得满足这几点中的任意一点:1)视频为静音播放 2)用户得先与页面有交互
项目遇到的问题: 1、关于自动播放这块,我们两个前端研究了很久,用了很多方法想要试图绕开谷歌的限制,百度谷歌的方法也用了很多,奈何谷歌的限制很严格,或者是我们才疏学浅,最终还是妥协为静音播放才行,如果有人能有办法绕开这个限制的话还希望能够提供。2、视频推流的格式这块我们和后端一起调试了很久,刚开始推流延迟达到了十秒,后面经过不断的改推流的命令,降低到了三秒左右,其实还不是很理想,最后发现是在摄像头采集视频推流那块出了问题,之前推流的帧数一直限制在十到二十帧,后面尝试把它提到三十帧,发现延迟竟然降到了一秒左右。。。到现在也不知道是什么原因,总之就当做经验吧。
参考文章(侵删):https://www.jianshu.com/p/8dda2be878b3