WEBRTC浅析(四)通过RTCP 报文计算RTT, Jitter以及丢包率
这篇文章是对webrtc 中,RTT, Jitter以及Nack值 这三种网络状态的变量的统计,主要分为两个部分:
第一部分,介绍RTCP的规范,主要包括Send Report,Receive Report。
第二部分,介绍在WEBRTC中,它是如何通过RTCP的SR,RR包,计算RTT,Jitter以及Nack。
第一部分:The RTP control protocol Format
参考链接:rfc6184
SR: Sender Report RTCP Packet
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 |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- NTP timestamp:此报告发送时的背景时钟
- RTP timestamp:据包中的 RTP 时间戳
- sender’s packet count: 从开始传输到此 SR 包产生时该发送者发送的 RTP 数据包总数
- sender’s octet count: 从开始传输到此 SR 包产生时该发送者在 RTP 数据包发送的字节总数(不包括头和填充)
- fraction lost: 丢包率
- cumulative number of packets lost: 累计包丢失数
- extended highest sequence number received: 接收到的扩展的最高序列号
- interarrival jitter: 网络间隔抖动
- last SR timestamp (LSR): 接收到的来自源 SSRC_n 的最新 RTCP 发送者报告(SR)的 64 位 NTP 时间
- delay since last SR (DLSR): 来自 SSRC_n 的 SR 包到发送此接收报告块之间的延时
6.4.2 RR: Receiver Report RTCP Packet
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 接收者报告包(RR)与发送者报告包基本相同,除了包类型域包含常数 201 和没有发送者信息的 5 个字(NTP 和 RTP 时间标志和发送者包和字节计数)。余下区域与 SR 包意义相同。若没有发送和接收据报告,在 RTCP 复合包头部加入空的 RR 包(RC=0)。
第二部分:在WEBRTC中,RTT,Jitter以及丢包率的计算方法
RTT的计算
-
RTT的计算公式
time ArriveTime = this reception report block is received RTT = ArriveTime - LSR - DLSR
-
WebRtc中,RTT的计算代码
void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, PacketInformation* packet_information, uint32_t remote_ssrc) { ...... uint32_t send_time_ntp = report_block.last_sr(); uint32_t delay_ntp = report_block.delay_since_last_sr(); // Local NTP time. uint32_t receive_time_ntp = CompactNtp(clock_->CurrentNtpTime()); // RTT in 1/(2^16) seconds. uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp; ...... }
Jitter的计算
-
Jitter的计算公式
Jitter的统计: D(i,j) = (Rj - Ri) - (Sj - Si) = (Rj - Sj) - (Ri - Si) 平均Jitter的统计: J(i) = J(i-1) + (|D(i-1,i)| - J(i-1))/16
-
Webrtc中Jitter的计算代码
void StreamStatisticianImpl::UpdateJitter(const RTPHeader& header, NtpTime receive_time) { uint32_t receive_time_rtp = NtpToRtp(receive_time, header.payload_type_frequency); uint32_t last_receive_time_rtp = NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency); int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) - (header.timestamp - last_received_timestamp_); time_diff_samples = std::abs(time_diff_samples); // lib_jingle sometimes deliver crazy jumps in TS for the same stream. // If this happens, don't update jitter value. Use 5 secs video frequency // as the threshold. if (time_diff_samples < 450000) { // Note we calculate in Q4 to avoid using float. int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_; jitter_q4_ += ((jitter_diff_q4 + 8) >> 4); ....... } }
丢包率的计算
-
丢包率的计算公式
fraction lost = 此次的丢包数*255/100
cumulative loss = 累计丢包数 -
Webrtc中的丢包率计算代码
RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics() { RtcpStatistics stats; 。。。。。。。 int32_t missing = 0; if (exp_since_last > rec_since_last) { missing = (exp_since_last - rec_since_last); } uint8_t local_fraction_lost = 0; if (exp_since_last) { // Scale 0 to 255, where 255 is 100% loss. local_fraction_lost = static_cast<uint8_t>(255 * missing / exp_since_last); } stats.fraction_lost = local_fraction_lost; // We need a counter for cumulative loss too. // TODO(danilchap): Ensure cumulative loss is below maximum value of 2^24. cumulative_loss_ += missing; stats.cumulative_lost = cumulative_loss_; 。。。。。。
}