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