10┃音視訊直播系統之 WebRTC 中的資料統計和繪製統計圖形

autofelix發表於2022-05-19

一、資料統計

  • 在視訊直播中,還有一項比較重要,那就是資料監控

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

  • 如果使用者的音視訊服務質量比較差時,尤其是網路頻寬不足時,可以通過降低視訊解析度、減少視訊幀率、關閉視訊等策略來調整使用者的網路狀況

  • 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>

 

 

相關文章