在之前的文章:WebRTC研究:rrt 时间 之 再次处理以供重传等功能使用 中讲到,ModuleRtpRtcpImpl::Process() 会将 RRT 时间与当前时间一起存入 CallStats 对象的 reports_ 集合中,然后由 CallStats.Process() 计算出重传等应用中所使用到的 avg_rtt_ms_ 与 max_rtt_ms_,那么本篇文章将会介绍此部分计算逻辑。
Call::Call(const Call::Config& config)
: module_process_thread_(ProcessThread::Create("ModuleProcessThread")),
call_stats_(new CallStats(clock_)),
...
...
...
{
...
...
...
module_process_thread_->Start();
module_process_thread_->RegisterModule(call_stats_.get());
...
...
...
}
void ProcessThreadImpl::RegisterModule(Module* module)
{
...
...
...
{
// 将 CallStats 对象添加到集合 modules_
rtc::CritScope lock(&lock_);
modules_.push_back(ModuleCallback(module));
}
// 唤醒当前线程
wake_up_->Set();
}
bool ProcessThreadImpl::Process()
{
int64_t now = rtc::TimeMillis();
/*
当前线程在本次处理完毕后,进入 wait 状态的持续时长
默认为 60s
*/
int64_t next_checkpoint = now + (1000 * 60);
{
rtc::CritScope lock(&lock_);
if (stop_)
return false;
for (ModuleCallback& m : modules_)
{
// 初始化模块下次处理时间
if (m.next_callback == 0)
m.next_callback = GetNextCallbackTime(m.module, now);
// 判断模块处理时间是否到了
if (m.next_callback <= now || m.next_callback == kCallProcessImmediately)
{
m.module->Process();
// 计算模块下次处理时间
int64_t new_now = rtc::TimeMillis();
m.next_callback = GetNextCallbackTime(m.module, new_now);
}
/*
若某模块下次处理时间在当前线程唤醒之前,则调整当前线程 wait 状态的持续时长
*/
if (m.next_callback < next_checkpoint)
next_checkpoint = m.next_callback;
}
...
...
...
}
/* 计算当前线程 wait 状态的持续时长 */
int64_t time_to_wait = next_checkpoint - rtc::TimeMillis();
if (time_to_wait > 0)
wake_up_->Wait(static_cast<unsigned long>(time_to_wait)); /* 进入 wait 状态*/
return true;
}
int64_t CallStats::TimeUntilNextProcess()
{
/*
last_process_time_:上次进入 Process() 的时间
kUpdateIntervalMs = 1000
理论上是,在本次调用 Process() 之后,需等待 1s,然后再次执行 Process()
last_process_time_ + kUpdateIntervalMs,就是下一次准备开始调用 Process() 的理论时间,
但是由于调用 CallStats.Process() 本身存在耗时,因此实际间隔时间需要减掉这部分耗时
*/
return last_process_time_ + kUpdateIntervalMs - clock_->TimeInMilliseconds();
}
void CallStats::Process()
{
rtc::CritScope cs(&crit_);
int64_t now = clock_->TimeInMilliseconds();
/* 本次处理时间还未到,直接返回 */
if (now < last_process_time_ + kUpdateIntervalMs)
return;
/* 记录本次处理时间 */
last_process_time_ = now;
/*
剔除 list:reports_ 中太久的数据,判断标准:
当前时间 距离 rrt 添加到 list 中的时间 超过 1500 ms
*/
RemoveOldReports(now, &reports_);
// 获取 list:reports_ 中 最大的 rrt 时间
max_rtt_ms_ = GetMaxRttMs(&reports_);
/*
计算最新的 avg_rtt_ms_,
最新 avg_rtt_ms_ 为 当前 avg_rtt_ms_ 与 list:reports_ 中 rrt平均值的加权和,权重分别为 70%、30%
*/
UpdateAvgRttMs(&reports_, &avg_rtt_ms_);
// 将 avg_rtt_ms_ 、max_rtt_ms_ 更新到所有 observers
if (max_rtt_ms_ >= 0)
{
RTC_DCHECK_GE(avg_rtt_ms_, 0);
for (std::list<CallStatsObserver*>::iterator it = observers_.begin(); it != observers_.end(); ++it)
{
(*it)->OnRttUpdate(avg_rtt_ms_, max_rtt_ms_);
}
// 累加历代所有 avg_rtt_ms_ 及 个数
sum_avg_rtt_ms_ += avg_rtt_ms_;
++num_avg_rtt_;
}
}
剔除 reports_ 中距离当前时间超过 1500ms 的 rrt 节点:
void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports)
{
const int64_t kRttTimeoutMs = 1500;
while (!reports->empty() && (now - reports->front().time) > kRttTimeoutMs)
{
reports->pop_front();
}
}
计算最新的 max_rtt_ms_:
int64_t GetMaxRttMs(std::list<CallStats::RttTime>* reports)
{
if (reports->empty())
return -1;
int64_t max_rtt_ms = 0;
for (const CallStats::RttTime& rtt_time : *reports)
max_rtt_ms = std::max(rtt_time.rtt, max_rtt_ms);
return max_rtt_ms;
}
计算 reports_ 中 rrt 时间的平均值:
int64_t GetAvgRttMs(std::list<CallStats::RttTime>* reports)
{
if (reports->empty())
{
return -1;
}
int64_t sum = 0;
for (std::list<CallStats::RttTime>::const_iterator it = reports->begin(); it != reports->end(); ++it)
{
sum += it->rtt;
}
return sum / reports->size();
}
计算最新的 avg_rtt_ms_:
void UpdateAvgRttMs(std::list<CallStats::RttTime>* reports, int64_t* avg_rtt)
{
/* 获取 list:reports_ 中 rrt 时间的平均值 */
int64_t cur_rtt_ms = GetAvgRttMs(reports);
// list:reports_ 为空,获取 rrt 平均值失败
if (cur_rtt_ms == -1)
{
// Reset.
*avg_rtt = -1;
return;
}
if (*avg_rtt == -1)
{
// 第一次获取 avg_rtt,直接初始化 avg_rtt,
*avg_rtt = cur_rtt_ms;
return;
}
/* 新 avg_rtt 由 旧 avg_rtt(70%) 和 本次计算的平均值(30%) 的加权和构成 */
*avg_rtt = *avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor;
}