<audio id="audio" title="15 | WebRTC中的数据统计原来这么强大（上）" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9e/d8/9e33bea6ae5a1e14799c0ffcc40ab7d8.mp3"></audio>

当你使用WebRTC实现1对1通话后，还有一个非常重要的工作需要做，那就是**实现数据监控**。数据监控对于 WebRTC 来讲，就像是人的眼睛，有了它，你就可以随时了解WebRTC客户端的运转情况。

在WebRTC中可以监控很多方面的数据，比如收了多少包、发了多少包、丢了多少包，以及每路流的流量是多少，这几个是我们平常最关心的。除此之外，WebRTC还能监控目前收到几路流、发送了几路流、视频的宽/高、帧率等这些信息。

有了这些信息，你就可以**评估出目前用户使用的音视频产品的服务质量是好还是坏了**。当发现用户的音视频服务质量比较差时，尤其是网络带宽不足时，可以通过降低视频分辨率、减少视频帧率、关闭视频等策略来调整你的网络状况。

当然，还可以给用户一些友好的提示信息，以增强用户更好的体验。比如说，当发现丢包率较高时，可以给用户一个提示信息，如 “你目前的网络质量较差，建议…”。

如果确实是网络质量较差时，还可以在底层做切换网络链路的尝试，从而使服务质量能有所改善！

## WebRTC都能统计哪些数据

鉴于这些统计信息的重要性，那接下来我们来看一下，在 WebRTC 中都能监控到哪些统计信息。

在WebRTC中可以统计到的信息特别多，按类型大体分为以下几种：

- inbound-rtp
- outbound-rtp
- data-channel
- ……

至于其他更多的类型，你可以到文章末尾查看参考中的内容。对于每一种类型，WebRTC 都有非常详细的规范，关于这一点我会在下篇文章中再做详细的介绍。

实际上，要查看 WebRTC 的统计数据，你不需要另外再开发一行代码，**只要在 Chrome 浏览器下输入“chrome://webrtc-internals”这个 URL 就可以看到所有的统计信息了**。但它有一个前提条件，就是你必须有页面创建了 RTCPeerConnection 对象之后，才可以通过这个 URL 地址查看相关内容。因为在 Chrome 内部会记录每个存活的 **RTCPeerConnection** 对象，通过上面的访问地址，就可以从 Chrome 中取出其中的具体内容。

下面这张图就是从获取的统计数据页面中截取的，从中你就可以看出 WebRTC 都能统计哪些信息。

<img src="https://static001.geekbang.org/resource/image/e4/32/e4f935f496ba580e10f272f7f8b16932.png" alt="">

从这张图中，你可以看到它统计到了以下信息：

- 接收到的音频轨信息，“…Track_receiver_5…”
- 接收到的视频轨信息，“…Track_receiver_6…”
- 发送的音频轨信息，“…Track_sender_5…”
- 发送的视频轨信息，“…Track_sender_6…”
- ……

从上面的描述中，你可以看到，这些统计信息基本上包括了与音视频相关的方方面面。通过这些信息，你就可以做各种各样的服务质量分析了。比如说通过**接收到的音视频轨信息**，你就能分析出你的网络丢包情况、传输速率等信息，从而判断出你的网络质量如何。

接下来，我们以**接收到的视频轨信息**和**发送的视频轨信息**为例，向你详细介绍一下这些信息中都包括了哪些内容。

首先我们来看**接收到的视频轨信息**，在浏览器上点开 “…receiver_6(track)” 时，你就可以看到类似于下面这张图的内容：

<img src="https://static001.geekbang.org/resource/image/0f/45/0f20677f3744c5d4ea2ac3fd53c1a045.png" alt="">

> 
这里需要注意的是，这张图只是截取了接收到的视频轨信息的部分内容。


大体上，通过该图你就可以看到这路视频轨总共收了多少数据包、多少字节的数据，以及每秒钟接收了多少包、多少字节的数据。除此之外，你还可以看到视频从开始直播到截图时丢包的总数，以及丢包率。当然，这里面还有很多其他信息，只是由于截图的原因，就不全部展示出来了。

了解了**接收到的视频轨信息**的内容后，我们再来看看**发送的视频轨信息**。它与**接收到的视频轨信息**描述的内容基本相同，只不过方向是相反的，一个是接收数据，另一个是发送数据。它的信息如下图所示：

<img src="https://static001.geekbang.org/resource/image/8d/b8/8dd767c80d45efebd31e45bb6b23a1b8.png" alt="">

从这张图中你可以看到，在**发送的视频轨信息**中包括了 WebRTC 发送的总字节数、总包数、每秒钟发送的字节数和包数，以及重传的包数和字节数等信息。

通过上面的讲解，我相信你已经知道 WebRTC 在信息统计方面做的还是非常细、非常全面的。

由于篇幅的原因，这里我就不将所有的内容进行一一讲解了，你可以自己在Chrome中输入“chrome://webrtc-internals”来查看更详细的信息。

## 如何获取统计数据

既然浏览器可以看到这么多与WebRTC相关的统计数据，那么你可能不禁要问，这些信息是从哪儿来的呢？是否有相应的 API 也能够获取到这些信息呢？

当然有！ WebRTC 提供了一个非常强大的 API，即 **getStats()** 。通过该 API 你就可以获得上面讲述的所有信息了。

我们来看一下 getStats 的基本格式，大致如下：

```
promise = rtcPeerConnection.getStats(selector)

```

关于该 API，这里有几点需要向你说明：

- getStats API 是 RTCPeerConnecton 对象的方法，用于获取各种统计信息。
- 该方法的 selector 参数是可选的。如果为 null，则收集的是RTCPeerConnection 对象所有相关的统计信息；当然，你也可以给它设置一个  MediaStreamTrack 类型的参数，这样它就只收集对应 track 相关的统计信息了。
- 该函数返回 Promise 对象，如果你给 Promise 对象的 then 分支设置一个回调函数，那当 getStats 方法调用成功后，就能通过该回调函数来获取想要的统计信息了。
- 获取到的统计信息以 RTCStatsReport 类型返回。

下面咱们看一下具体的代码，这样你会有更深刻的感悟：

```
...
//获得速个连接的统计信息
pc.getStats().then( 
    //在一个连接中有很多 report
    reports =&gt; {
        //遍历每个 report
        reports.forEach( report =&gt; {
            //将每个 report 的详细信息打印出来
            console.log(report);
        });

    }).catch( err=&gt;{
    	console.error(err);
    });
);
...  

```

在上面的代码中，通过调用 RTCPeerConnecction 对象的 getStats 方法，就可以获取到你想得到的所有统计信息了。

如果你在浏览器上执行上面的代码，它大体上会得到下面这样的结果：

<img src="https://static001.geekbang.org/resource/image/e4/d6/e4b2635bb99e4f24004c6ba30824f6d6.png" alt="">

从这个结果中你可以看到，每个 Report 对象包括以下三个字段：

- id：对象的唯一标识，是一个字符串。
- timestamp：时间戳，用来标识该条Report是什么时间产生的。
- type：类型，是 RTCStatsType 类型，具体的类型可以到文章末尾查看参考中的内容。另外，在下一篇文章中我们还会对各种不同类型的 Report 做进一步的分析。

在上面这三个字段中，Type（类型）是最关键的。每种类型的 Report 都有它自己的格式定义，因此，当你要获取更详细的信息时，首先要判断出该 Report 的类型是什么，然后根据类型转成对应的Report对象，再将信息取出来。

咱们举个例子，inbound-rtp 类型的 Report 与 outbound-rtp 类型的 Report 就有着非常大的区别，通过下面这两张图的对比就能看得非常清楚了。

首先我们来看一下 inbound-rtp 类型的 Report：

<img src="https://static001.geekbang.org/resource/image/f8/e8/f8e7956f6fc333f6dab76a945cb1bbe8.png" alt="">

接下来是outbound-rtp类型的 Report：

<img src="https://static001.geekbang.org/resource/image/83/71/83ca4f0fc8c999d6745212cacfd78471.png" alt="">

从两张图中可以非常清楚地看到，inbount-rtp里描述的是与接收相关的统计信息，而outbound-rtp 中描述的则是与发送相关的各种统计信息。

## 小结

通过上面的讲解，我想你应该可以通过 RTCPeerConnection 对象的 getStats 方法得到你想要的各种统计信息了。

当然，你还可以通过向 RTCPeerConnection 对象的 getStats 方法中设置参数或不设置参数来决定你要获得多少统计数据或哪些统计数据。

WebRTC的这些统计信息对于真实的应用场景是非常重要的，音视频各种服务质量的好坏都是通过它们来决定的。其中最最关键的统计信息是**与传输相关**的信息，比如发了多少包、收了多少包、丢了多少包等，通过这些信息你很容易就能评估出用户在使用你的产品时是否出现了问题。

## 思考时间

现在到了思考时间，那本文你要思考的问题是，对于网络相关的统计信息是如何计算的呢？举个例子，如果 A 向 B 发了 1000 个包，A 怎么知道 B 有没有收到呢？你怎么知道它们之间有没有发生过丢包呢？

欢迎在留言区与我分享你的想法，也欢迎你在留言区记录你的思考过程。感谢阅读，如果你觉得这篇文章对你有帮助的话，也欢迎把它分享给更多的朋友。

## 参考

<img src="https://static001.geekbang.org/resource/image/72/93/72b638952a9e9d0440e9efdb4e2f4493.png" alt="">


