項目需求 Web端播放實時音頻流,折騰了兩天後問題得以解決。記錄下開發調試過程,友善後來者。
首次想到是利用Audio标簽,Audio标簽可以直接播放MP3格式,服務端将實時音頻流編碼成MP3格式
通過Http方式傳給Web端即可,前端代碼如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
</script>
</head>
<body>
<audio controls="controls" autoplay="autoplay">
<source src="http://127.0.0.1:12345/cgmedia/28181/[email protected]:5060&format=mp3&transporttype=udp&transportport=22000" type="audio/mpeg">
</audio>
</body>
</html>
通過Audio标簽 實作音頻流播放 代碼比較簡單,但有緩沖過大問題,粗略測試了下延時 20-30s左右,這顯然
不滿足實時播放實時播放需求。開始調試時懷疑是背景服務端傳輸過來的流有問題,于是将流儲存成MP3檔案進行
測試 ,結果正常未出現緩沖一段時間後開始播放。分析Audio标簽發出的Http封包,發現Http請求Head中有Range字段,
嘗試做了相應Response,結果未發生變化。猜想Audio标簽可能隻适合于MP3檔案(一次性将Audio資料加載完成再處
理)。如這個猜測不對,歡迎指正(本人主要從事背景媒體服務開發,前端經驗很少)。
Audio标簽的方式不行,想到利用Web Audio API是實作,基本的思路是:通過WebSocket 接收服務端推送過來的音
頻流(MP3格式)調用decodeAudioData進行解碼,最後将解碼資料推送到AudioContext最後一個Node,代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function WebSocketTest()
{
var wsUrl = "ws://127.0.0.1:12345/cgmedia/28181/[email protected]:5060&format=mp3&transporttype=udp&transportport=22000";
ws = new WebSocket(wsUrl);
ws.binaryType = 'arraybuffer'; //arraybuffer
ws.onmessage = function(msg) {
var data = msg.data;
var datalen = msg.data.size;
var reader = new FileReader();
var audioContext = new AudioContext({
sampleRate:8000,
});
reader.onload = function(evt)
{
if(evt.target.readyState == FileReader.DONE)
{
audioContext.decodeAudioData(data, function(buffer) {
console.log("decode success");
var bufferSource = audioContext.createBufferSource();
bufferSource.connect(audioContext.destination);
bufferSource.buffer = buffer;
bufferSource.start(0);
}, function(e) {
console.log("decode failed" + e);
});
}
}
reader.readAsArrayBuffer(new Blob([data]));
};
ws.onopen = function(evt) {
if(self.verbose) {
console.log("Connection open......");
}
ws.onclose = function(evt) {
console.log("Connection closed......");
}
}
</script>
</head>
<body>
<button onclick="WebSocketTest()">發送請求</button>
</body>
</html>
采用Audio Web API方式播放實時流會出現卡頓現象,以上方法一次性解碼的資料可以連續播放,每次解碼後要重新
建立BufferSource,顯而易見這種播放模式播放實時流效率很低,查閱了Audio Web API 文檔 播放網絡流似乎要利用
基于AudioWorkletProcessor的自定義節點,文檔也給了一個簡單的例子,那個例子不符合我們的使用場景。沒有
更多的時間研究Audio Web API,這種方案隻好作罷,單看Audio Web API接口有些無語, 這有可能跟Web端處理能力有關。
可行的方法
條條大路通羅馬,畢竟項目不是科研,可以實作需求就行。一種可行的方法是服務端輸出Rtmp音頻流 通過video.js播放
實際應該是用了flash。項目開始已經想到了這個方案可行隻是覺得有些繞(需要将音頻流封裝後推送到rtmp server)。
另外一個可行的方案就是利用H5 MSE實作,這個方案也有開源的庫可以用,例如flv.js 這需要 服務端将音頻打包成flv格式
推送給Web前端,Web端接收到音頻資料後調用flv.js進行播放。video.js 及flv.js github都有下載下傳 代碼就不貼出來了。
如需交流可加QQ群766718184,1038388075 或者QQ3501870
視訊下載下傳位址:http://www.chungen90.com/?news_33/
Demo下載下傳位址: http://www.chungen90.com/?news_34