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_engine/call_stats.h" 12 13 #include <assert.h> 14 15 #include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h" 16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 17 #include "webrtc/system_wrappers/interface/tick_util.h" 18 19 namespace webrtc { 20 21 // A rtt report is considered valid for this long. 22 const int kRttTimeoutMs = 1500; 23 // Time interval for updating the observers. 24 const int kUpdateIntervalMs = 1000; 25 26 class RtcpObserver : public RtcpRttStats { 27 public: 28 explicit RtcpObserver(CallStats* owner) : owner_(owner) {} 29 virtual ~RtcpObserver() {} 30 31 virtual void OnRttUpdate(uint32_t rtt) { 32 owner_->OnRttUpdate(rtt); 33 } 34 35 virtual uint32_t LastProcessedRtt() const { 36 return owner_->last_processed_rtt_ms(); 37 } 38 39 private: 40 CallStats* owner_; 41 42 DISALLOW_COPY_AND_ASSIGN(RtcpObserver); 43 }; 44 45 CallStats::CallStats() 46 : crit_(CriticalSectionWrapper::CreateCriticalSection()), 47 rtcp_rtt_stats_(new RtcpObserver(this)), 48 last_process_time_(TickTime::MillisecondTimestamp()), 49 last_processed_rtt_ms_(0) { 50 } 51 52 CallStats::~CallStats() { 53 assert(observers_.empty()); 54 } 55 56 int32_t CallStats::TimeUntilNextProcess() { 57 return last_process_time_ + kUpdateIntervalMs - 58 TickTime::MillisecondTimestamp(); 59 } 60 61 int32_t CallStats::Process() { 62 CriticalSectionScoped cs(crit_.get()); 63 if (TickTime::MillisecondTimestamp() < last_process_time_ + kUpdateIntervalMs) 64 return 0; 65 66 // Remove invalid, as in too old, rtt values. 67 int64_t time_now = TickTime::MillisecondTimestamp(); 68 while (!reports_.empty() && reports_.front().time + kRttTimeoutMs < 69 time_now) { 70 reports_.pop_front(); 71 } 72 73 // Find the max stored RTT. 74 uint32_t max_rtt = 0; 75 for (std::list<RttTime>::const_iterator it = reports_.begin(); 76 it != reports_.end(); ++it) { 77 if (it->rtt > max_rtt) 78 max_rtt = it->rtt; 79 } 80 81 // If there is a valid rtt, update all observers. 82 if (max_rtt > 0) { 83 for (std::list<CallStatsObserver*>::iterator it = observers_.begin(); 84 it != observers_.end(); ++it) { 85 (*it)->OnRttUpdate(max_rtt); 86 } 87 } 88 last_processed_rtt_ms_ = max_rtt; 89 last_process_time_ = time_now; 90 return 0; 91 } 92 93 uint32_t CallStats::last_processed_rtt_ms() const { 94 CriticalSectionScoped cs(crit_.get()); 95 return last_processed_rtt_ms_; 96 } 97 98 RtcpRttStats* CallStats::rtcp_rtt_stats() const { 99 return rtcp_rtt_stats_.get(); 100 } 101 102 void CallStats::RegisterStatsObserver(CallStatsObserver* observer) { 103 CriticalSectionScoped cs(crit_.get()); 104 for (std::list<CallStatsObserver*>::iterator it = observers_.begin(); 105 it != observers_.end(); ++it) { 106 if (*it == observer) 107 return; 108 } 109 observers_.push_back(observer); 110 } 111 112 void CallStats::DeregisterStatsObserver(CallStatsObserver* observer) { 113 CriticalSectionScoped cs(crit_.get()); 114 for (std::list<CallStatsObserver*>::iterator it = observers_.begin(); 115 it != observers_.end(); ++it) { 116 if (*it == observer) { 117 observers_.erase(it); 118 return; 119 } 120 } 121 } 122 123 void CallStats::OnRttUpdate(uint32_t rtt) { 124 CriticalSectionScoped cs(crit_.get()); 125 int64_t time_now = TickTime::MillisecondTimestamp(); 126 reports_.push_back(RttTime(rtt, time_now)); 127 } 128 129 } // namespace webrtc 130