• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2012 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 "webrtc/video/call_stats.h"
12 
13 #include <assert.h>
14 
15 #include <algorithm>
16 
17 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
19 #include "webrtc/system_wrappers/include/tick_util.h"
20 
21 namespace webrtc {
22 namespace {
23 // Time interval for updating the observers.
24 const int64_t kUpdateIntervalMs = 1000;
25 // Weight factor to apply to the average rtt.
26 const float kWeightFactor = 0.3f;
27 
RemoveOldReports(int64_t now,std::list<CallStats::RttTime> * reports)28 void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports) {
29   // A rtt report is considered valid for this long.
30   const int64_t kRttTimeoutMs = 1500;
31   while (!reports->empty() &&
32          (now - reports->front().time) > kRttTimeoutMs) {
33     reports->pop_front();
34   }
35 }
36 
GetMaxRttMs(std::list<CallStats::RttTime> * reports)37 int64_t GetMaxRttMs(std::list<CallStats::RttTime>* reports) {
38   int64_t max_rtt_ms = 0;
39   for (std::list<CallStats::RttTime>::const_iterator it = reports->begin();
40        it != reports->end(); ++it) {
41     max_rtt_ms = std::max(it->rtt, max_rtt_ms);
42   }
43   return max_rtt_ms;
44 }
45 
GetAvgRttMs(std::list<CallStats::RttTime> * reports)46 int64_t GetAvgRttMs(std::list<CallStats::RttTime>* reports) {
47   if (reports->empty()) {
48     return 0;
49   }
50   int64_t sum = 0;
51   for (std::list<CallStats::RttTime>::const_iterator it = reports->begin();
52        it != reports->end(); ++it) {
53     sum += it->rtt;
54   }
55   return sum / reports->size();
56 }
57 
UpdateAvgRttMs(std::list<CallStats::RttTime> * reports,int64_t * avg_rtt)58 void UpdateAvgRttMs(std::list<CallStats::RttTime>* reports, int64_t* avg_rtt) {
59   uint32_t cur_rtt_ms = GetAvgRttMs(reports);
60   if (cur_rtt_ms == 0) {
61     // Reset.
62     *avg_rtt = 0;
63     return;
64   }
65   if (*avg_rtt == 0) {
66     // Initialize.
67     *avg_rtt = cur_rtt_ms;
68     return;
69   }
70   *avg_rtt = *avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor;
71 }
72 }  // namespace
73 
74 class RtcpObserver : public RtcpRttStats {
75  public:
RtcpObserver(CallStats * owner)76   explicit RtcpObserver(CallStats* owner) : owner_(owner) {}
~RtcpObserver()77   virtual ~RtcpObserver() {}
78 
OnRttUpdate(int64_t rtt)79   virtual void OnRttUpdate(int64_t rtt) {
80     owner_->OnRttUpdate(rtt);
81   }
82 
83   // Returns the average RTT.
LastProcessedRtt() const84   virtual int64_t LastProcessedRtt() const {
85     return owner_->avg_rtt_ms();
86   }
87 
88  private:
89   CallStats* owner_;
90 
91   RTC_DISALLOW_COPY_AND_ASSIGN(RtcpObserver);
92 };
93 
CallStats(Clock * clock)94 CallStats::CallStats(Clock* clock)
95     : clock_(clock),
96       crit_(CriticalSectionWrapper::CreateCriticalSection()),
97       rtcp_rtt_stats_(new RtcpObserver(this)),
98       last_process_time_(clock_->TimeInMilliseconds()),
99       max_rtt_ms_(0),
100       avg_rtt_ms_(0) {}
101 
~CallStats()102 CallStats::~CallStats() {
103   assert(observers_.empty());
104 }
105 
TimeUntilNextProcess()106 int64_t CallStats::TimeUntilNextProcess() {
107   return last_process_time_ + kUpdateIntervalMs - clock_->TimeInMilliseconds();
108 }
109 
Process()110 int32_t CallStats::Process() {
111   CriticalSectionScoped cs(crit_.get());
112   int64_t now = clock_->TimeInMilliseconds();
113   if (now < last_process_time_ + kUpdateIntervalMs)
114     return 0;
115 
116   last_process_time_ = now;
117 
118   RemoveOldReports(now, &reports_);
119   max_rtt_ms_ = GetMaxRttMs(&reports_);
120   UpdateAvgRttMs(&reports_, &avg_rtt_ms_);
121 
122   // If there is a valid rtt, update all observers with the max rtt.
123   // TODO(asapersson): Consider changing this to report the average rtt.
124   if (max_rtt_ms_ > 0) {
125     for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
126          it != observers_.end(); ++it) {
127       (*it)->OnRttUpdate(avg_rtt_ms_, max_rtt_ms_);
128     }
129   }
130   return 0;
131 }
132 
avg_rtt_ms() const133 int64_t CallStats::avg_rtt_ms() const {
134   CriticalSectionScoped cs(crit_.get());
135   return avg_rtt_ms_;
136 }
137 
rtcp_rtt_stats() const138 RtcpRttStats* CallStats::rtcp_rtt_stats() const {
139   return rtcp_rtt_stats_.get();
140 }
141 
RegisterStatsObserver(CallStatsObserver * observer)142 void CallStats::RegisterStatsObserver(CallStatsObserver* observer) {
143   CriticalSectionScoped cs(crit_.get());
144   for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
145        it != observers_.end(); ++it) {
146     if (*it == observer)
147       return;
148   }
149   observers_.push_back(observer);
150 }
151 
DeregisterStatsObserver(CallStatsObserver * observer)152 void CallStats::DeregisterStatsObserver(CallStatsObserver* observer) {
153   CriticalSectionScoped cs(crit_.get());
154   for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
155        it != observers_.end(); ++it) {
156     if (*it == observer) {
157       observers_.erase(it);
158       return;
159     }
160   }
161 }
162 
OnRttUpdate(int64_t rtt)163 void CallStats::OnRttUpdate(int64_t rtt) {
164   CriticalSectionScoped cs(crit_.get());
165   reports_.push_back(RttTime(rtt, clock_->TimeInMilliseconds()));
166 }
167 
168 }  // namespace webrtc
169