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 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 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 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 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: 76 explicit RtcpObserver(CallStats* owner) : owner_(owner) {} 77 virtual ~RtcpObserver() {} 78 79 virtual void OnRttUpdate(int64_t rtt) { 80 owner_->OnRttUpdate(rtt); 81 } 82 83 // Returns the average RTT. 84 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 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 102 CallStats::~CallStats() { 103 assert(observers_.empty()); 104 } 105 106 int64_t CallStats::TimeUntilNextProcess() { 107 return last_process_time_ + kUpdateIntervalMs - clock_->TimeInMilliseconds(); 108 } 109 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 133 int64_t CallStats::avg_rtt_ms() const { 134 CriticalSectionScoped cs(crit_.get()); 135 return avg_rtt_ms_; 136 } 137 138 RtcpRttStats* CallStats::rtcp_rtt_stats() const { 139 return rtcp_rtt_stats_.get(); 140 } 141 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 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 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