webrtc rtt 计算
Definitions
-
RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。
-
一般认为单向时延=传输时延t1+传播时延t2+排队时延t3 t1是数据从进入节点到传输媒体所需要的时间,通常等于数据块长度/信道带宽 t2是信号在信道中需要传播一定距离而花费的时间,等于信道长度/传播速率(光纤中电磁波的传播速率约为210^5 km/s,铜缆中2.310^5 km/s) t3可笼统归纳为随机噪声,由途径的每一跳设备及收发两端负荷情况及吞吐排队情况决定(包含互联网设备和传输设备时延) 综上:时延并无标准值只有经验值。某运营商规定网内路由器间时延1000公里之内<=40ms,2000公里之内<=60ms,3000公里之内<=80ms
RTT Calculation
大写S代表发送时间,R代表接收时间,D代表延时 S(a0) A------------------------------------------------------ > B R( b0)
S(a0) D(b0) A<--------------------------------------------------------B D(b0) = S(b0) - R(b0)
1,A先发一个数据包,在本地记录下发送时间 S(a0),并把 S(a0)放在数据包中发给B 2,B收到数据包,在本地记录下数据接收时间R( b0),并把数据包发回A,发送时把本地处理延时时间 D(b0)也记录到数据包中,D(b0) = S(b0) - R(b0) 3,A收到B的回应后,记录到数据接收时间R(a0) 4, rtt = R(a0) - S(a0) - D0
WebRtc RTT Calculation
1.名词解释
-
LSR: 最近一次SR包的NTP时间戳(remote_sender_ntp_time_);LSR由NTP秒(second)低16位和毫秒(fraction)高16位组合而成;
-
DLSR: 最近一次收到SR包到打包Report Block包的间隔.
SR报文格式:
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) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
RR报文格式:
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2. 探测流程
探测流程:
-
发送端构造和发送SR包,携带发送时间戳
LSR
; -
接收端接收到最新的SR之后,使用
last_received_sr_ntp_
字段记录当前ntp时间戳; -
接收端构造RR包,设置DLSR字段为
当前ntp时间戳 - last_received_sr_ntp_
,之后发出RR包; -
发送端在接收到RR包之后,记录RR包到达时间
now_ntp
; -
计算rtt:
now_ntp - LSR - DLSR
SR和RR包的数量并不需要完全相同,它们之间并不是一一对应的关系,而是相互独立发送的,各自按照自己的发送节奏发送数据. 即使SR或者RR丢失了一部分,只要发送端接收到过RR,它总能计算出rtt,因为发送端只需要一次RR包中的LSR和DLSR字段就能够算出一次rtt.
3. 更新流程
由上一步得到的rtt值会被传递到CallStats
中进行定时更新操作(CallStats::Process
), 时间间隔为1s(kUpdateIntervalMs
). 一次处理流程CallStats::Process
为:
-
RemoveOldReports
移除1.5s之前的旧的rtt数据; -
计算最近1.5s之内的rtt平均值和最大值;
-
如果最大值和平均值都是非负数,那么便认为rtt合法;
-
以平均rtt值和之前的旧的值做一个加权(3:7)作为最终的rtt计算值,通知所有观察者.
4. 相关代码
`RTCPSender::BuildSR` `RTCPSender::BuildRR` `RTCPSender::SendCompoundRTCP` `RTCPReceiver::HandleReceiverReport` `RTCPReceiver::HandleReportBlock
获取LSR
bool ModuleRtpRtcpImpl::LastReceivedNTP( uint32_t* rtcp_arrival_time_secs, // When we got the last report. uint32_t* rtcp_arrival_time_frac, uint32_t* remote_sr) const { // Remote SR: NTP inside the last received (mid 16 bits from sec and frac). uint32_t ntp_secs = 0; uint32_t ntp_frac = 0; if (!rtcp_receiver_.NTP(&ntp_secs, &ntp_frac, rtcp_arrival_time_secs, rtcp_arrival_time_frac, NULL)) { return false; } //remote_sr 就是 last SR (LSR) LSR由NTP秒(second)低16位和毫秒(fraction)高16位组合而成; *remote_sr = ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16); return true; }
计算DLSR
bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state, uint32_t ssrc, StreamStatistician* statistician) { ... ... ... // Delay since last received report. if ((feedback_state.last_rr_ntp_secs != 0) || (feedback_state.last_rr_ntp_frac != 0)) { // Get the 16 lowest bits of seconds and the 16 highest bits of fractions. uint32_t now = CompactNtp(ntp); //接收到sr的的时间 last_rr_ntp_secs last_rr_ntp_frac uint32_t receiveTime = feedback_state.last_rr_ntp_secs & 0x0000FFFF; receiveTime <<= 16; receiveTime += (feedback_state.last_rr_ntp_frac & 0xffff0000) >> 16; block->SetDelayLastSr(now - receiveTime); } return true; }
计算RTT
void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block, PacketInformation* packet_information, uint32_t remote_ssrc) { ... ... ... int64_t rtt_ms = 0; //LSR uint32_t send_time_ntp = report_block.last_sr(); // RFC3550, section 6.4.1, LSR field discription states: // If no SR has been received yet, the field is set to zero. // Receiver rtp_rtcp module is not expected to calculate rtt using // Sender Reports even if it accidentally can. if (!receiver_only_ && send_time_ntp != 0) { //DLSR uint32_t delay_ntp = report_block.delay_since_last_sr(); // Local NTP time. uint32_t receive_time_ntp = CompactNtp(clock_->CurrentNtpTime()); //计算RTT // RTT in 1/(2^16) seconds. uint32_t rtt_ntp = receive_time_ntp - delay_ntp - send_time_ntp; // Convert to 1/1000 seconds (milliseconds). rtt_ms = CompactNtpRttToMs(rtt_ntp); if (rtt_ms > report_block_info->max_rtt_ms) report_block_info->max_rtt_ms = rtt_ms; if (report_block_info->num_rtts == 0 || rtt_ms < report_block_info->min_rtt_ms) report_block_info->min_rtt_ms = rtt_ms; report_block_info->last_rtt_ms = rtt_ms; report_block_info->sum_rtt_ms += rtt_ms; ++report_block_info->num_rtts; } ... ... ... }
更新回调
void CallStats::Process() { RTC_DCHECK_RUN_ON(&process_thread_checker_); int64_t now = clock_->TimeInMilliseconds(); last_process_time_ = now; // |avg_rtt_ms_| is allowed to be read on the process thread since that's the // only thread that modifies the value. int64_t avg_rtt_ms = avg_rtt_ms_; RemoveOldReports(now, &reports_); max_rtt_ms_ = GetMaxRttMs(reports_); avg_rtt_ms = GetNewAvgRttMs(reports_, avg_rtt_ms); { rtc::CritScope lock(&avg_rtt_ms_lock_); avg_rtt_ms_ = avg_rtt_ms; } // If there is a valid rtt, update all observers with the max rtt. if (max_rtt_ms_ >= 0) { RTC_DCHECK_GE(avg_rtt_ms, 0); for (CallStatsObserver* observer : observers_) observer->OnRttUpdate(avg_rtt_ms, max_rtt_ms_); // Sum for Histogram of average RTT reported over the entire call. sum_avg_rtt_ms_ += avg_rtt_ms; ++num_avg_rtt_; } }
int64_t GetNewAvgRttMs(const std::list<CallStats::RttTime>& reports, int64_t prev_avg_rtt) { if (reports.empty()) return -1; // Reset (invalid average). int64_t cur_rtt_ms = GetAvgRttMs(reports); if (prev_avg_rtt == -1) return cur_rtt_ms; // New initial average value. // Weight factor to apply to the average rtt. // We weigh the old average at 70% against the new average (30%). constexpr const float kWeightFactor = 0.3f; return prev_avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor; }
References
[http://www.voidcn.com/article/p-dkzjvoaj-bpd.html] http://www.voidcn.com/article/p-dkzjvoaj-bpd.html
[https://www.cnblogs.com/xl2432/p/13424448.html] https://www.cnblogs.com/xl2432/p/13424448.html