• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "video/call_stats2.h"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <utility>
16 
17 #include "absl/algorithm/container.h"
18 #include "rtc_base/checks.h"
19 #include "system_wrappers/include/metrics.h"
20 
21 namespace webrtc {
22 namespace internal {
23 namespace {
24 
RemoveOldReports(int64_t now,std::list<CallStats::RttTime> * reports)25 void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports) {
26   static constexpr const int64_t kRttTimeoutMs = 1500;
27   reports->remove_if(
28       [&now](CallStats::RttTime& r) { return now - r.time > kRttTimeoutMs; });
29 }
30 
GetMaxRttMs(const std::list<CallStats::RttTime> & reports)31 int64_t GetMaxRttMs(const std::list<CallStats::RttTime>& reports) {
32   int64_t max_rtt_ms = -1;
33   for (const CallStats::RttTime& rtt_time : reports)
34     max_rtt_ms = std::max(rtt_time.rtt, max_rtt_ms);
35   return max_rtt_ms;
36 }
37 
GetAvgRttMs(const std::list<CallStats::RttTime> & reports)38 int64_t GetAvgRttMs(const std::list<CallStats::RttTime>& reports) {
39   RTC_DCHECK(!reports.empty());
40   int64_t sum = 0;
41   for (std::list<CallStats::RttTime>::const_iterator it = reports.begin();
42        it != reports.end(); ++it) {
43     sum += it->rtt;
44   }
45   return sum / reports.size();
46 }
47 
GetNewAvgRttMs(const std::list<CallStats::RttTime> & reports,int64_t prev_avg_rtt)48 int64_t GetNewAvgRttMs(const std::list<CallStats::RttTime>& reports,
49                        int64_t prev_avg_rtt) {
50   if (reports.empty())
51     return -1;  // Reset (invalid average).
52 
53   int64_t cur_rtt_ms = GetAvgRttMs(reports);
54   if (prev_avg_rtt == -1)
55     return cur_rtt_ms;  // New initial average value.
56 
57   // Weight factor to apply to the average rtt.
58   // We weigh the old average at 70% against the new average (30%).
59   constexpr const float kWeightFactor = 0.3f;
60   return prev_avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor;
61 }
62 
63 }  // namespace
64 
65 constexpr TimeDelta CallStats::kUpdateInterval;
66 
CallStats(Clock * clock,TaskQueueBase * task_queue)67 CallStats::CallStats(Clock* clock, TaskQueueBase* task_queue)
68     : clock_(clock),
69       max_rtt_ms_(-1),
70       avg_rtt_ms_(-1),
71       sum_avg_rtt_ms_(0),
72       num_avg_rtt_(0),
73       time_of_first_rtt_ms_(-1),
74       task_queue_(task_queue) {
75   RTC_DCHECK(task_queue_);
76   RTC_DCHECK_RUN_ON(task_queue_);
77 }
78 
~CallStats()79 CallStats::~CallStats() {
80   RTC_DCHECK_RUN_ON(task_queue_);
81   RTC_DCHECK(observers_.empty());
82 
83   repeating_task_.Stop();
84 
85   UpdateHistograms();
86 }
87 
EnsureStarted()88 void CallStats::EnsureStarted() {
89   RTC_DCHECK_RUN_ON(task_queue_);
90   repeating_task_ =
91       RepeatingTaskHandle::DelayedStart(task_queue_, kUpdateInterval, [this]() {
92         UpdateAndReport();
93         return kUpdateInterval;
94       });
95 }
96 
UpdateAndReport()97 void CallStats::UpdateAndReport() {
98   RTC_DCHECK_RUN_ON(task_queue_);
99 
100   RemoveOldReports(clock_->CurrentTime().ms(), &reports_);
101   max_rtt_ms_ = GetMaxRttMs(reports_);
102   avg_rtt_ms_ = GetNewAvgRttMs(reports_, avg_rtt_ms_);
103 
104   // If there is a valid rtt, update all observers with the max rtt.
105   if (max_rtt_ms_ >= 0) {
106     RTC_DCHECK_GE(avg_rtt_ms_, 0);
107     for (CallStatsObserver* observer : observers_)
108       observer->OnRttUpdate(avg_rtt_ms_, max_rtt_ms_);
109     // Sum for Histogram of average RTT reported over the entire call.
110     sum_avg_rtt_ms_ += avg_rtt_ms_;
111     ++num_avg_rtt_;
112   }
113 }
114 
RegisterStatsObserver(CallStatsObserver * observer)115 void CallStats::RegisterStatsObserver(CallStatsObserver* observer) {
116   RTC_DCHECK_RUN_ON(task_queue_);
117   if (!absl::c_linear_search(observers_, observer))
118     observers_.push_back(observer);
119 }
120 
DeregisterStatsObserver(CallStatsObserver * observer)121 void CallStats::DeregisterStatsObserver(CallStatsObserver* observer) {
122   RTC_DCHECK_RUN_ON(task_queue_);
123   observers_.remove(observer);
124 }
125 
LastProcessedRtt() const126 int64_t CallStats::LastProcessedRtt() const {
127   RTC_DCHECK_RUN_ON(task_queue_);
128   // No need for locking since we're on the construction thread.
129   return avg_rtt_ms_;
130 }
131 
OnRttUpdate(int64_t rtt)132 void CallStats::OnRttUpdate(int64_t rtt) {
133   // This callback may for some RtpRtcp module instances (video send stream) be
134   // invoked from a separate task queue, in other cases, we should already be
135   // on the correct TQ.
136   int64_t now_ms = clock_->TimeInMilliseconds();
137   auto update = [this, rtt, now_ms]() {
138     RTC_DCHECK_RUN_ON(task_queue_);
139     reports_.push_back(RttTime(rtt, now_ms));
140     if (time_of_first_rtt_ms_ == -1)
141       time_of_first_rtt_ms_ = now_ms;
142     UpdateAndReport();
143   };
144 
145   if (task_queue_->IsCurrent()) {
146     update();
147   } else {
148     task_queue_->PostTask(SafeTask(task_safety_.flag(), std::move(update)));
149   }
150 }
151 
UpdateHistograms()152 void CallStats::UpdateHistograms() {
153   RTC_DCHECK_RUN_ON(task_queue_);
154 
155   if (time_of_first_rtt_ms_ == -1 || num_avg_rtt_ < 1)
156     return;
157 
158   int64_t elapsed_sec =
159       (clock_->TimeInMilliseconds() - time_of_first_rtt_ms_) / 1000;
160   if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
161     int64_t avg_rtt_ms = (sum_avg_rtt_ms_ + num_avg_rtt_ / 2) / num_avg_rtt_;
162     RTC_HISTOGRAM_COUNTS_10000(
163         "WebRTC.Video.AverageRoundTripTimeInMilliseconds", avg_rtt_ms);
164   }
165 }
166 
167 }  // namespace internal
168 }  // namespace webrtc
169