Line data Source code
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 <algorithm>
14 :
15 : #include "webrtc/base/checks.h"
16 : #include "webrtc/base/constructormagic.h"
17 : #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
18 : #include "webrtc/system_wrappers/include/metrics.h"
19 :
20 : namespace webrtc {
21 : namespace {
22 : // Time interval for updating the observers.
23 : const int64_t kUpdateIntervalMs = 1000;
24 : // Weight factor to apply to the average rtt.
25 : const float kWeightFactor = 0.3f;
26 :
27 0 : void RemoveOldReports(int64_t now, std::list<CallStats::RttTime>* reports) {
28 : // A rtt report is considered valid for this long.
29 0 : const int64_t kRttTimeoutMs = 1500;
30 0 : while (!reports->empty() &&
31 0 : (now - reports->front().time) > kRttTimeoutMs) {
32 0 : reports->pop_front();
33 : }
34 0 : }
35 :
36 0 : int64_t GetMaxRttMs(std::list<CallStats::RttTime>* reports) {
37 0 : if (reports->empty())
38 0 : return -1;
39 0 : int64_t max_rtt_ms = 0;
40 0 : for (const CallStats::RttTime& rtt_time : *reports)
41 0 : max_rtt_ms = std::max(rtt_time.rtt, max_rtt_ms);
42 0 : return max_rtt_ms;
43 : }
44 :
45 0 : int64_t GetAvgRttMs(std::list<CallStats::RttTime>* reports) {
46 0 : if (reports->empty()) {
47 0 : return -1;
48 : }
49 0 : int64_t sum = 0;
50 0 : for (std::list<CallStats::RttTime>::const_iterator it = reports->begin();
51 0 : it != reports->end(); ++it) {
52 0 : sum += it->rtt;
53 : }
54 0 : return sum / reports->size();
55 : }
56 :
57 0 : void UpdateAvgRttMs(std::list<CallStats::RttTime>* reports, int64_t* avg_rtt) {
58 0 : int64_t cur_rtt_ms = GetAvgRttMs(reports);
59 0 : if (cur_rtt_ms == -1) {
60 : // Reset.
61 0 : *avg_rtt = -1;
62 0 : return;
63 : }
64 0 : if (*avg_rtt == -1) {
65 : // Initialize.
66 0 : *avg_rtt = cur_rtt_ms;
67 0 : return;
68 : }
69 0 : *avg_rtt = *avg_rtt * (1.0f - kWeightFactor) + cur_rtt_ms * kWeightFactor;
70 : }
71 : } // namespace
72 :
73 : class RtcpObserver : public RtcpRttStats {
74 : public:
75 0 : explicit RtcpObserver(CallStats* owner) : owner_(owner) {}
76 0 : virtual ~RtcpObserver() {}
77 :
78 0 : virtual void OnRttUpdate(int64_t rtt) {
79 0 : owner_->OnRttUpdate(rtt);
80 0 : }
81 :
82 : // Returns the average RTT.
83 0 : virtual int64_t LastProcessedRtt() const {
84 0 : return owner_->avg_rtt_ms();
85 : }
86 :
87 : private:
88 : CallStats* owner_;
89 :
90 : RTC_DISALLOW_COPY_AND_ASSIGN(RtcpObserver);
91 : };
92 :
93 0 : CallStats::CallStats(Clock* clock)
94 : : clock_(clock),
95 0 : rtcp_rtt_stats_(new RtcpObserver(this)),
96 0 : last_process_time_(clock_->TimeInMilliseconds()),
97 : max_rtt_ms_(-1),
98 : avg_rtt_ms_(-1),
99 : sum_avg_rtt_ms_(0),
100 : num_avg_rtt_(0),
101 0 : time_of_first_rtt_ms_(-1) {}
102 :
103 0 : CallStats::~CallStats() {
104 0 : RTC_DCHECK(observers_.empty());
105 0 : UpdateHistograms();
106 0 : }
107 :
108 0 : int64_t CallStats::TimeUntilNextProcess() {
109 0 : return last_process_time_ + kUpdateIntervalMs - clock_->TimeInMilliseconds();
110 : }
111 :
112 0 : void CallStats::Process() {
113 0 : rtc::CritScope cs(&crit_);
114 0 : int64_t now = clock_->TimeInMilliseconds();
115 0 : if (now < last_process_time_ + kUpdateIntervalMs)
116 0 : return;
117 :
118 0 : last_process_time_ = now;
119 :
120 0 : RemoveOldReports(now, &reports_);
121 0 : max_rtt_ms_ = GetMaxRttMs(&reports_);
122 0 : UpdateAvgRttMs(&reports_, &avg_rtt_ms_);
123 :
124 : // If there is a valid rtt, update all observers with the max rtt.
125 0 : if (max_rtt_ms_ >= 0) {
126 0 : RTC_DCHECK_GE(avg_rtt_ms_, 0);
127 0 : for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
128 0 : it != observers_.end(); ++it) {
129 0 : (*it)->OnRttUpdate(avg_rtt_ms_, max_rtt_ms_);
130 : }
131 : // Sum for Histogram of average RTT reported over the entire call.
132 0 : sum_avg_rtt_ms_ += avg_rtt_ms_;
133 0 : ++num_avg_rtt_;
134 : }
135 : }
136 :
137 0 : int64_t CallStats::avg_rtt_ms() const {
138 0 : rtc::CritScope cs(&crit_);
139 0 : return avg_rtt_ms_;
140 : }
141 :
142 0 : RtcpRttStats* CallStats::rtcp_rtt_stats() const {
143 0 : return rtcp_rtt_stats_.get();
144 : }
145 :
146 0 : void CallStats::RegisterStatsObserver(CallStatsObserver* observer) {
147 0 : rtc::CritScope cs(&crit_);
148 0 : for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
149 0 : it != observers_.end(); ++it) {
150 0 : if (*it == observer)
151 0 : return;
152 : }
153 0 : observers_.push_back(observer);
154 : }
155 :
156 0 : void CallStats::DeregisterStatsObserver(CallStatsObserver* observer) {
157 0 : rtc::CritScope cs(&crit_);
158 0 : for (std::list<CallStatsObserver*>::iterator it = observers_.begin();
159 0 : it != observers_.end(); ++it) {
160 0 : if (*it == observer) {
161 0 : observers_.erase(it);
162 0 : return;
163 : }
164 : }
165 : }
166 :
167 0 : void CallStats::OnRttUpdate(int64_t rtt) {
168 0 : rtc::CritScope cs(&crit_);
169 0 : int64_t now_ms = clock_->TimeInMilliseconds();
170 0 : reports_.push_back(RttTime(rtt, now_ms));
171 0 : if (time_of_first_rtt_ms_ == -1)
172 0 : time_of_first_rtt_ms_ = now_ms;
173 0 : }
174 :
175 0 : void CallStats::UpdateHistograms() {
176 0 : rtc::CritScope cs(&crit_);
177 0 : if (time_of_first_rtt_ms_ == -1 || num_avg_rtt_ < 1)
178 0 : return;
179 :
180 : int64_t elapsed_sec =
181 0 : (clock_->TimeInMilliseconds() - time_of_first_rtt_ms_) / 1000;
182 0 : if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
183 0 : int64_t avg_rtt_ms = (sum_avg_rtt_ms_ + num_avg_rtt_ / 2) / num_avg_rtt_;
184 0 : RTC_HISTOGRAM_COUNTS_10000(
185 : "WebRTC.Video.AverageRoundTripTimeInMilliseconds", avg_rtt_ms);
186 : }
187 : }
188 :
189 : } // namespace webrtc
|