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 19namespace webrtc { 20 21// A rtt report is considered valid for this long. 22const int kRttTimeoutMs = 1500; 23// Time interval for updating the observers. 24const int kUpdateIntervalMs = 1000; 25 26class 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 45CallStats::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 52CallStats::~CallStats() { 53 assert(observers_.empty()); 54} 55 56int32_t CallStats::TimeUntilNextProcess() { 57 return last_process_time_ + kUpdateIntervalMs - 58 TickTime::MillisecondTimestamp(); 59} 60 61int32_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 93uint32_t CallStats::last_processed_rtt_ms() const { 94 CriticalSectionScoped cs(crit_.get()); 95 return last_processed_rtt_ms_; 96} 97 98RtcpRttStats* CallStats::rtcp_rtt_stats() const { 99 return rtcp_rtt_stats_.get(); 100} 101 102void 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 112void 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 123void 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