1. 概览介绍
打开 Chrome 浏览器,在地址栏输入chrome://webrtc-internals 即可打开调试工具,进入后可以看到类似的页面
1.1 Create Dump 保存日志
数据包含所有 PeerConnection 涉及到的信息,可供后续问题复盘。
1.2 读取状态日志
WebRTC 读取状态日志的2种标准,两种标准之间存在较大的差异。
- Standardized:符合W3C的新标准,其代码调用是基于 Promise
- Legacy Non-Standard:废弃的 google 定义的旧标准,基代码调用是基于 callback
// Standardized
pc.getStats().then(stats => console.log(stats))
// Legacy Non-Standard
pc.getStats(stats => console.log(stats))
1.3 GetUserMedia
是浏览器获取摄像头和麦克风媒体流的接口,GetUserMedia Request 的 Tab 中可以看到近期调用该API的记录,以及调用参数,有关 getUserMedia 的基本使用。每条记录都会包括:调用的域名、调用时间、音频约束、视频约束,如图:
navigator.mediaDevices 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等
mediaDevices 上提供了4个方法和一个监听事件
enumerateDevices: 获取系统可用的媒体输入和输出设备
getSupportedConstraints: 返回一个输入设备可支持的约束属性
getDisplayMedia: 开启屏幕共享
getUserMedia: 开启媒体输入设备
2. RTCPeerConnection 监控信息详解
可以看到除了GetUserMedia Requests,还有其他的Tab,这些每一个Tab都对应了一个 PeerConnection对象,打开后又可以分为4部分:
2.1 构造 PeerConnection 的参数
这一部分可以看到我们在构造 PeerConnection的 参数,这个参数是传入参数与默认参数的合并后的结果,PeerConnection 的构造函数详情可以参考 MDN
2.2 PeerConnection 的操作与事件
这里按照时间顺序记录了对 PeerConnection 的一些操作和回调事件
操作
- createOffer、createAnswer:生成 offer 和 answer,点击展开后可以看到调用参数(参数同样是合并后的值)
- setLocalDescription、setRemoteDescription: 设置的 local sdp 和 remote sdp,展开后可以看到详情
- addIceCandidate:将对端的 candidate 添加到 PeerConnection 中
回调事件
- createOfferOnSuccess、createAnswerOnSuccess:由于 createOffer 和 createAnswer 是异步的,所以这里显示了调用成功之后的结果
- setLocalDescriptionOnSuccess、setRemoteDescriptionOnSuccess:同样 setLocalDescription 和setRemoteDescription 也是异步的,这里表明是正确调用(也会有调用Failed的情况)
- signalingstatechange:信令状态的回调,信令状态是调用 setLocalDescription、setRemoteDescription 等API的结果,具体变化情况可以参考下图(信令状态同样重要,比如在'stable'的状态是不能直接设置remote sdp)
信令状态变化这里可能有点绕,但是如果像下图这样,设置时序或者任何SDP设置的问题可以很明显地看到
- icecandidate:收集本地的 candidate,收集动作一般是 setLocalDescription 后由 WebRTC 内部自动完成,然后由回调抛到 JS 层
- iceconnectionstatechange:ICE 的连接状态发生变化,具体可以参考MDN
- connectionstatechange:PeerConnection的连接状态发生变化,具体可以参考MDN
2.3 流数据(数值格式 & 图表格式)
这里可以真正的可以看到上行、下行的流数据,其中可以重点观注以下4行(上下连接部分分别的数值和图表格式,其含义和数据源是一致的):
- inbound-rtp:下行数据,可以分为音频和视频
-
outbound-rtp:上行数据,可以分为音频和视频
image.png
2.3.1 audio outbound-rtp/remote-inbound-rtp
- Kind: audio
- SSRC: 2840249774 和sdp的mline相对应
- bytesSent_in_bits/s:上行码率,音频一般在30k左右(静音后会减半),该值并不直接体现在getStats的返回值中,而是需要两次stats计算得出:码率 = (delta bytesSent) / (delta timestamp)
- packetsSent/s: 每秒发送的数据包 同理是由计算得出
- retransmittedPacketsSent: 重传包
- packetsLost:丢包,除以发送的总包数可以得到丢包率
- packetsLost:丢包,除以发送的总包数可以得到丢包率
const deltaLost = currentLost - prevLost;
const deltaSent = (currentPacketsSent + currentLost) - (prevPacketsSent + prevLost);
const lostRate = deltaLost / deltaSent;
- roundTripTime: 单位是秒
2.3.2 video outbound-rtp/remote-inbound-rtp
视频上行和音频类似,可以重点关注以下几个字段:
ssrc、codec、packetsSent、bytesSent_in_bit/s这些和音频统计一致
- frameWidth: 上行视频宽度
- frameHeight: 上行视频高度
同样可以对应的remote-inbound-rtp里看到远端接收的情况来计算丢包率和roundTripTime
2.3.3 audio inbound-rtp、video inbound-rtp
这里代表下行数据,大体和outbound-rtp类似,只是这里会包含丢包、audioLevel等数据
3. 实战问题分析
3.1 收到画面模糊
一般发生成通话刚建立时,下图是一个码率比较大的视频上行数据,可以看到刚开始有个明显爬坡的过程,这是因为WebRTC刚建立连接时并不知道网络状况如何,会一点点放开上行的码率,以确保视频的流畅,所以对端刚开始接收的是比较模糊的画面,这个属于正常现象。
如果在通话中画面模糊一直未恢复,可能是发送端网络比较差,或者采集码率极大,但是限制了 RTC 的上行码率,限制码率可以查看sdp 中是否有b=AS:行,或者如果是通过sender来限制可以通过 transceiverModified 事件来确定是否有maxBitrate的限制
3.2 拉流画面黑屏
需要查看 video 的 inbound-rtp 的下行码率是否有值,如果有值可以排查渲染的问题,如果无值的话,可以查看下发流方的码率,排除发流方发送异常。如果也正常的话需要服务器排查问题。
3.3 拉流无声
需要查看 audio 的 inbound-rtp 接收的 audioLevel 和 totalAudioEnergy,audioLevel 由 totalAudioEnergy 计算得出,值在 [0, 1] 之间,正常说话应该在 0.1 以上
在实际应用中可能会遇到各种各样的问题,比如打开通话Demo页面开始通话,查看audioLevel是正常有值的,但是如果在开始通话前在控制台输入:
Array(50).fill(0).forEach(() => new AudioContext());