自從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進行相似的輪換操做,以抹掉兩個片斷間的停頓。
不過最終播放效果仍是不夠好,音質變差了點,而且多了點噪音。若是有現成的播放代碼拿過來用就就行了。
完。