【WebRTC】使用getStats()获取WebRTC实时统计信息

一、getStats()功能

返回丰富的WebRTC运行时的状态信息

主要返回以下内容:

  • 发送端采集统计

对应于媒体数据的产生,包括帧率、帧大小、媒体数据源的时钟频率和编码器名称等等

  • 发送端RTP统计

对应于媒体数据的发送,包括发送数据包数,发送字节数和往返时间RTT等等

  • 接收端RTP统计

对应于媒体数据的接收,包括接收数据包数、接收字节数、丢弃数据包数、丢失数据包数和网络抖动jitter

  • 接收端渲染统计

对应于媒体数据的渲染,包括丢弃帧数、丢失帧数、渲染帧数和渲染延迟等等

getStats()的返回信息包含WebRTC数据管线各个阶段的统计信息,为监控WebRTC应用的运行状态提供第一手数据。

二、前期知识

1. setInterval()

setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。

setInterval()方法会不停地调用函数,直到 clearInterval()被调用或窗口被关闭。由 setInterval()返回的 ID 值可用作 clearInterval() 方法的参数。

提示: 如果你只想执行一次可以使用 setTimeout()方法。

setInterval(code, milliseconds);
setInterval(function, milliseconds, param1, param2, ...)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>

<p>点击按钮,等待 3 秒会弹出 "Hello"</p>
<p>在弹出的对话框中点击 “确定”, 3 秒后会继续弹出。如此循环下去...</p>
<button onclick="myFunction()">点我</button>

<script>
function myFunction() {
    setInterval('alert("Hello");', 3000);
}
</script>

</body>
</html>

2. Object.keys()

方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致。

// 用法
Object.keys(obj)

// e.g.
// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

// getFoo is a property which isn't enumerable
var myObj = Object.create({}, {
  getFoo: {
    value: function () { return this.foo; }
  }
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']

3. =>箭头函数

函数的一种简洁写法

// e.g.
// ---------------------------------------
var funcName = params => params + 2;
funcName(2);
// 4
// ---------------------------------------
parameters => expression

// 等价于:
function (parameters){
  return expression;
}

与一般写法的区别:

和一般的函数不同,箭头函数不会绑定this。 或者说箭头函数不会改变this本来的绑定。

// e.g.
function Counter() {
    this.num = 0;
    this.timer = setInterval(function add() {
        this.num++;			// 注意:首先函数setInterval没有被某个声明的对象调用
      									// 也没有使用new关键字,再之没有使用bind, call和apply。
      							    // setInterval只是一个普通的函数。实际上setInterval里面的this绑定到全局对象的。
        console.log(this.num);
    }, 1000);
}
var b = new Counter();
// 输出
// NaN
// NaN
// NaN
// ...

那么,我们如何解决这个问题呢?使用箭头函数!使用箭头函数就不会导致this被绑定到全局对象。

function Counter() {
    this.num = 0;
    this.timer = setInterval(() => {
        this.num++;
        console.log(this.num);
    }, 1000);
}
var b = new Counter();

// 输出
// 1
// 2
// 3
// ...

三、getStats()调用说明

1. 调用参数

  • 一个可为空的MediaStreamTrack对象
  • 一个调用成功时的回调函数(成功回调函数的参数为getStats()得到的RTCStatsReport
  • 一个调用失败时的回调函数

2. 返回值——RTCStatsReport

RTCStatsReport 内部提供了通过调用RTCPeerConnection.getStats()RTCRtpReceiver.getStats()RTCRtpSender.getStats()这三个方法之一所获得的统计报告。该统计报告包含统计类别字符串名称到包含相应统计数据的对象的映射。

RTCPeerConnection上调用 getStats() 可以指定为希望获取连接上的出站,入站还是所有流的统计信息。

3. RTCStats字典

对于每种统计信息类别,都有一个字典,字典的属性提供相关信息。

所有 WebRTC 统计对象都基于 RTCStats 字典,该字典提供了最基本的信息:时间戳,统计类型字符串和唯一标识数据源的ID:

type

type给出了对象所代表的统计类别的名称,以及如何查找所需的特定数据类型。统计类别名称是枚举类RTCStatsType的成员。

candidate-pair

An RTCIceCandidatePairStats object providing statistics related to an RTCIceTransport. Candidate pairs other than the currently active pair for the transport are deleted when the RTCPeerConnection changes its RTCPeerConnection.iceGatheringState to new during an ICE restart. The active candidate pair is deleted after the transport switches to another candidate pair; this change cannot be detected otherwise.

截屏2021-01-26 下午9.55.46
  • bytesSent:发送的有效载荷字节数

  • bytesReceived:接收到的有效载荷字节数

  • totalRoundTripTime:从发送 STUN 请求到收到响应之间的总时间。该值包括连接性检查和同意检查请求。

  • currentRoundTripTime:该对等体通过这对ICE候选者描述的连接发送数据到远程对等体并返回所需的秒数。

  • availableOutgoingBitrate:可用带宽。返回一个指示候选对所代表的网络连接的可用出站能力的值。该值越高,您可以假设可用于外发数据的带宽越多。该值以 bit/s 为单位,以1秒为间隔进行计算。

certificate

An RTCCertificateStats object providing statistics related to a certificate being used by an RTCIceTransport.

截屏2021-01-26 下午9.49.22

codec

An RTCCodecStats object containing statistics about a codec currently being used by RTP streams to send or receive data for the RTCPeerConnection.

不同的profile/level对应了不同的codecs信息

截屏2021-01-26 下午9.54.54
csrc

An RTCContributingSourceStats object which contains statistics related to a contributing source (CSRC) that contributed to an inbound RTP stream.

data-channel

An RTCDataChannelStats object which contains statistics about each RTCDataChannel on the connection.

inbound-rtp(不包含RTT)

An RTCInboundRtpStreamStats object providing statistics about inbound data being received from remote peers. Since this only provides statistics related to inbound data, without considering the local peer’s state, any values that require knowledge of both, such as round-trip time, is not included.This report isn’t available if there are no connected peers.

inbound:入站

Xnip2021-01-26_22-01-49
  • packetsReceived:连接上收到的任何种类的数据包的总数。
  • bytesReceived
  • packetsLost:丢失的RTP数据包总数。请注意,由于这个数据包的估计方式,如果收到的数据包多于发送的数据包,它可能是负数。
  • framesReceived:Only exists for video. Represents the total number of complete frames received on this RTP stream. This metric is incremented when the complete frame is received.
  • frameWidth
  • frameHeight
  • keyFramesDecoded:只存在于视频中。它表示该RTP媒体流成功解码的关键帧的总数,如VP8[RFC6386]中的关键帧或H.264[RFC6184]中的IDR帧。这是 framesDecoded 的一个子集。
  • framesDropped:只存在于视频中。在解码前丢弃的帧总数,或者因为该帧错过了该接收器的显示期限而丢弃的帧总数。该测量从接收器创建时开始,是[RFC7004]附录A(g)中定义的累积度量。
  • totalDecodeTimes
  • totalInterFrameDelay:连续解码的帧之间的帧间延迟的总和,以秒为单位,在一帧被解码后记录。
  • totalSquareInterFrameDelay:连续解码的帧之间的帧间延迟的平方和,以秒为单位,在一帧被解码后记录。
local-candidate

An RTCIceCandidateStats object giving statistics about an ICE local candidate; these candidates are found in the output from RTCIceTransport.getLocalCandidates().

截屏2021-01-26 下午9.58.34
  • networkType:出于保护隐私的考虑,网络类型属性被废弃
  • ip
  • port
  • protocol
  • candidateType
outbound-rtp(不包含RTT)

The report is an RTCOutboundRtpStreamStats object providing statistics based on the local peer’s outgoing data being sent to its peers. This information considers only the outbound RTP stream, so any data which requires information about the state of the remote peers (such as round-trip time) is unavailable,since those values can’t be computed without knowing about the other peers’ states.

outbound:出站

Xnip2021-01-26_22-15-50
  • packetsSent
  • retransmittedPacketsSent:该SSRC重发的数据包总数。这是 packetsSent 的一个子集。如果RTX没有经过协商,重传的数据包通过这个ssrc发送。如果RTX经过协商,重传的数据包通过单独的rtxSsrc发送。
  • bytesSent
  • headerBytesSent:Total number of RTP header and padding bytes sent for this SSRC. This does not include the size of transport layer headers such as IP or UDP. headerBytesSent + bytesSent equals the number of bytes sent as payload over the transport.
peer-connection

A RTCPeerConnectionStats object provides statistics related to the overall peer connection’s RTCPeerConnection.

截屏2021-01-26 下午10.18.15
receiver

Provides statistics about a specific RTCRtpReceiver. The statistics object is an RTCAudioReceiverStats object if kind is audio; if kind is video, the object is an RTCVideoReceiverStats object.

remote-candidate

The report is an RTCIceCandidateStats object containing statistics about the remote candidate’s RTCIceTransport. This may include information such as the type of network, the protocol, the URL, the type of relay being used, and so forth.

截屏2021-01-26 下午9.59.26

so forth:之类的; 等等;

remote-inbound-rtp

The report is an RTCRemoteInboundRtpStreamStats object providing statistics about your outbound RTP data stream, but from the perspective of the remote peer. That is, this information is about your outbound-rtp stream, but as seen by the remote device that’s handling the stream. You can use this information to do things like determine how well the remote peer is receiving data.

这些信息是关于你的出站rtp数据流的,但是是由处理数据流的远程设备看到的。你可以使用这些信息来做一些事情,比如确定远程对等体接收数据的情况。

截屏2021-01-26 下午10.19.19
  • jitter:以秒为单位测量的抖动
  • packersLost
remote-outbound-rtp

The report is an RTCRemoteOutboundRtpStreamStats object that contains statistics about your inbound RTP (inbound-rtp) stream, but from the perspective of the remote peer.

sender

An object containing statistics about the RTCRtpSender for a stream on the RTCPeerConnection. If kind is "audio", this object is of type RTCAudioSenderStats; if kind is "video", this is an RTCVideoSenderStats object.

stream

An object of type RTCMediaStreamStats, providing statistics and information about a MediaStream which is part of the RTCPeerConnection.

截屏2021-01-26 下午10.14.48
track

The object is one of the types based on RTCMediaHandlerStats:

for audio tracks, the type is RTCSenderAudioTrackAttachmentStats

for video tracks, the type is RTCSenderVideoTrackAttachmentStats.

The data within provides statistics related to a particular MediaStreamTrack's attachment to an RTCRtpSender; also included are the media level metrics that go along with the track.

Xnip2021-01-26_22-12-52
  • jitterBufferDelay:它是指每个音频样本或视频帧从抖动缓冲区接收到第一个数据包(摄取时间戳)到离开抖动缓冲区(发射时间戳)的时间总和,以秒为单位。在音频的情况下,几个样本属于同一个RTP数据包,因此它们的摄取时间戳相同,但抖动缓冲区的发射时间戳不同。在视频的情况下,帧可能是通过几个RTP数据包接收的,因此摄取时间戳是进入抖动缓冲区的帧的最早数据包,而发射时间戳是整个帧离开抖动缓冲区的时间。这个指标在样本或帧退出时增加,已经完成了它们在缓冲区的时间(并递增jitterBufferEmittedCount)。平均抖动缓冲区延迟可以通过jitterBufferDelay / jitterBufferEmittedCount来计算。
  • jitterBufferEmittedCount
transport

An object that contains statistics related to a transport for an RTCPeerConnection. The object is of type RTCTransportStats.

截屏2021-01-26 下午10.19.59

3. 实现细节

监控P2P连接运行状态的getStats()PeerConnection对象中实现,而该对象把任务委托给成员变量StatsCollector对象的UpdateStats函数来实现

注意:getStats只负责拉取统计数据,而统计数据本身则由WebRTC内部各个模块周期性更新,这个过程是异步的。例如,传输层的RTT是由网络线程收到数据包后实时更新,而带宽估计信息则是在受到RTCP报文后解析计算得到。

UpdateStats函数

信息的收集是分模块进行的,其中最重要的是四个模块的信息:Transport,VoiceChannel,VideoChannel,DataChannel

  • Transport —— 网络相关的统计信息

  • VoiceChannel VideoChannel DataChannel —— 和各自MediaChannel相关

Extract系列函数从相应模块收集到信息后,执行后处理操作,把不同类型的信息重新组织为类型相同的StatsReport对象,存储到StatsCollector的列表中。

struct StatsReport{
	const ID id_;					// 包括类型,唯一标识符等信息	
	double timestamp_;		// 本次信息收集的开始时间
	Values values_;			  // 信息集合,可存储int,int64,string,bool,double等类型
}

四、一个例子——打印所有状态信息

<div id="statsBox"></div>
window.setInterval(function () {
    pc.getStats(null).then(stats => {
        let statsOutput = "";

        stats.forEach(report => {
            statsOutput += `<h2>Report: ${report.type}</h2>\n<strong>ID:</strong> ${report.id}<br>\n` +
                `<strong>Timestamp:</strong> ${report.timeStamp}<br>\n`;

            Object.keys(report).forEach(stateName => {
                if (stateName !== "id" && stateName != "timestamp" && stateName !== "type") {
                    statsOutput += `<strong>${stateName}:</strong> ${report[stateName]}<br>\n`;
                }
            });
            document.getElementById("statsBox").innerHTML = statsOutput;
        });
    });
}, 1000);

参考文档

https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/getStats

https://blog.csdn.net/onlycoder_net/article/details/76703856

https://developer.mozilla.org/zh-CN/docs/Web/API/RTCStatsReport

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的Flutter WebRTC使用示例: 1. 首先,您需要在您的Flutter应用程序中添加WebRTC插件。在pubspec.yaml文件中添加以下依赖项: ``` dependencies: flutter_webrtc: ^0.5.9 ``` 2. 创建一个新的Flutter页面,并导入WebRTC插件: ```dart import 'package:flutter_webrtc/flutter_webrtc.dart'; ``` 3. 在您的页面中创建一个RTCVideoRenderer对象,用于显示远程视频流: ```dart RTCVideoRenderer _remoteRenderer = RTCVideoRenderer(); ``` 4. 在页面初始化方法中初始化RTCVideoRenderer对象: ```dart @override void initState() { super.initState(); _remoteRenderer.initialize(); } ``` 5. 在页面销毁方法中释放RTCVideoRenderer对象: ```dart @override void dispose() { super.dispose(); _remoteRenderer.dispose(); } ``` 6. 在页面中创建一个RTCPeerConnection对象,用于建立WebRTC连接: ```dart RTCPeerConnection _peerConnection = await createPeerConnection(configuration); ``` 7. 创建一个RTCSessionDescription对象,用于设置本地SDP: ```dart RTCSessionDescription _localSdp = await _peerConnection.createOffer({'offerToReceiveVideo': 1}); await _peerConnection.setLocalDescription(_localSdp); ``` 8. 将本地SDP发送给远程对等体: ```dart sendLocalSdp(_localSdp.toMap()); ``` 9. 接收远程SDP,并设置远程SDP: ```dart RTCSessionDescription _remoteSdp = RTCSessionDescription(_sdp['sdp'], _sdp['type']); await _peerConnection.setRemoteDescription(_remoteSdp); ``` 10. 在页面中创建一个RTCIceCandidate对象,用于设置ICE候选项: ```dart RTCIceCandidate _candidate = RTCIceCandidate(_candidateMap['candidate'], _candidateMap['sdpMid'], _candidateMap['sdpMLineIndex']); await _peerConnection.addCandidate(_candidate); ``` 11. 在RTCVideoRenderer对象上显示远程视频流: ```dart _remoteRenderer.srcObject = _peerConnection.getRemoteStreams().first; ``` 这是一个简单的Flutter WebRTC使用示例,您可以根据您的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值