webrtc QOS笔记三 RTT计算,SRS增加XR
创始人
2025-06-01 15:47:41

webrtc QOS笔记三 RTT计算,SRS增加XR


RTT计算方式

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

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

这两种方式计算RTT的原理大同小异。至于为什么需要接收端计算方式,这是因为在一些场景,两个端点间一个只发媒体数据,一个只接收。假设客户端与SRS服务器下行拉流场景,客户端仅拉流,这种场景下作为接收端并不会发送SR,导致无法计算RTT。于是就可以通过RTCP XR在接收端计算这种方式,SDK里面需要手动配置打开

调用栈

webrtc [M88]

发送端RTT计算

WebRTC中媒体流发送端RTT的计算是根据SR以及RR中携带的时间信息。

RTT=T1−T0−(t1−t0)

RR 并不是SR的应答packet 分别独立发送, 只需要记录好上一个SR的到达时间t0 和 RR发送时间t1, 得到dslsr 接收到端就总能算出正确RTT.

  • Send Report
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|    RC   |   PT=SR=200   |             length            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         SSRC of sender                        |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|              NTP timestamp, most significant word             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|             NTP timestamp, least significant word             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         RTP timestamp                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     sender's packet count                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      sender's octet count                     |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
  • NTP timestamp:64bits。记录着发送该SR的NTP时间戳。

  • Receiver Report

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|    RC   |   PT=RR=201   |             length            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     SSRC of packet sender                     |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_1 (SSRC of first source)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fraction lost |       cumulative number of packets lost       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           extended highest sequence number received           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      interarrival jitter                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         last SR (LSR)                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                   delay since last SR (DLSR)                  |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                 SSRC_2 (SSRC of second source)                |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
:                               ...                             :
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|                  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。

接收端RTT计算

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

  • Receiver Reference Time Report Block
    由媒体流接收端发送。报文格式如下:
      0                   1                   2                   30 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                         :+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-4.40                   1                   2                   30 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
    由媒体流发送端发送。报文格式如下:

      0                   1                   2                   30 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                         :+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-4.40                   1                   2                   30 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。

SRS play端增加xr实现

解析客户端发送过来的xr rrtr 报文,记录lsr(last_sender_report_ntp_).

srs_error_t SrsRtcPlayStream::on_rtcp_xr(SrsRtcpXr* rtcp)
{srs_error_t err = srs_success;// TODO: FIXME: Implements it./*@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-20                   1                   2                   30 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                         :+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-4.40                   1                   2                   30 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             |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*/SrsBuffer stream(rtcp->data(), rtcp->size());stream.read_1bytes();uint8_t pt = stream.read_1bytes();srs_assert(pt == kXR);uint16_t length = (stream.read_2bytes() + 1) * 4;uint32_t ssrc = stream.read_4bytes();if (length > rtcp->size()) {return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid XR packet, length=%u, nb_buf=%d", length, rtcp->size());}uint8_t bt = stream.read_1bytes();uint8_t reserved = stream.read_1bytes();uint16_t block_length = stream.read_2bytes();SrsNtp lsr_ntp;lsr_ntp.ntp_second_ = stream.read_4bytes();lsr_ntp.ntp_fractions_ = stream.read_4bytes();for (map::iterator it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {SrsRtcVideoSendTrack* track = it->second;if (!track->get_track_status() || !track->has_ssrc(ssrc)) {continue;}track->last_sender_report_ntp_ = lsr_ntp;track->last_sender_report_sys_time_ = srs_update_system_time();break;}return err;
}

定时发送xr dlrr 报文.
play原生没有实现可参考publish端的定时任务添加一个.

srs_error_t SrsRtcConnection::send_rtcp_xr_dlrr(uint32_t ssrc, const uint64_t& last_send_systime, const SrsNtp& last_send_ntp) {/*@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-20                   1                   2                   30 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                         :+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+@see: http://www.rfc-editor.org/rfc/rfc3611.html#section-4.40                   1                   2                   30 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+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*/srs_error_t err = srs_success;// srs_warn("this: %p", this);// @see https://tools.ietf.org/html/rfc3550#section-6.4.2char buf[kRtpPacketSize];SrsBuffer stream(buf, sizeof(buf));stream.write_1bytes(0x80);stream.write_1bytes(kXR);stream.write_2bytes(5);stream.write_4bytes(ssrc); // TODO: FIXME: Should be 1?stream.write_1bytes(5);stream.write_1bytes(0);stream.write_2bytes(3);stream.write_4bytes(1);uint32_t xr_lrr = 0;uint32_t xr_dlrr = 0;if (last_send_systime > 0) {xr_lrr = (last_send_ntp.ntp_second_ << 16) | (last_send_ntp.ntp_fractions_ >> 16);uint32_t dlrr = (srs_update_system_time() - last_send_systime) / 1000;xr_dlrr = ((dlrr / 1000) << 16) | ((dlrr % 1000) * 65536 / 1000);}stream.write_4bytes(xr_lrr);stream.write_4bytes(xr_dlrr);int nb_protected_buf = stream.pos();if ((err = transport_->protect_rtcp(stream.data(), &nb_protected_buf)) != srs_success) {return srs_error_wrap(err, "protect rtcp xr");}return sendonly_skt->sendto(stream.data(), nb_protected_buf, 0);
}

参考:
https://blog.jianchihu.net/webrtc-research-stats-rtt.html
https://www.rfc-editor.org/rfc/pdfrfc/rfc3611.txt.pdf

相关内容

热门资讯

媒体点赞!当牛排“遇见”贵州,... 当牛排与多彩贵州的山地风味相遇,会碰撞出怎样的味觉惊喜?12月23日,贵州饭店·贵宾楼NO.66扒房...
凉山会东:惠民演出搭台 绘就文... 日前,会东县2025“多彩欢歌”惠民文艺演出暨第十届“双黑”美食文化季在会东县姜州镇中和村精彩上演。...
请查收!这份“冬日限定版敦煌”... 冬季的甘肃敦煌是时间按下慢放键的礼物当冷冽的风吹过九层楼初雪轻落鸣沙山敦煌便迎来了一年中最安静的时辰...
美食故事:藏在剁椒鱼头和广东煲... 分享关于美食的故事,并非仅仅是去回想某一道菜肴所尝出的味道,更是再度去品味跟其有所关联的人,以及与之...
宁夏:让本土葡萄酒进入千家万户 12月24日,为了让宁夏打造的本土葡萄酒进入千家万户,记者跟随宁夏银川贺兰山东麓葡萄酒管委会,一起走...