JCHub

  • Home
  • Category
    • A/V
    • WebRTC
    • Beauty of Programming
    • Linux
    • Windows
    • Moments of Life
    • Campus Life
  • Reference
    • API Reference
    • Utilities
    • AV Test
    • Doc
  • Message Board
  • About
JCHub
Code as My Sword, Lost in Obsession
  1. Main page
  2. WebRTC
  3. Main content

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

2021年3月21日 8157hotness 20likes 12comments

前面文章介绍了抖动,今天我们来看下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.

This article is licensed with Creative Commons Attribution-NonCommercial-No Derivatives 4.0 International License
Tag: WebRTC 网络
Last updated:2024年4月9日

Jeff

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

Tip the author Like
< Last article
Next article >

Comments

  • 6666

    为啥你ping google的RTT那么小

    2021年5月31日
    Reply
    • Jeff

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

      2021年5月31日
      Reply
  • MarkCao

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

    2021年6月10日
    Reply
  • chris

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

    2022年1月12日
    Reply
    • Jeff

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

      2022年1月26日
      Reply
  • Jerry

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

    2022年2月8日
    Reply
    • Unreal

      @Jerry 非常不准

      2022年11月30日
      Reply
      • Jerry

        @Unreal 请问为什么不准啊?

        2023年3月12日
        Reply
    • Jeff

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

      2023年11月23日
      Reply
  • fireyang

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

    2023年11月24日
    Reply
    • Jeff

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

      2023年11月24日
      Reply
  • fireyang

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

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

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    文章目录
    • 什么是RTT
    • RTT计算方式
    • 媒体流发送端RTT计算
      • Sender Report
      • Receiver Report
      • 计算原理
      • 代码导读
    • 媒体流接收端RTT计算
      • RTCP XR报文
      • 计算原理
      • 代码导读
    • 注意事项
    • 总结
    • 参考
    相关文章
    • 浅谈基于SFU实现一对一效果
    • WebRTC研究:Transport-cc之RTP及RTCP
    • WebRTC音视频传输基础:NAT穿透
    • WebRTC研究:丢包判断
    • WebRTC研究:RTP中的序列号以及时间戳比较

    COPYRIGHT © 2026 jianchihu.net. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang