18、浏览器兼容性调试:在不同浏览器(Chrome/Firefox/Safari)中对比 webrtc-internals 输出差异
做 WebRTC 开发,最头疼的问题之一就是:Chrome 上跑得好好的,换到 Safari 就黑屏了。
我遇到过不止一次。有一次线上会议系统,用户反馈说「我用 Mac 的 Safari 看不到对方画面」,我本地 Chrome 测了 N 遍都没问题。最后打开 webrtc-internals 一对比,才发现是 rtcp-mux 协商出了问题。
所以这一章,咱们就来聊聊怎么用 webrtc-internals 这把「手术刀」,解剖不同浏览器下的信令和媒体流差异。
18.1 为什么浏览器之间会有差异?
说白了,WebRTC 是一套规范,但各家浏览器实现细节不一样。Chrome 用 libwebrtc,Firefox 有自己的实现,Safari 更是「特立独行」。你想想看,ICE 候选人的优先级算法、SDP 的格式、甚至统计信息的字段名,都可能不同。
我个人习惯是:先统一场景,再对比差异。比如同一个房间、同一个网络环境,分别用三个浏览器打开,然后导出 webrtc-internals 的日志。
18.2 打开 webrtc-internals 的正确姿势
每个浏览器打开调试工具的方式略有不同,我列个表给你参考:
| 浏览器 | 打开方式 | 注意事项 |
|---|---|---|
| Chrome | 地址栏输入 chrome://webrtc-internals |
支持实时刷新,数据最全 |
| Firefox | 地址栏输入 about:webrtc |
界面风格不同,但核心信息都有 |
| Safari | 开发者菜单 → WebRTC → 勾选「启用日志」 | 需要先开启「开发」菜单,数据导出较麻烦 |
18.3 对比三大关键模块
我们不可能把几千行日志全看一遍。我一般只盯三个地方:SDP 协商、ICE 连接、RTP 统计。
18.3.1 SDP 协商差异
这是最常出问题的地方。Chrome 和 Firefox 在生成 SDP 时,a=ice-options 和 a=extmap 的排列顺序可能不同。Safari 则可能缺少某些扩展头。
举个例子,我曾经在 Safari 上发现它没有发送 a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id,导致接收端无法关联音视频流。
// Chrome 的 SDP 片段(正常)
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
// Safari 的 SDP 片段(缺少 extmap:3)
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
rtp-stream-id,接收端可能无法正确将 RTP 包映射到对应的 MediaStreamTrack。这时候你需要手动在接收端做 fallback 处理。
18.3.2 ICE 候选人差异
Firefox 和 Chrome 在 ICE 候选人优先级计算上略有不同。Firefox 更倾向于使用 host 类型的候选人,而 Chrome 会尝试更多 srflx 和 relay 候选人。
我记得有一次,用户反馈「Firefox 连不上,Chrome 可以」。我对比了 webrtc-internals 的 ICE 状态,发现 Firefox 的 srflx 候选人一直处于 checking 状态,而 Chrome 已经切换到 relay 成功了。
// Chrome ICE 候选人列表(部分)
candidate:1 1 UDP 2122252543 192.168.1.10 54321 typ host
candidate:2 1 UDP 1686052607 203.0.113.5 54322 typ srflx
candidate:3 1 UDP 41819903 203.0.113.5 54323 typ relay
// Firefox ICE 候选人列表(部分)
candidate:0 1 UDP 2130706431 192.168.1.10 54321 typ host
candidate:1 1 UDP 1694498815 203.0.113.5 54322 typ srflx
// 注意:Firefox 的 relay 候选人优先级较低,可能不会主动尝试
srflx 候选人一直失败,但又不切换到 relay。后来发现是 TURN 服务器的 transport 字段没配好。Firefox 对 TURN 的 UDP/TCP 协商更严格。
18.3.3 RTP 统计信息差异
webrtc-internals 里的 googTrackId、googFrameRateReceived 这些字段,其实是 Chrome 特有的。Firefox 和 Safari 的统计字段名完全不同。
比如,Chrome 用 googRtt 表示往返时延,Firefox 用 roundTripTime,Safari 则可能直接不暴露这个字段。你想想看,如果你写了一个自动化测试脚本,只解析 Chrome 的字段,那在 Safari 上肯定报错。
| 统计指标 | Chrome 字段名 | Firefox 字段名 | Safari 字段名 |
|---|---|---|---|
| 往返时延 (RTT) | googRtt |
roundTripTime |
可能缺失 |
| 丢包率 | googPacketsLost |
packetsLost |
packetsLost |
| 帧率 | googFrameRateReceived |
frameRate |
frameRate |
| 码率 | googFrameWidthReceived |
frameWidth |
frameWidth |
18.4 实战:三步对比法
我总结了一套「三步对比法」,你可以直接套用:
- 导出日志:在三个浏览器中分别打开 webrtc-internals,建立相同的 PeerConnection,然后点击「Export」或「Save」保存为 JSON 文件。
- 对齐时间轴:用文本编辑器打开 JSON,找到
startTime或timestamp字段,把三个文件的时间轴对齐到同一个起点。 - 逐项对比:重点关注 SDP 中的
a=extmap、ICE 候选人列表、以及googRtt/packetsLost等关键统计。
a=extmap 数量不一致,大概率是 Safari 或 Firefox 不支持某些 RTP 头部扩展。这时候你需要在 RTCRtpSender 或 RTCRtpReceiver 中手动设置 degradationPreference 或 headerExtensions。
18.5 核心知识体系
下面这张图,帮你理清本章的核心逻辑:
18.6 常见问题与避坑
最后,分享几个我踩过的坑:
- Safari 的 webrtc-internals 没有「Export」按钮:你需要手动复制日志窗口的内容,或者用
console.log输出RTCPeerConnection.getStats()的结果。 - Firefox 的 about:webrtc 页面不会自动刷新:每次建立新连接后,需要手动刷新页面才能看到最新数据。我一开始没注意,浪费了半天时间。
- Chrome 的 webrtc-internals 数据量太大:如果连接时间很长,导出的 JSON 可能几十 MB。建议只保留关键时间段的日志,或者用脚本过滤掉无关的
ssrc条目。
嗯,这一章的内容就到这里。记住,浏览器兼容性调试没有银弹,但 webrtc-internals 是你最可靠的「照妖镜」。多对比、多记录,慢慢你就能一眼看出问题出在哪个环节。
公众号:蓝海资料掘金营,微信deep3321