WebRTC internal dump 文件的分析
Posted on Sat 01 July 2023 in Journal
Abstract | WebRTC stats analyze |
---|---|
Authors | Walter Fan |
Category | webrtc note |
Status | v1.0 |
Updated | 2023-07-01 |
License | CC-BY-NC-ND 4.0 |
Overview
在 WebRTC 的开发过程中, 我们看的最多的度量数据来自 getStats 接口, 我接触 WebRTC 开发的第一个任务就是定时调用这个接口, 获取, 分析并计算出相应的度量数据, 发送到远程的 ElasticSearch 中做进一步分析.
日常做 QoS 调优时, 看的最多的就是 chrome://webrtc * chrome://webrtc-internals/ in chrome, * edge://webrtc-internals/ in edge * about:webrtc in firefox
主要有如下状态信息以及度量数据:
- ICE connection state
- Signaling state
- ICE candidate grid
- ICE connection candidate pair and related metrics
- Inbound RTP and remote inbound RTP stream metrics
- Outbound RTP and remote outbound RTP stream metrics
下列类别的度量指标
- Candidate-pair
- Local-candidate
- Remote-candidate
- Inbound-rtp
- Outbound-rtp
- Opus codec: maxaveragebitrate, maxplaybackrate, stereo, useinbandfec, etc.
- H264 codec: level-asymmetry-allowed, max-br, max-dpb, max-fps, max-fs, max-mbps, packetization-mode, profile-level-id, id, etc.
以前写过一篇相关的笔记 WebRTC 之度量与统计: 到底出了什么问题
我用过最多的分析工具是 https://fippo.github.io/webrtc-dump-importer/, 它是一个 Web 前端的分析工具, 用来分析和展示从 chrome://webrtc-internals导出的文件, 功能强大.
可是用的多了, 难免有些地方不太满意, 尤其我常常需要自动分析提取一些度量数据, 这个 web 工具用起来并不趁手, 索性自己用 python 写一个脚本. 用来分析 chrome://webrtc-internals 的导出文件结构其实不复杂, 就是一个大的 JSON 文件, 基本结构大致如下:
{
"PeerConnections": {"9-1": {
"stats": {
"T31-[bytesSent_in_bits/s]": {
"values": "[0,0,672,0,...,0,448]",
"statsType": "transport",
"startTime": "2023-04-25T07:13:58.127Z",
"endTime": "2023-04-25T07:20:19.289Z"
},
//...
}}}}
}
完整的例子请参见 https://github.com/walterfan/webrtc_stats/blob/master/samples/receiver_webrtc_internals_dump.txt
最顶层的节点是 PeerConnections, 包含的子节点是 PeerConnection 的标识, 其子节点 stats 中包含所有相关的度量数据, 结构如下, 键 key 是度量所属类型节点的标识加上度量的名称,中间用横线隔开.
例如 "T31-[bytesSent_in_bits/s]", 它是一个 "transport" 类型的度量数据, T31 是这个 transport 的标识, "[bytesSent_in_bits/s]"是这个度量指标的名称, startTime 和 endTime 是度量采集的开始和结束时间, 具体的度量指标在 value 节点中, 它其实就是一个度量值的列表.
"T31-[bytesSent_in_bits/s]": {
"values": "[0,0,...,0,448]",
"statsType": "transport",
"startTime": "2023-04-25T07:13:58.127Z",
"endTime": "2023-04-25T07:20:19.289Z"
}
了解了结构, 代码就好写了, 核心代码如下, 解析出来的数据分门别类放在 Pandas 的 DataFrame 中以供检索和分析
def parse(self, file_name):
with open(file_name, 'r', encoding='utf_8') as f:
logger.info(f"open {file_name}")
self._webrtc_internals = {}
try:
self._webrtc_internals = json.load(f)
except:
logger.errror('not a json file {}'.format(file_name))
for pcKey, pcValue in self._webrtc_internals['PeerConnections'].items():
pcStats = pcValue["stats"]
for itemKey, itemDict in pcValue.items():
if itemKey == "stats":
for statKey, statDict in itemDict.items():
statsItem = {}
statsItem["key"] = statKey
statsItem["pc"] = pcKey
if "-" in statKey:
arr = statKey.split("-")
statsItem["id"] = arr[0]
statsItem["name"] = arr[1]
statsItem.update(statDict)
self._pc_stats.append(statsItem)
elif itemKey == "updateLog":
self._pc_events = itemDict
else:
pass
self._webrtc_stats = pd.DataFrame.from_records(self._pc_stats)
self._webrtc_events = pd.DataFrame.from_records(self._pc_events)
self._media_stats = self.get_metrics_values(self._webrtc_stats)
完整的代码参见 https://github.com/walterfan/webrtc_stats/blob/master/src/webrtc_stats/analyzer.py
你可以从 github 下 clone 下来试试, 也欢迎提交 issue 或 commit
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements.txt
命令行的用法很简单, 我写了一个 fabric file 提供如下的命令行
fab -l
Available tasks:
candidate-pair-stats usage: fab candidate-pair-stats -f samples/receiver_webrtc_internals_dump.txt
frontend
inbound-rtp-stats usage: fab inbound-rtp-stats -f samples/receiver_webrtc_internals_dump.txt
local-ip
media-stats usage: fab media-stats -f samples/receiver_webrtc_internals_dump.txt -t inbound-rtp -n "[bytesReceived_in_bits/s]"
fab media-stats -f samples/receiver_webrtc_internals_dump.txt -n "[framesDecoded/s]" -i IT01V467742569
outbound-rtp-stats usage: fab outbound-rtp-stats -f samples/sender_webrtc_internals_dump.txt
rtp-stats usage: fab rtp-stats -f samples/sender_webrtc_internals_dump.txt -c outbound-rtp -b "[bytesSent_in_bits/s]"
如果你想查看 inbound-rtp 的度量数据, 命令行示例如下:
$ webrtc_stats % fab inbound-rtp-stats -f samples/receiver_webrtc_internals_dump.txt
# inbound-rtp: IT01V467742569
* IT01V467742569-[bytesReceived_in_bits/s]: [1057815.6084069193, 1949136.4, 2380781.399318759, 1181545.8275777523, 1729870.2551245708, 2928208.0, 2665694.498708824, 2764680.961158322, 3107860.3648904916, 2916136.0]
* IT01V467742569-frameWidth: [960, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920]
* IT01V467742569-framesPerSecond: [22, 31, 27, 28, 30, 30, 20, 26, 33, 28]
* IT01V467742569-framesDecoded: [2954, 4312, 5017, 5035, 5065, 5095, 5115, 5141, 5174, 5202]
* IT01V467742569-[framesDecoded/s]: [31.181973109198267, 22.633333333333333, 25.546255135422783, 31.914886277745744, 29.970032140065328, 30.0, 19.98002142671022, 26.052100424375453, 32.96703535407186, 28.0]
* IT01V467742569-keyFramesDecoded: [59, 67, 67, 67, 67, 67, 67, 67, 67, 67]
* IT01V467742569-nackCount: [3632, 3855, 3998, 3998, 3998, 3998, 4002, 4009, 4015, 4020]
* IT01V467742569-pliCount: [151, 151, 151, 151, 151, 151, 151, 151, 151, 151]
* IT01V467742569-ssrc: ['467742569', '467742569', '467742569', '467742569', '467742569', '467742569', '467742569', '467742569', '467742569', '467742569']
* IT01V467742569-kind: ['video', 'video', 'video', 'video', 'video', 'video', 'video', 'video', 'video', 'video']
# inbound-rtp: IT11A558062930
* IT11A558062930-[bytesReceived_in_bits/s]: [226840.0292826884, 226648.8, 224852.26749868362, 225191.43757577398, 231104.91183847174, 222264.0, 226573.44297889387, 227254.47600955202, 226573.44297889387, 226800.0]
* IT11A558062930-ssrc: ['558062930', '558062930', '558062930', '558062930', '558062930', '558062930', '558062930', '558062930', '558062930', '558062930']
* IT11A558062930-kind: ['audio', 'audio', 'audio', 'audio', 'audio', 'audio', 'audio', 'audio', 'audio', 'audio']
- 查看所有输入 RTP 的比特率
% fab media-stats -f samples/receiver_webrtc_internals_dump.txt -t inbound-rtp -n "[bytesReceived_in_bits/s]"
key values startTime endTime
94 IT21V2517750364-[bytesReceived_in_bits/s] [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
373 IT11A558062930-[bytesReceived_in_bits/s] [0,1200,1200,1222.7773113146654,1200,1176,1201... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
504 IT01V467742569-[bytesReceived_in_bits/s] [0,3378640,3345656,3023744.474684042,2627192,2... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
878 IT31A4243477824-[bytesReceived_in_bits/s] [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
1054 IT11A2396938120-[bytesReceived_in_bits/s] [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
1110 IT11A123918746-[bytesReceived_in_bits/s] [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0... 2023-04-25T07:13:58.127Z 2023-04-25T07:20:19.289Z
还可以用如下命令只分析其一项指标的变化
% fab media-stats -f samples/receiver_webrtc_internals_dump.txt -n "[framesDecoded/s]" -i IT01V467742569
+-----+----------------------------------+-----------+
| | timestamp | value |
|-----+----------------------------------+-----------|
| 0 | 2023-04-24 23:13:58.127000+00:00 | 0 |
| 1 | 2023-04-24 23:13:59.127000+00:00 | 15 |
| 2 | 2023-04-24 23:14:00.127000+00:00 | 18 |
| 3 | 2023-04-24 23:14:01.127000+00:00 | 21.978 |
| 4 | 2023-04-24 23:14:02.127000+00:00 | 24 |
| 5 | 2023-04-24 23:14:03.127000+00:00 | 9 |
| 6 | 2023-04-24 23:14:04.127000+00:00 | 20.02 |
| 7 | 2023-04-24 23:14:05.127000+00:00 | 13.9795 |
| 8 | 2023-04-24 23:14:06.127000+00:00 | 15.0862 |
| 9 | 2023-04-24 23:14:07.127000+00:00 | 8.00801 |
| 10 | 2023-04-24 23:14:08.127000+00:00 | 7.99201 |
当然, 对于那些用惯了图形化界面的同学, 我也写了一个图形界面, 代码正在施工中, 敬请期待
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。