[webrtc] rtcp模块中rtt时间计算
来源:互联网 发布:html5 json 数据解析 编辑:程序博客网 时间:2024/06/05 09:27
RTT指 round-trip time,即计算AB两端的往返时延
这里可以分成两个问题:
如何在A端估算A和B之间的RTT时间?
如何在B端估算A和B之间的RTT时间?
本文参考资料:
rfc 3550
rfc 3611
webrtc issue https://code.google.com/p/webrtc/issues/detail?id=1613
以及解决版本
https://code.google.com/p/webrtc/source/detail?r=4898
https://code.google.com/p/webrtc/source/detail?r=5063
一、假设A -> B 发送视频. 那么如何在A端估算A->B之间的RTT时间?
RFC 3550 http://tools.ietf.org/html/rfc3550#section-6.4.1
6.4.1 SR: Sender Report RTCP Packet
中描述了如何在发送端计算RTT时间.
大概过程如下:
A 发送 SR 包, 并记录SR包的发送时间. 记为send_time
B 接收到 A的SR包后, 记录下最后一次接受到SR包的时间. 记为last_recv_time
… (B等待发送rtcp包)
B 发送 RR包, 计算从[last_recv_time] 到 当前时间的延时. 记录为delay_since_last_SR. 附加到RR包中.
A 收到 B的RR包后, 计算RTT
RTT = send_time - delay_since_last_SR - last_recv_time
对应到webrtc中的实现.
何时发送rtcp ? 这里写代码片
ModuleRtpRtcpImpl::Process
if (rtcp_sender_.TimeToSendRTCPReport()) {rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);}
在RTCPSender::TimeToSendRTCPReport 详细说明了RTCP的发送频率.
每次发送RTCP时都会计算出下一次发送rtcp的时间, 即_nextTimeToSendRTCP.
对于 RR和SR包. 计算如下.
RTCPSender::PrepareRTCP
….
if( rtcpPacketTypeFlags & kRtcpRr ||rtcpPacketTypeFlags & kRtcpSr){// generate next time to send a RTCP report// seeded from RTP constructorint32_t random = rand() % 1000;int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS;if(_audio){timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +(RTCP_INTERVAL_AUDIO_MS*random/1000);}else{uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;if(_sending){// Calculate bandwidth for video; 360 / send bandwidth in kbit/s.uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;if (send_bitrate_kbit != 0)minIntervalMs = 360000 / send_bitrate_kbit;}if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS){minIntervalMs = RTCP_INTERVAL_VIDEO_MS;}timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);}_nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;}
依赖于随机值, 而且音视频的时间也不同.
A -> 发送SR包.
ModuleRtpRtcpImpl::Process
RTCPSender::SendRTCP
RTCPSender::PrepareRTCP
RTCPSender::BuildSR
PrepareRTCP 中通过_sending(是否是发送端) 状态判定发送SR或RR. SR包中含有发送时的NTP时间戳.
BuildSR中
_lastSendReport 记录NTP时间的中间32位. 可以标识SR包, 也就是B回应RR包中report block的LSR字段(last SR timestamp ), 通过LSR可以查找_lastRTCPTime.
_lastRTCPTime记录RTCP_NUMBER_OF_SR个数的SR发送时间.
这两个数组是一一对应的.
_lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
_lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
最后SendToNetwork.
B -> 接收到SR包.
ModuleRtpRtcpImpl::IncomingRtcpPacket
RTCPReceiver::IncomingRTCPPacket
RTCPReceiver::HandleSenderReceiverReport
在HandleSenderReceiverReport 中保存 SR包中的NTP时间戳
_remoteSenderInfo.NTPseconds = rtcpPacket.SR.NTPMostSignificant;
_remoteSenderInfo.NTPfraction = rtcpPacket.SR.NTPLeastSignificant;
并记录SR包接到时的NTP时间戳
_clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac);
B -> 发送RR包
获取回馈状态, 并发送给A
ModuleRtpRtcpImpl::Process()
if (rtcp_sender_.TimeToSendRTCPReport()) {rtcp_sender_.SendRTCP(GetFeedbackState(), kRtcpReport);}
ModuleRtpRtcpImpl::GetFeedbackState()
ModuleRtpRtcpImpl::LastReceivedNTP
state.last_rr_ntp_secs 和state.last_rr_ntp_frac
即为上一次接收到SR包时, 记录的_clock->CurrentNtp(_lastReceivedSRNTPsecs, _lastReceivedSRNTPfrac); 时间戳.
state.remote_sr 通过_remoteSenderInfo.NTPseconds 和 _remoteSenderInfo.NTPfraction, 取中间32位算出.
RTCPSender::PrepareReport
在这里计算延时, 填充到report block中.
// get our NTP as late as possible to avoid a race_clock->CurrentNtp(*ntp_secs, *ntp_frac);// Delay since last received reportuint32_t delaySinceLastReceivedSR = 0;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 higest bits of fractionsuint32_t now=*ntp_secs&0x0000FFFF;now <<=16;now += (*ntp_frac&0xffff0000)>>16;uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;receiveTime <<=16;receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;delaySinceLastReceivedSR = now-receiveTime;}report_block->delaySinceLastSR = delaySinceLastReceivedSR;report_block->lastSR = feedback_state.remote_sr;
report_block->delaySinceLastSR 即为 从接到SR包到发送RR包之间的延时.
report_block->lastSR 即SR包中NTP时间戳的中间32位. (在A端_lastSendReport数组中记录).
A 收到 B的RR包
ModuleRtpRtcpImpl::IncomingRtcpPacket
RTCPReceiver::IncomingRTCPPacket
RTCPReceiver::HandleSenderReceiverReport
RTCPReceiver::HandleReportBlock
通过 lastSR 到sender模块中取出SR包的发送时间.
uint32_t sendTimeMS =
_rtpRtcp.SendTimeOfSendReport(rtcpPacket.ReportBlockItem.LastSR);
计算RTT .
uint32_t delaySinceLastSendReport =rtcpPacket.ReportBlockItem.DelayLastSR;// local NTP time when we received thisuint32_t lastReceivedRRNTPsecs = 0;uint32_t lastReceivedRRNTPfrac = 0;_clock->CurrentNtp(lastReceivedRRNTPsecs, lastReceivedRRNTPfrac);// time when we received this in MSuint32_t receiveTimeMS = Clock::NtpToMs(lastReceivedRRNTPsecs,lastReceivedRRNTPfrac);// Estimate RTTuint32_t d = (delaySinceLastSendReport & 0x0000ffff) * 1000;d /= 65536;d += ((delaySinceLastSendReport & 0xffff0000) >> 16) * 1000;int32_t RTT = 0;if (sendTimeMS > 0) {RTT = receiveTimeMS - d - sendTimeMS;....}
注意delay since last SR (DLSR) 的单位是1/65536秒.
二、另外一个问题, 那么如何在B端估算A和B之间的RTT时间?
如果是互相视频聊天的话, A和B都是发送端, 自然都可以计算出RTT.
但是B如果仅仅是接收者的话, 仅仅依靠RFC3550协议是无法计算RTT时间的.
需要参考rfc 3611协议, 实现section4.5 的 DLRR Report Block 即可. http://tools.ietf.org/html/rfc3611#section-4.5
webrtc 在bug 1613 https://code.google.com/p/webrtc/issues/detail?id=1613
中讨论该问题. 并在版本 https://code.google.com/p/webrtc/source/detail?r=4898
和https://code.google.com/p/webrtc/source/detail?r=5063 中修复.
具体实现和SR非常类似.
1. 开启XR协议 ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(true)
webrtc的示例loopback 程序中可以这样启动
receive_config.rtp.rtcp_xr.receiver_reference_time_report = true;
接受者(B)发送RTCP时, 附加kRtcpXrReceiverReferenceTime
发送者(A)发送RTCP时, 附加kRtcpXrDlrrReportBlock
RTCPSender::PrepareRTCP
if (xrSendReceiverReferenceTimeEnabled_ && !_sending){rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;}if (feedback_state.has_last_xr_rr){rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;}
B在发送kRtcpXrReceiverReferenceTime, 在last_xr_rr_ map中记录 NTP时间戳中间32位(key) 和 发送时间(value).
A 收到XR_RR包后
在处理kRtcpXrReceiverReferenceTimeCode
RTCPReceiver::HandleXrReceiveReferenceTime
_remoteXRReceiveTimeInfo.lastRR = RTCPUtility::MidNtp(packet.XRReceiverReferenceTimeItem.NTPMostSignificant,packet.XRReceiverReferenceTimeItem.NTPLeastSignificant);_clock->CurrentNtp(_lastReceivedXRNTPsecs, _lastReceivedXRNTPfrac);
记录lastRR和收到XR_RR包的时间.
A 发送RTCP时, 会检查是否收到过xr_rr包.
ModuleRtpRtcpImpl::GetFeedbackState()
state.has_last_xr_rr = LastReceivedXrReferenceTimeInfo(&state.last_xr_rr);bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(RtcpReceiveTimeInfo* info) const {assert(info);CriticalSectionScoped lock(_criticalSectionRTCPReceiver);if (_lastReceivedXRNTPsecs == 0 && _lastReceivedXRNTPfrac == 0) {return false;}info->sourceSSRC = _remoteXRReceiveTimeInfo.sourceSSRC;info->lastRR = _remoteXRReceiveTimeInfo.lastRR;// Get the delay since last received report (RFC 3611).uint32_t receive_time = RTCPUtility::MidNtp(_lastReceivedXRNTPsecs,_lastReceivedXRNTPfrac);uint32_t ntp_sec = 0;uint32_t ntp_frac = 0;_clock->CurrentNtp(ntp_sec, ntp_frac);uint32_t now = RTCPUtility::MidNtp(ntp_sec, ntp_frac);info->delaySinceLastRR = now - receive_time;return true;}
计算出 从接到last_xr_rr 到当前的延时.
然后发送 kRtcpXrDlrrReportBlock 出去.
B 收到XR_SR后
RTCPReceiver::HandleXrDlrrReportBlock
计算出RTT时间. 保存在xr_rr_rtt_ms_
rtp_rtcp_impl_unittest.cc 测试程序.
TEST_F(RtpRtcpImplTest, RttForReceiverOnly)
http://www.cnblogs.com/lingdhox/p/5746210.html
- [webrtc] rtcp模块中rtt时间计算
- [webrtc] rtcp模块中rtt时间计算
- webrtc中rtcp反馈与码率控制模块分析
- webrtc中rtcp反馈与码率控制模块分析
- WebRTC 中RTT实现方法
- WebRTC中RTP/RTCP协议实现分析
- WebRTC中RTP/RTCP协议实现分析
- WebRTC中RTP/RTCP协议实现分析
- WebRTC中RTP/RTCP协议实现分析
- WebRTC中RTP/RTCP协议实现分析
- WebRTC中RTP/RTCP协议实现分析【转】
- TCP中RTT的测量和RTO的计算
- TCP中RTT的测量和RTO的计算
- TCP中RTT的测量和RTO的计算
- TCP中RTT的测量和RTO的计算
- TCP中RTT的测量和RTO的计算
- TCP中RTT的测量和RTO的计算
- RTT CPU使用率计算
- 高手总结的“恋爱法”学习Linux系统,效果更好。
- 利用virtualbox增强器实现本机与kali linux的文件共享(macOS)
- 第十六周项目1--验证算法--(7)归并排序
- Python----字符编码方法
- gulp入坑系列(2)——初试JS代码合并与压缩
- [webrtc] rtcp模块中rtt时间计算
- 第一次参加全国noi大赛后感受
- 第三章
- 常用概率不等式
- Unicode也是一种字符编码方法,容纳65536个字符
- Tesseract编译安装
- 第十五周oj训练——字符串分段(串)(2279)
- 第十六周项目1--验证算法--(8)基数排序
- Url请求get拼接