天天看點

Html5 播放實時音頻流

     項目需求 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

繼續閱讀