自从Recorder H5 GitHub开源库优化后,对边录边转码成小语音片断文件实时上传服务器这种操做支持很是良好,所以之前不太好支持的H5语音通话已经有了更好的突破空间。所以花了两晚时间打造了一个H5语音通话聊天的demo。欢迎在线把玩:https://xiangyuecn.github.io/Recorder/javascript
局域网H5版对讲机😂
github demo中考虑到减小对服务器的依赖,所以采用了WebRTC P2P传输功能,无需任何服务器支持便可实现局域网内的两个设备之间互相链接,链接代码也算简单。有服务器支持可能就要逆天了,不过代码也会更复杂。前端
若是正式使用,可能不太会考虑使用WebRTC,用WebSocket经过服务器进行转发多是最佳的选择。java
WebRTC局域网P2P链接要点(实际代码其实差很少,只不过多作了点兼容):git
/******Peer A(本机)******/ var peerA=new RTCPeerConnection(null,null) //开启会话,等待远程链接 peerA.createOffer().then(function(offer){ peerA.setLocalDescription(offer); peerAOffer=offer; }); var peerAICEList=[......] //经过peerA.onicecandidate监听得到全部的ICE链接信息候选项,若是有多个网络适配器,就会有多个候选 //建立链接通道对象,A端经过这个来进行数据发送 var peerAChannel=peerA.createDataChannel("RTC Test"); /******Peer B(远程)******/ var peerB=new RTCPeerConnection(null,null) //链接到Peer A peerB.setRemoteDescription(peerAOffer); //开启应答会话,等待Peer A确认链接 peerB.createAnswer().then(function(answer){ peerB.setLocalDescription(answer); peerBAnswer=answer; }); //把Peer A的链接点都添加进去 peerB.addIceCandidate(......peerAICEList) var peerBICEList=[......] //经过peerB.onicecandidate监听得到全部的ICE链接信息候选项,若是有多个网络适配器,就会有多个候选 var peerBChannel=... //经过peerB.ondatachannel获得链接通道对象,B端经过这个来进行数据发送 /*******最终完成链接********/ //链接到Peer B peerA.setRemoteDescription(peerBAnswer); //把Peer B的链接点都添加进去 peerA.addIceCandidate(......peerBICEList) /* peerA peerB分别等待peerA/BChannel.onopen回调即完成P2P链接 ,而后经过监听peerA/BChannel.onmessage得到对方发送的信息 ,经过peerA/BChannel.send(data) 发送数据。 */
因为是在个人Recorder库中新加的demo,所以音频采集和编码都是现成的,Recorder库有好的兼容性和稳定性,所以节省了最大头的工做量。github
编码最佳使用MP3格式,由于此格式已优化了实时编码性能,可作到边录边转码,16kbps 16khz的状况下可作到2kb每秒的文件大小,音质还能够,实时传输时为3kb每秒,15分钟大概3M的流量。web
用wav格式也能够,不过此格式编码出来的数据量太大,16位 16khz接近50kb每秒的实时传输数据,15分钟要37M多流量。其余格式因为暂未对实时编码进行优化,使用中会致使明显卡顿。浏览器
降噪、静音检测等高级功能是没有的,毕竟是非专业人员😂 要求高点能够,但不要超出范围太多啦。服务器
接收到一个音频片断后,本应该是当即播放的,但因为编码、网络传输致使的延迟,可能上个片断还未播放完(甚至未开始播放),所以须要缓冲处理。微信
由于存在缓冲,就须要进行实时同步处理,若是缓冲内积压了过多的音频片断,会致使语音播放滞后太多,所以须要适当进行对数据进行丢弃,实测发现网络正常、设备性能靠谱的状况下基本没有丢弃的数据。网络
而后就是播放了,本应是播完一个就播下一个,测试发现这是不靠谱的。由于结束一个片断后再开始播放下一个发出声音,这个过程会中断比较长时间,明显感受得出来中间存在短暂停顿。所以必须在片断未播完时准备好下一个片断的播放,而且提早开始播放,达到抹掉中间的停顿。
我写了两个播放方式:
最开始用一个Audio停顿感太明显,所以用两个Audio轮换抹掉中间的停顿,但发现不一样格式Auido播放差别巨大,播放wav很是流畅,但播放mp3仍是存在停顿(后面用解码的发现是获得的PCM时长变长了,致使事件触发会出现偏差,为何会变长?怪异)。
所以后面写了一个解码而后再播放,mp3此次终于能正常连续播放了,wav格式和双Audio的播放差别不大。实时解码里面也用到了双Audio中的技巧,其实也是用到了两个BufferSource进行相似的轮换操做,以抹掉两个片断间的停顿。
不过最终播放效果仍是不够好,音质变差了点,而且多了点噪音。若是有现成的播放代码拿过来用就就行了。
完。