Home | History | Annotate | Download | only in video
      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