一、ModuleRtpRtcpImpl::Process() 会定时处理 SR/RR 包发送、bitrate、rrt 等事宜,处理时间间隔为 5 ms:
int64_t ModuleRtpRtcpImpl::TimeUntilNextProcess()
{
/*
last_process_time_:上次调用 Process() 的开始时间
理论上是,在本次调用 Process() 之后,需等待 5ms,然后再次执行 Process()
但是由于调用 Process() 本身存在耗时,因此实际等待时间需要减掉这部分耗时
*/
const int64_t now = clock_->TimeInMilliseconds();
const int64_t kRtpRtcpMaxIdleTimeProcessMs = 5;
return kRtpRtcpMaxIdleTimeProcessMs - (now - last_process_time_);
}
二、发送 SR / RR 包
对于 audio,发送 SR / RR 包的时间间隔为 [1/2 * 5000, 3/2 * 5000] ms 之间的一个随机数:
void ModuleRtpRtcpImpl::Process()
{
...
...
...
/*
判断发送 RTP 包的时间是否到达
*/
if (rtcp_sender_.TimeToSendRTCPReport())
{
/*
获取 最近收到的 SR 包中所携带的 NTP 时间戳、收到 SR 包时本地时间戳等信息
*/
RTCPSender::FeedbackState state = GetFeedbackState();
// Prevent sending streams to send SR before any media has been sent.
if (!rtcp_sender_.Sending() || state.packets_sent > 0)
rtcp_sender_.SendRTCP(state, kRtcpReport); /* 发送RTP包 并计算下一次发送 RTP包的时间 */
}
...
...
...
}
三、获取最近收到的 SR 包中所携带的 NTP 时间戳、收到 SR 包时本地时间戳等信息:
RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState()
{
...
...
...
/*
remote_sr:最近收到的 SR 包中所携带的 NTP 时间戳的中间32位
last_rr_ntp_secs / last_rr_ntp_frac:最近收到 SR 包时的当前时间戳
*/
LastReceivedNTP(&state.last_rr_ntp_secs,
&state.last_rr_ntp_frac,
&state.remote_sr);
...
...
...
}
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 = ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16);
return true;
}
_remoteSenderInfo.NTPseconds 与 _remoteSenderInfo.NTPfraction:最近收到的 SR 包中所携带的 NTP 时间戳。
_lastReceivedSRNTPfrac 与 _lastReceivedSRNTPsecs:最近收到 SR 包时的本地时间戳。
具体来源,参考前一篇文章:WebRTC研究:rrt 时间计算 之 接收 SR 包
// TODO(pbos): Make this fail when we haven't received NTP.
bool RTCPReceiver::NTP(uint32_t* ReceivedNTPsecs,
uint32_t* ReceivedNTPfrac,
uint32_t* RTCPArrivalTimeSecs,
uint32_t* RTCPArrivalTimeFrac,
uint32_t* rtcp_timestamp) const
{
rtc::CritScope lock(&_criticalSectionRTCPReceiver);
if(ReceivedNTPsecs)
{
*ReceivedNTPsecs = _remoteSenderInfo.NTPseconds; // SR 包所携带 NTP 时间戳
}
if(ReceivedNTPfrac)
{
*ReceivedNTPfrac = _remoteSenderInfo.NTPfraction;
}
if(RTCPArrivalTimeFrac)
{
*RTCPArrivalTimeFrac = _lastReceivedSRNTPfrac; // 接收到 SR 包时的当前 NTP 时间戳
}
if(RTCPArrivalTimeSecs)
{
*RTCPArrivalTimeSecs = _lastReceivedSRNTPsecs;
}
if (rtcp_timestamp)
{
*rtcp_timestamp = _remoteSenderInfo.RTPtimeStamp;
}
return true;
}
四、PrepareReport() 会根据字段 sending_(是否发送端)的值,判定发送 SR 还是 RR 包:
void RTCPSender::PrepareReport(const std::set<RTCPPacketType>& packetTypes,
const FeedbackState& feedback_state)
{
...
...
...
/*
根据 sending_(是否发送端)判定发送 SR 或 RR 包
SetFlag():将 flag:kRtcpSr 或 kRtcpRr 存入 集合 report_flags_,节点内部字段:is_volatile 的值设置为 true。
*/
if (generate_report)
SetFlag(sending_ ? kRtcpSr : kRtcpRr, true);
...
...
...
/*
计算下次发送 RTCP 的时间,每次时间间隔不一,
对于 audio,时间间隔是 [1/2 * 5000, 3/2 * 5000] ms之间的一个随机数
*/
uint32_t timeToNext = random_.Rand(minIntervalMs * 1 / 2, minIntervalMs * 3 / 2);
next_time_to_send_rtcp_ = clock_->TimeInMilliseconds() + timeToNext;
/*
AddReportBlock()会设置两个关键值:
last_sr_:SR 包中 NTP 时间戳的中间32位
delay_since_last_sr_:从收到 SR包 到发送 RR包 之间的延时
*/
if (receive_statistics_)
{
StatisticianMap statisticians = receive_statistics_->GetActiveStatisticians();
RTC_DCHECK(report_blocks_.empty());
for (auto& it : statisticians)
{
AddReportBlock(feedback_state, it.first, it.second);
}
}
...
...
...
}
五、设置 last_sr_(SR 包中 NTP 时间戳的中间32位)与 delay_since_last_sr_(从 接到SR包 到 发送RR包 之间的延时):
bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state,
uint32_t ssrc,
StreamStatistician* statistician)
{
...
...
...
rtcp::ReportBlock* block = &report_blocks_[ssrc];
/* 设置 last_sr_,即为 SR 包中 NTP 时间戳的中间32位 */
block->WithLastSr(feedback_state.remote_sr);
// 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 = 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;
/* 设置 delay_since_last_sr_,即为 从接到SR包 到发送RR包 之间的延时 */
block->WithDelayLastSr(now - receiveTime);
}
return true;
...
...
...
}
六、根据发送 SR 包还是RR 包,调用不同的包封装函数:
int32_t RTCPSender::SendCompoundRTCP(
const FeedbackState& feedback_state,
const std::set<RTCPPacketType>& packet_types,
int32_t nack_size,
const uint16_t* nack_list,
bool repeat,
uint64_t pictureID)
{
...
...
...
// 获取当前 NTP 时间戳
uint32_t ntp_sec;
uint32_t ntp_frac;
clock_->CurrentNtp(ntp_sec, ntp_frac);
RtcpContext context(feedback_state, nack_size, nack_list, repeat, pictureID,
ntp_sec, ntp_frac);
// 判断是发送 SR 包还是RR 包,并设置 last_sr_ 与 delay_since_last_sr_
PrepareReport(packet_types, feedback_state);
std::unique_ptr<rtcp::RtcpPacket> packet_bye;
// 封装包
auto it = report_flags_.begin();
while (it != report_flags_.end())
{
auto builder_it = builders_.find(it->type);
RTC_DCHECK(builder_it != builders_.end());
if (it->is_volatile)
{
report_flags_.erase(it++);
}
else
{
++it;
}
/*
根据 flag 调用对应的包封装函数:
kRtcpSr:RTCPSender::BuildSR
kRtcpRr:RTCPSender::BuildRR
*/
BuilderFunc func = builder_it->second;
std::unique_ptr<rtcp::RtcpPacket> packet = (this->*func)(context);
...
...
...
}
// 发送包
size_t bytes_sent = container.SendPackets(max_payload_length_);
return bytes_sent == 0 ? -1 : 0;
}
七、封装 SR 包:
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildSR(const RtcpContext& ctx)
{
...
...
...
/* 封装当前 NTP 时间戳 */
report->WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
report->WithRtpTimestamp(rtp_timestamp);
...
...
...
}
八、封装 RR 包:
直接使用 map 对象 report_blocks_ 构造包:
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildRR(const RtcpContext& ctx)
{
rtcp::ReceiverReport* report = new rtcp::ReceiverReport();
report->From(ssrc_);
for (auto it : report_blocks_)
report->WithReportBlock(it.second);
report_blocks_.clear();
return std::unique_ptr<rtcp::RtcpPacket>(report);
}