10┃音視頻直播系統之 WebRTC 中的數據統計和繪製統計圖形

一、數據統計

  • 在視頻直播中,還有一項比較重要,那就是數據監控

  • 比如開發人員需要知道收了多少包、發了多少包、丟了多少包,以及每路流的流量是多少,才能評估出目前用戶使用的音視頻產品的服務質量是好還是壞

  • 如果用戶的音視頻服務質量比較差時,尤其是網絡帶寬不足時,可以通過降低視頻分辨率、減少視頻幀率、關閉視頻等策略來調整用戶的網絡狀況

  • WebRTC 中的統計信息大體分為三種:inbound-rtpoutbound-rtpdata-channel

  • 另外如果你需要查看 WebRTC 的統計數據,可以在 Chrome瀏覽器下地址欄中輸入 chrome://webrtc-internals 即可看到所有的統計信息了

  • 當你點進其中一個通道中查看詳情,即可看到大概如下的圖形界面

  • 接受視頻軌信息圖中你可以實時看到總共收了多少數據包、多少位元組的數據,以及每秒鐘接收了多少包、多少位元組的數據等統計數據

  • 而在發送視頻軌信息圖中你可以實時看到WebRTC 發送的總位元組數、總包數、每秒鐘發送的位元組數和包數,以及重傳的包數和位元組數等信息

 

二、獲取統計數據

  • WebRTC 提供了一個非常強大的 API,即 getStats(),通過該 API 你就可以獲取上面講述的所有信息

  • getStats API 是 RTCPeerConnecton 對象的方法,用於獲取各種統計信息

  • 通過向 getStats 方法中設置參數或不設置參數來決定你要獲得多少統計數據或哪些統計數據

var pc = new RTCPeerConnection();

// 獲得速個連接的統計信息
pc.getStats().then( 
 	// 在一個連接中有很多 report
 	reports => {
 		// 遍歷每個 report
 		reports.forEach( report => {
 			// 將每個 report 的詳細信息打印出來
 			console.log(report);
 		});
 }).catch( err => {
		console.error(err);
 })
)

 

三、插件庫繪製圖形

  • 步驟一:需要引入第三方庫 graph.js

  • 步驟二:啟動一個定時器,每秒鐘繪製一次圖形

  • 步驟三:在定時器的回調函數中,讀取 RTCStats 統計信息,轉化為可量化參數,並將其傳給graph.js 進行繪製

  • 就可以得到上面的視頻軌信息圖了

// 引入第三方庫 graph.js
<script src="/js/graph.js"></script>

<script>
var pc = null;
// 定義繪製比特率圖形相關的變量
var bitrateGraph;
var bitrateSeries;
// 定義繪製發送包圖形相關的變理
var packetGraph;
var packetSeries;

pc = new RTCPeerConnection(null);

//bitrateSeries 用於繪製點
bitrateSeries = new TimelineDataSeries();

//bitrateGraph 用於將 bitrateSeries 繪製的點展示出來
bitrateGraph = new TimelineGraphView('bitrateGraph', 'bitrateCanvas');
bitrateGraph.updateEndDate(); // 繪製時間軸

// 與上面一樣,只不是用於繪製包相關的圖
packetSeries = new TimelineDataSeries();
packetGraph = new TimelineGraphView('packetGraph', 'packetCanvas');
packetGraph.updateEndDate();

// 每秒鐘獲取一次 Report,並更新圖形
window.setInterval(() => {
    if (!pc) { // 如果 pc 沒有創建直接返回
        return;
    }
    // 從 pc 中獲取發送者對象
    const sender = pc.getSenders()[0];
    if (!sender) {
        return;
    }
    sender.getStats().then(res => { // 獲取到所有的 Report
        res.forEach(report => { // 遍歷每個 Report
            let bytes;
            let packets;
            // 我們只對 outbound-rtp 型的 Report 做處理
            if (report.type === 'outbound-rtp') {
                if (report.isRemote) { // 只對本地的做處理
                    return;
                }
                const now = report.timestamp;
                bytes = report.bytesSent; // 獲取到發送的位元組
                packets = report.packetsSent; // 獲取到發送的包數
                // 因為計算的是每秒與上一秒的數據的對比,所以這裡要做個判斷
                // 如果是第一次就不進行繪製
                if (lastResult && lastResult.has(report.id)) {
                    // 計算這一秒與上一秒之間發送數據的差值
                    var mybytes = (bytes - lastResult.get(report.id).bytesSent);
                    // 計算走過的時間,因為定時器是秒級的,而時間戳是豪秒級的
                    var mytime = (now - lastResult.get(report.id).timestamp);
                    const bitrate = 8 * mybytes / mytime * 1000; // 將數據轉成比特位
                    // 繪製點
                    bitrateSeries.addPoint(now, bitrate);
                    // 將會制的數據顯示出來
                    bitrateGraph.setDataSeries([bitrateSeries]);
                    bitrateGraph.updateEndDate();// 更新時間
                    // 下面是與包相關的繪製
                    packetSeries.addPoint(now, packets -
                        lastResult.get(report.id).packetsSent);
                    packetGraph.setDataSeries([packetSeries]);
                    packetGraph.updateEndDate();
                }
            }
        });
        // 記錄上一次的報告
        lastResult = res;
    });
}, 1000); // 每秒鐘觸發一次  
</script>

 

四、Canvas繪製圖形

  • 分析源碼可知,上面的視頻軌信息圖都是通過 Canvas 進行繪製的

  • Canvas 可以繪製矩形、路徑、圓弧等基本幾何圖形,通過這些基本圖形的組合,可以繪製出其他更加複雜的圖形

  • 除了繪製各種圖形外,Canvas 還可以對圖形進行顏色填充和邊框塗色。而對圖形的操作,如旋轉、伸縮、位置變換等也是 Canvas 必備的功能

  • CanvasHTML5 標準中的一個新元素

  • Canvas 坐標系的原點在畫布的左上角,X 坐標從左向右增長,Y 坐標是從上到下增長

  • 你可以把它想像成一塊「畫布」,有了它你就可以在網頁上繪製圖像和動畫了

  • 對 2D 圖形渲染,使用了 CanvasRenderingContext2D 類,底層使用了 Google 開源的 Skia

  • 對 3D 圖形渲染,使用了 WebGLRenderingContext 類,底層使用的是 OpenGL,不過在 Windows 上使用的卻是 D3D

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>canvas 實戰</title>
</head>

<body>
    <canvas id="canvas" width="150" height="150">
        The browser doesn't support the canvas tag.
    </canvas>
</body>
<script>
    // 從 HTML 獲取到 Canvas
    let canvas = document.getElementById('canvas');

    // 得到 Canvas 的渲染上下文
    let ctx_2d = canvas.getContext('2d');

    // 設置顏色為紅色
    ctx_2d.fillStyle = "rgb(200,0,0)";

    // 設置矩型的大小
    ctx_2d.fillRect(10, 10, 55, 50);

    // 設置顏色為藍色,並且透明
    ctx_2d.fillStyle = "rgba(0, 0, 200, 0.5)";

    // 設置矩型大小
    ctx_2d.fillRect(30, 30, 55, 50);
</script>

</html>