剑痴乎

剑痴乎
代码为剑,如痴如醉
  1. 首页
  2. WebRTC
  3. 正文

WebRTC研究:统计参数之往返时延

2021年3月21日 6526点热度 20人点赞 12条评论

前面文章介绍了抖动,今天我们来看下chrome://webrtc-internals/页面中的一个重要统计参数:往返时延(RTT)。

什么是RTT

往返时延(round-trip time,RTT) 是网络请求从起点到目的地然后再回到起点所花费的时长(不包括接收端的处理时间)。RTT是分析网络性能的一个重要指标,我们通常使用RTT来诊断网络连接的速度,可靠性以及拥塞程度。

ping命令是最常见的一种估计往返时延的方法。下面是ping Google的示例,底部显示了rtt的不同表示:最小,平均,最大,平均偏差。

1
2
3
4
5
6
7
8
9
10
11
root@jeff:~# ping google.com
PING google.com (172.253.118.138) 56(84) bytes of data.
64 bytes from 172.253.118.138: icmp_seq=1 ttl=105 time=1.81 ms
64 bytes from 172.253.118.138: icmp_seq=2 ttl=105 time=1.77 ms
64 bytes from 172.253.118.138: icmp_seq=3 ttl=105 time=1.76 ms
64 bytes from 172.253.118.138: icmp_seq=4 ttl=105 time=1.77 ms
64 bytes from 172.253.118.138: icmp_seq=5 ttl=105 time=1.94 ms
64 bytes from 172.253.118.138: icmp_seq=6 ttl=105 time=1.86 ms
--- google.com ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 5554ms
rtt min/avg/max/mdev = 1.764/1.821/1.944/0.069 ms

RTT计算方式

WebRTC中目前有两种方式计算RTT:

  • 基于媒体流发送端的计算(默认开启)。通过Sender Report(SR)与Receiver Report(RR)携带的信息。
  • 基于媒体流接收端的计算。通过RTCP Extended ReportsRTCP(XR)携带的信息。

这两种方式计算RTT的原理都一样。至于为什么需要接收端计算方式,这是因为在一些场景,媒体流传输是单向的,两个端点间一个只发媒体数据,一个只接收,例如客户端与SFU服务器间。假设客户端与SFU服务器上行推流场景,客户端推流,服务端收流,这种场景下作为接收端的服务端并不会发送SR,导致无法计算RTT。于是就有了通过RTCP XR在接收端计算这种方式。

媒体流发送端RTT计算

WebRTC中媒体流发送端RTT的计算是根据SR以及RR中携带的时间信息。这里我们回顾下Sender Report与Receiver Report RTCP两种报文。

Sender Report

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    RC   |   PT=SR=200   |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         SSRC of sender                        |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sender |              NTP timestamp, most significant word             |
info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |             NTP timestamp, least significant word             |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         RTP timestamp                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     sender's packet count                     |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      sender's octet count                     |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

  • NTP timestamp:64bits。记录着发送该SR的NTP时间戳。

Receiver Report

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P|    RC   |   PT=RR=201   |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                     SSRC of packet sender                     |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_1 (SSRC of first source)                 |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  1    | fraction lost |       cumulative number of packets lost       |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |           extended highest sequence number received           |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                      interarrival jitter                      |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         last SR (LSR)                         |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                   delay since last SR (DLSR)                  |
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report |                 SSRC_2 (SSRC of second source)                |
block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2    :                               ...                             :
       +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
       |                  profile-specific extensions                  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  • last SR timestamp (LSR): 32 bits。64位NTP时间戳中间的32bit(NTP时间戳指绝对时间,相对1900年1月1日00:00:00经历的时间,单位为秒。完整NTP时间戳用64bits表示,左半32bits表示整数,右半32bits表示小数,一般为了紧凑,取中间32bits表示即可,这时整数与小数分别16bits表示)。记录着上次源SSRC_n发送SR的NTP时间,从收到的SR记录的NTP时间戳获取。如果没有收到SR,值为0。
  • delay since last SR (DLSR): 32 bits。以1/65536(2^16)秒为单位。记录着上次接收到源SSRC_n发送的SR到当前发送RR的间隔时间。如果没有收到SR,值为0。

计算原理

前面简单介绍了RR中记录的时间信息,下面我们看下如何根据这些时间信息计算RTT。

上图中\(T_{0}\)时刻媒体流发送端发送SR,SR中记录着send_time_ntp。媒体流接收端\(t_{0}\)时刻收到SR,\(t_{1}\)时刻回复RR,RR中记录着:1)从收到的SR中获取的send_time_ntp信息;2)接收端回复RR与收到SR的间隔时间delay_since_last_sr。发送端在\(T_{1}\)时刻收到回复的RR。可知:
\[
delay\_since\_last\_sr = t_{1} - t_{0}\tag{1}
\]
\[
RTT = T_{1} - T_{0} - (t_{1} - t_{0})\tag{2}
\]
\[
RTT = receive\_time\_ntp - send\_time\_ntp - delay\_since\_last\_sr\tag{3}
\]

代码导读

WebRTC中,发送端首先需要调用ModuleRtpRtcpImpl::OnSendingRtpFrame,这样才能触发发送SR。

接着收到反馈的RR后才能进行RTT计算。WebRTC中发送端RTT计算代码位于RTCPReceiver::HandleReportBlock。
主要代码流程如下:

1
2
3
4
5
6
7
8
9
ModuleRtpRtcpImpl::IncomingRtcpPacket
             ↓
RTCPReceiver::IncomingPacket
             ↓
RTCPReceiver::ParseCompoundPacket
             ↓
RTCPReceiver::HandleReceiverReport
             ↓
RTCPReceiver::HandleReportBlock

RTCPReceiver::HandleReportBlock中RTT计算代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  int64_t rtt_ms = 0;
  uint32_t send_time_ntp = report_block.last_sr();
  if (send_time_ntp != 0) {
    uint32_t delay_ntp = report_block.delay_since_last_sr();
    // Local NTP time.
    uint32_t receive_time_ntp =
        CompactNtp(TimeMicrosToNtp(last_received_rb_.us()));
 
    // RTT in 1/(2^16) seconds.
    // 由于NTP时间戳中,整数以及小数部分分别用16bits表示,所以单位为1/(2^16)秒
    uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp;
    // Convert to 1/1000 seconds (milliseconds).
    rtt_ms = CompactNtpRttToMs(rtt_ntp);
    report_block_data->AddRoundTripTimeSample(rtt_ms);
 
    packet_information->rtt_ms = rtt_ms;
  }

结合前面的公式,上面代码应该很好理解。最后得到一个ms表示的RTT,chrome://webrtc-internals/中RTT的单位是秒。

媒体流接收端RTT计算

RTCP XR报文

WebRTC中媒体流接收端RTT的计算是根据XR中携带的时间信息。这里我们看下XR报文格式:

1
2
3
4
5
6
7
8
9
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|reserved |   PT=XR=207   |             length            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                              SSRC                             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   :                         report blocks                         :
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

时间信息存放在report blocks中。report blocks格式如下:

1
2
3
4
5
6
7
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      BT       | type-specific |         block length          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   :             type-specific block contents                      :
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

接收端RTT计算主要用到了Receiver Reference Time Report Block与DLRR Report Block这两种report blocks。

Receiver Reference Time Report Block(RRTR)

由媒体流接收端发送。报文格式如下:

1
2
3
4
5
6
7
8
9
    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     BT=4      |   reserved    |       block length = 2        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |              NTP timestamp, most significant word             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             NTP timestamp, least significant word             |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  • NTP timestamp:64bits。记录着发送该Receiver Reference Time Report Block的NTP时间戳。

DLRR Report Block

由媒体流发送端发送。报文格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     BT=5      |   reserved    |         block length          |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_1 (SSRC of first receiver)               | sub-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
|                         last RR (LRR)                         |   1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   delay since last RR (DLRR)                  |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_2 (SSRC of second receiver)              | sub-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
:                               ...                             :   2
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

  • last RR timestamp (LRR): 32 bits。记录着上次源SSRC_n发送Receiver Reference Time Report Block的NTP时间,从收到的Receiver Reference Time Report Block记录的NTP时间戳获取。如果没有收到,值为0。
  • delay since last RR (DLRR): 32 bits。以1/65536(2^16)秒为单位。记录着上次接收到源SSRC_n发送的Receiver Reference Time Report Block到当前发送DLRR Report Block的间隔时间。如果没有收到Receiver Reference Time Report Block,值为0。

计算原理

类似发送端RTT计算,只不过SR变为了Receiver Reference Time Report Block,由媒体流接收端发送。RR变为了DLRR Report Block,由媒体流发送端发送,最后在接收端计算。具体原理这里就不再啰嗦一次了。

代码导读

需要配置接收端ModuleRtpRtcpImpl中RtpRtcpInterface::Configuration的non_sender_rtt_measurement开启XR。
这里以视频为例,配置开启方式如下:

C++
1
2
3
4
5
6
7
8
9
WebRtcVideoReceiveChannel::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream{
  config_.rtp.rtcp_xr.receiver_reference_time_report = HasRrtr(codec.codec);
}
 
const char kRtcpFbParamRrtr[] = "rrtr";
bool HasRrtr(const Codec& codec) {
  return codec.HasFeedbackParam(
      FeedbackParam(kRtcpFbParamRrtr, kParamValueEmpty));
}

也就是检查SDP中某编码器"a=rtcp-fb"是否含有"rrtr"。例如:

1
2
3
4
5
6
7
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 rrtr

最终这个receiver_reference_time_report配置会传给RtpRtcpInterface::Configuration中的non_sender_rtt_measurement配置项,最后传到RTCPSender中。

媒体流接收端首先发送RRTR,然后收到媒体流发送端反馈的DLRR Report Block进行RTT计算。WebRTC中接收端RTT计算代码位于RTCPReceiver::HandleXrDlrrReportBlock。
主要代码流程如下:

1
2
3
4
5
6
7
8
9
ModuleRtpRtcpImpl::IncomingRtcpPacket
            ↓
RTCPReceiver::IncomingPacket
            ↓
RTCPReceiver::ParseCompoundPacket
            ↓
RTCPReceiver::HandleXr
            ↓
RTCPReceiver::HandleXrDlrrReportBlock

RTCPReceiver::HandleXrDlrrReportBlock中RTT计算代码如下:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  // The send_time and delay_rr fields are in units of 1/2^16 sec.
  uint32_t send_time_ntp = rti.last_rr;
  // RFC3611, section 4.5, LRR field discription states:
  // If no such block has been received, the field is set to zero.
  if (send_time_ntp == 0) {
    auto rtt_stats = non_sender_rtts_.find(sender_ssrc);
    if (rtt_stats != non_sender_rtts_.end()) {
      rtt_stats->second.Invalidate();
    }
    return;
  }
 
  uint32_t delay_ntp = rti.delay_since_last_rr;
  uint32_t now_ntp = CompactNtp(clock_->CurrentNtpTime());
 
  uint32_t rtt_ntp = now_ntp - delay_ntp - send_time_ntp;
  TimeDelta rtt = CompactNtpRttToTimeDelta(rtt_ntp);
  xr_rr_rtt_ = rtt;
 
  non_sender_rtts_[sender_ssrc].Update(rtt);

代码类似前面发送端RTT计算,就不分析了。

注意事项

WebRTC中RTCP XR总是附在SR或者RR后组成Compound RTCP包发送。

总结

本文简单介绍了RTT以及WebRTC中两种RTT的计算,RTT作为网络性能分析的一个重要指标,在WebRTC中扮演一个很重要的角色,至于具体用途,后面有空结合其它再分析。

参考

[1] RFC3550.https://tools.ietf.org/html/rfc3550.
[2] RFC3611.https://tools.ietf.org/html/rfc3611.

本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可
标签: WebRTC 网络
最后更新:2024年4月9日

Jeff

管理员——代码为剑,如痴如醉

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • 6666

    为啥你ping google的RTT那么小

    2021年5月31日
    回复
    • Jeff

      @6666 我是在我的国外服务器上操作的

      2021年5月31日
      回复
  • MarkCao

    谢谢大佬,解析的很透彻,受益匪浅。
    我的理解,这套RTT算法设计得真的很妙:
    1、对于双向传输,使用发送端RTT算法计算出一次round trip的时长作为RTT,满足双向传输的评估需求;
    2、对于单向传输,使用接收端RTT算法计算出两次发送所需的时长作为RTT,既兼容了传统的RTT算法,又刚好满足单向传输的评估需求。

    2021年6月10日
    回复
  • chris

    这种场景下作为接收端的服务端并不会发送SR,导致无法计算RTT——我看了下文中的图,为什么觉得应该时作为接收端不会发送RR,而不是SR。 是我理解错了还是笔误?

    2022年1月12日
    回复
    • Jeff

      @chris 上行推流场景,我们服务端需要获取RTT值,也就是需要在媒体流接收端计算RTT,由于媒体是上行传输,服务端只能发送RR,计算是在发送SR端,当然无法计算RTT了

      2022年1月26日
      回复
  • Jerry

    webrtc的统计信息中,有一个 currentRoundTripTime 信息。请问这个是 rrt吧? 服务器发送视频流,客户端只是接收,这个rrt 是否准确?

    2022年2月8日
    回复
    • Unreal

      @Jerry 非常不准

      2022年11月30日
      回复
      • Jerry

        @Unreal 请问为什么不准啊?

        2023年3月12日
        回复
    • Jeff

      @Jerry 这个也是rtt,不过不是本文webrtc这种通过RTC/RTCP协议计算的,可以参考:https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-currentroundtriptime 属于某个IceCandidatePair的,通过ICE的stun检测计算得到

      2023年11月23日
      回复
  • fireyang

    请教个问题 这个RTT时间很大 我怎么去debug是哪里出问题了 比如是是turn service的问题还是机器的问题

    2023年11月24日
    回复
    • Jeff

      @fireyang 在问题机器先用普通Ping命令ping下turn服务器看下rtt多少,初步判断网络是否问题

      2023年11月24日
      回复
  • fireyang

    用的是aws的 kinesis video stream 上海电信到us-west-2的 turn service ttl 大约0.5 开多个session 丢包很严重 不知道是不是因为跨海就是有这么高的延迟

    2023年11月27日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理。

    版权声明

    为支持原创,创作更好的文章,未经许可,禁止任何形式的转载与抄袭,如需转载请邮件私信!本人保留所有法定权利。违者必究!

    文章目录
    • 什么是RTT
    • RTT计算方式
    • 媒体流发送端RTT计算
      • Sender Report
      • Receiver Report
      • 计算原理
      • 代码导读
    • 媒体流接收端RTT计算
      • RTCP XR报文
      • 计算原理
      • 代码导读
    • 注意事项
    • 总结
    • 参考
    最近评论
    ztt 发布于 3 周前(04月05日) 你好,想看里面的视频和图片为什么没有显示呢?需要下flash吗还是什么。
    huowa222 发布于 4 周前(03月26日) 同问
    邱国禄 发布于 2 个月前(02月17日) Receive Delta以0.25ms为单位,reference time以64ms为单位,kDe...
    啊非 发布于 4 个月前(12月30日) 大神,请教一个问题: constexpr int kBaseScaleFactor = Tran...
    啊非 发布于 4 个月前(12月30日) reference time:3字节,表示参考时间,以64ms为单位,但是 代码里面是 Trans...
    相关文章
    • WebRTC研究:Transport-cc之RTP及RTCP
    • WebRTC音视频传输基础:NAT穿透
    • WebRTC研究:丢包判断
    • WebRTC研究:RTP中的序列号以及时间戳比较
    • WebRTC资讯:H265支持进展

    COPYRIGHT © 2024 jianchihu.net. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang