blob: cf277e3f8a1d90cddf4cb176163877058c0c18ba [file] [log] [blame]
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001/*
2 * Copyright (c) 2013 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/send_statistics_proxy.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000012
asaperssond89920b2015-07-22 06:52:00 -070013#include <algorithm>
Tim Psiakiad13d2f2015-11-10 16:34:50 -080014#include <cmath>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000015#include <map>
asapersson58d992e2016-03-29 02:15:06 -070016#include <vector>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000017
Mirko Bonadei71207422017-09-15 13:58:09 +020018#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/include/video_codec_interface.h"
20#include "rtc_base/checks.h"
21#include "rtc_base/logging.h"
asapersson8d75ac72017-09-15 06:41:15 -070022#include "system_wrappers/include/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000024
25namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070026namespace {
asapersson1aa420b2015-12-07 03:12:22 -080027const float kEncodeTimeWeigthFactor = 0.5f;
Åsa Persson0122e842017-10-16 12:19:23 +020028const size_t kMaxEncodedFrameMapSize = 150;
29const int64_t kMaxEncodedFrameWindowMs = 800;
30const int64_t kBucketSizeMs = 100;
31const size_t kBucketCount = 10;
asapersson1aa420b2015-12-07 03:12:22 -080032
asapersson8d75ac72017-09-15 06:41:15 -070033const char kVp8ForcedFallbackEncoderFieldTrial[] =
34 "WebRTC-VP8-Forced-Fallback-Encoder";
35const char kVp8SwCodecName[] = "libvpx";
36
asapersson2a0a2a42015-10-27 01:32:00 -070037// Used by histograms. Values of entries should not be changed.
38enum HistogramCodecType {
39 kVideoUnknown = 0,
40 kVideoVp8 = 1,
41 kVideoVp9 = 2,
42 kVideoH264 = 3,
43 kVideoMax = 64,
44};
45
asaperssonc2148a52016-02-04 00:33:21 -080046const char* kRealtimePrefix = "WebRTC.Video.";
47const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
48
sprangb4a1ae52015-12-03 08:10:08 -080049const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
50 switch (content_type) {
51 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080052 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080053 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080054 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080055 }
56 RTC_NOTREACHED();
57 return nullptr;
58}
59
asapersson2a0a2a42015-10-27 01:32:00 -070060HistogramCodecType PayloadNameToHistogramCodecType(
61 const std::string& payload_name) {
kthelgason1cdddc92017-08-24 03:52:48 -070062 VideoCodecType codecType = PayloadStringToCodecType(payload_name);
63 switch (codecType) {
deadbeefc964d0b2017-04-03 10:03:35 -070064 case kVideoCodecVP8:
65 return kVideoVp8;
66 case kVideoCodecVP9:
67 return kVideoVp9;
68 case kVideoCodecH264:
69 return kVideoH264;
70 default:
71 return kVideoUnknown;
72 }
asapersson2a0a2a42015-10-27 01:32:00 -070073}
74
75void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080076 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
77 PayloadNameToHistogramCodecType(payload_name),
78 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070079}
asapersson8d75ac72017-09-15 06:41:15 -070080
81bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) {
82 return codec_info->codecType == kVideoCodecVP8 &&
83 codec_info->codecSpecific.VP8.simulcastIdx == 0 &&
84 (codec_info->codecSpecific.VP8.temporalIdx == 0 ||
85 codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
86}
87
88rtc::Optional<int> GetFallbackIntervalFromFieldTrial() {
89 if (!webrtc::field_trial::IsEnabled(kVp8ForcedFallbackEncoderFieldTrial))
90 return rtc::Optional<int>();
91
92 std::string group =
93 webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
94 if (group.empty())
95 return rtc::Optional<int>();
96
97 int low_kbps;
98 int high_kbps;
99 int min_low_ms;
100 int min_pixels;
101 if (sscanf(group.c_str(), "Enabled-%d,%d,%d,%d", &low_kbps, &high_kbps,
102 &min_low_ms, &min_pixels) != 4) {
103 return rtc::Optional<int>();
104 }
105
106 if (min_low_ms <= 0 || min_pixels <= 0 || low_kbps <= 0 ||
107 high_kbps <= low_kbps) {
108 return rtc::Optional<int>();
109 }
110 return rtc::Optional<int>(min_low_ms);
111}
asapersson2a0a2a42015-10-27 01:32:00 -0700112} // namespace
113
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000114
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000115const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
116
sprangb4a1ae52015-12-03 08:10:08 -0800117SendStatisticsProxy::SendStatisticsProxy(
118 Clock* clock,
119 const VideoSendStream::Config& config,
120 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -0700121 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -0700122 payload_name_(config.encoder_settings.payload_name),
123 rtp_config_(config.rtp),
asapersson8d75ac72017-09-15 06:41:15 -0700124 min_first_fallback_interval_ms_(GetFallbackIntervalFromFieldTrial()),
sprangb4a1ae52015-12-03 08:10:08 -0800125 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -0700126 start_ms_(clock->TimeInMilliseconds()),
asapersson1aa420b2015-12-07 03:12:22 -0800127 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -0700128 quality_downscales_(-1),
129 cpu_downscales_(-1),
Åsa Persson0122e842017-10-16 12:19:23 +0200130 media_byte_rate_tracker_(kBucketSizeMs, kBucketCount),
131 encoded_frame_rate_tracker_(kBucketSizeMs, kBucketCount),
sprang07fb9be2016-02-24 07:55:00 -0800132 uma_container_(
133 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000134}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000135
sprang07fb9be2016-02-24 07:55:00 -0800136SendStatisticsProxy::~SendStatisticsProxy() {
137 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -0700138 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -0700139
140 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700141 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
142 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700143
144 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700145 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800146}
sprangb4a1ae52015-12-03 08:10:08 -0800147
148SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800149 const char* prefix,
150 const VideoSendStream::Stats& stats,
151 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800152 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800153 clock_(clock),
Honghai Zhang82d78622016-05-06 11:29:15 -0700154 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800155 input_fps_counter_(clock, nullptr, true),
156 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800157 total_byte_counter_(clock, nullptr, true),
158 media_byte_counter_(clock, nullptr, true),
159 rtx_byte_counter_(clock, nullptr, true),
160 padding_byte_counter_(clock, nullptr, true),
161 retransmit_byte_counter_(clock, nullptr, true),
162 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800163 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100164 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800165 start_stats_(stats) {
166 InitializeBitrateCounters(stats);
167}
sprangb4a1ae52015-12-03 08:10:08 -0800168
sprang07fb9be2016-02-24 07:55:00 -0800169SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200170
asapersson93e1e232017-02-06 05:18:35 -0800171void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
172 const VideoSendStream::Stats& stats) {
173 for (const auto& it : stats.substreams) {
174 uint32_t ssrc = it.first;
175 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
176 ssrc);
177 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
178 ssrc);
179 retransmit_byte_counter_.SetLast(
180 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
181 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
182 if (it.second.is_rtx) {
183 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
184 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100185 } else {
asapersson93e1e232017-02-06 05:18:35 -0800186 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
187 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100188 }
189 }
190}
191
Åsa Persson0122e842017-10-16 12:19:23 +0200192void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(int64_t now_ms) {
193 while (!encoded_frames_.empty()) {
194 auto it = encoded_frames_.begin();
195 if (now_ms - it->second.send_ms < kMaxEncodedFrameWindowMs)
196 break;
197
198 // Use max per timestamp.
199 sent_width_counter_.Add(it->second.max_width);
200 sent_height_counter_.Add(it->second.max_height);
201 encoded_frames_.erase(it);
202 }
203}
204
205bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame(
206 const EncodedImage& encoded_frame) {
207 int64_t now_ms = clock_->TimeInMilliseconds();
208 RemoveOld(now_ms);
209 if (encoded_frames_.size() > kMaxEncodedFrameMapSize) {
210 encoded_frames_.clear();
211 }
212
213 auto it = encoded_frames_.find(encoded_frame._timeStamp);
214 if (it == encoded_frames_.end()) {
215 // First frame with this timestamp.
216 encoded_frames_.insert(std::make_pair(
217 encoded_frame._timeStamp, Frame(now_ms, encoded_frame._encodedWidth,
218 encoded_frame._encodedHeight)));
219 sent_fps_counter_.Add(1);
220 return true;
221 }
222
223 it->second.max_width =
224 std::max(it->second.max_width, encoded_frame._encodedWidth);
225 it->second.max_height =
226 std::max(it->second.max_height, encoded_frame._encodedHeight);
227 return false;
228}
229
sprang07fb9be2016-02-24 07:55:00 -0800230void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700231 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800232 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800233 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
234 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800235 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700236 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
237 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700238 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700239 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
240 in_width);
241 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
242 in_height);
asapersson2077f2f2017-05-11 05:37:35 -0700243 LOG(LS_INFO) << uma_prefix_ << "InputWidthInPixels " << in_width;
244 LOG(LS_INFO) << uma_prefix_ << "InputHeightInPixels " << in_height;
asaperssond89920b2015-07-22 06:52:00 -0700245 }
asapersson320e45a2016-11-29 01:40:35 -0800246 AggregatedStats in_fps = input_fps_counter_.GetStats();
247 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
248 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
249 in_fps.average);
250 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
251 }
252
perkj803d97f2016-11-01 11:45:46 -0700253 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
254 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700255 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700256 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
257 sent_width);
258 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
259 sent_height);
asapersson2077f2f2017-05-11 05:37:35 -0700260 LOG(LS_INFO) << uma_prefix_ << "SentWidthInPixels " << sent_width;
261 LOG(LS_INFO) << uma_prefix_ << "SentHeightInPixels " << sent_height;
asaperssond89920b2015-07-22 06:52:00 -0700262 }
asapersson320e45a2016-11-29 01:40:35 -0800263 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
264 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
265 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
266 sent_fps.average);
267 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
268 << sent_fps.ToString();
269 }
270
ilnikf4ded682017-08-30 02:30:20 -0700271 if (in_fps.num_samples > kMinRequiredPeriodicSamples &&
272 sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
273 int in_fps_avg = in_fps.average;
274 if (in_fps_avg > 0) {
275 int sent_fps_avg = sent_fps.average;
276 int sent_to_in_fps_ratio_percent =
277 (100 * sent_fps_avg + in_fps_avg / 2) / in_fps_avg;
278 // If reported period is small, it may happen that sent_fps is larger than
279 // input_fps briefly on average. This should be treated as 100% sent to
280 // input ratio.
281 if (sent_to_in_fps_ratio_percent > 100)
282 sent_to_in_fps_ratio_percent = 100;
283 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
284 uma_prefix_ + "SentToInputFpsRatioPercent",
285 sent_to_in_fps_ratio_percent);
286 LOG(LS_INFO) << uma_prefix_ << "SentToInputFpsRatioPercent "
287 << sent_to_in_fps_ratio_percent;
288 }
289 }
290
perkj803d97f2016-11-01 11:45:46 -0700291 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800292 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700293 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
294 encode_ms);
asapersson2077f2f2017-05-11 05:37:35 -0700295 LOG(LS_INFO) << uma_prefix_ << "EncodeTimeInMs " << encode_ms;
asaperssonc2148a52016-02-04 00:33:21 -0800296 }
perkj803d97f2016-11-01 11:45:46 -0700297 int key_frames_permille =
298 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700299 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700300 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
301 key_frames_permille);
asapersson2077f2f2017-05-11 05:37:35 -0700302 LOG(LS_INFO) << uma_prefix_ << "KeyFramesSentInPermille "
303 << key_frames_permille;
asaperssondec5ebf2015-10-05 02:36:17 -0700304 }
asapersson4306fc72015-10-19 00:35:21 -0700305 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700306 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700307 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700308 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
309 uma_prefix_ + "QualityLimitedResolutionInPercent",
310 quality_limited);
asapersson2077f2f2017-05-11 05:37:35 -0700311 LOG(LS_INFO) << uma_prefix_ << "QualityLimitedResolutionInPercent "
312 << quality_limited;
asapersson4306fc72015-10-19 00:35:21 -0700313 }
perkj803d97f2016-11-01 11:45:46 -0700314 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700315 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700316 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800317 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
318 20);
asapersson4306fc72015-10-19 00:35:21 -0700319 }
perkj803d97f2016-11-01 11:45:46 -0700320 int cpu_limited =
321 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
322 if (cpu_limited != -1) {
323 RTC_HISTOGRAMS_PERCENTAGE(
324 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
325 }
326 int bw_limited =
327 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700328 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700329 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800330 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
331 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700332 }
perkj803d97f2016-11-01 11:45:46 -0700333 int num_disabled =
334 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700335 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700336 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800337 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
338 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700339 }
perkj803d97f2016-11-01 11:45:46 -0700340 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800341 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700342 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
343 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800344
perkj803d97f2016-11-01 11:45:46 -0700345 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800346 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700347 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
348 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800349 }
sprang07fb9be2016-02-24 07:55:00 -0800350
asapersson118ef002016-03-31 00:00:19 -0700351 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700352 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700353 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700354 int spatial_idx = it.first;
355 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700356 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
357 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700358 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700359 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
360 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700361 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700362 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
363 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700364 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700365 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
366 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700367 } else {
368 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
369 << spatial_idx;
370 }
371 }
perkj803d97f2016-11-01 11:45:46 -0700372 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700373 if (qp_vp9 != -1) {
374 int spatial_idx = it.first;
375 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700376 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
377 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700378 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700379 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
380 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700381 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700382 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
383 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700384 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700385 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
386 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700387 } else {
388 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
389 << spatial_idx;
390 }
391 }
asapersson827cab32016-11-02 09:08:47 -0700392 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
393 if (qp_h264 != -1) {
394 int spatial_idx = it.first;
395 RTC_DCHECK_EQ(-1, spatial_idx);
396 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
397 qp_h264);
398 }
asapersson118ef002016-03-31 00:00:19 -0700399 }
400
asapersson0944a802017-04-07 00:57:58 -0700401 if (first_rtp_stats_time_ms_ != -1) {
asapersson09f05612017-05-15 23:40:18 -0700402 quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
403 int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700404 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
405 int quality_changes = current_stats.number_of_quality_adapt_changes -
406 start_stats_.number_of_quality_adapt_changes;
407 RTC_HISTOGRAMS_COUNTS_100(kIndex,
408 uma_prefix_ + "AdaptChangesPerMinute.Quality",
409 quality_changes * 60 / elapsed_sec);
410 }
asapersson09f05612017-05-15 23:40:18 -0700411 cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
412 elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700413 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
414 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
415 start_stats_.number_of_cpu_adapt_changes;
416 RTC_HISTOGRAMS_COUNTS_100(kIndex,
417 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
418 cpu_changes * 60 / elapsed_sec);
419 }
asapersson6eca98b2017-04-04 23:40:50 -0700420 }
421
sprange2d83d62016-02-19 09:03:26 -0800422 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800423 int64_t elapsed_sec =
424 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
425 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
426 int fraction_lost = report_block_stats_.FractionLostInPercent();
427 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700428 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800429 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
asapersson2077f2f2017-05-11 05:37:35 -0700430 LOG(LS_INFO) << uma_prefix_ << "SentPacketsLostInPercent "
431 << fraction_lost;
sprang07fb9be2016-02-24 07:55:00 -0800432 }
433
434 // The RTCP packet type counters, delivered via the
435 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
436 // life of the send stream and are not reset when switching content type.
437 // For the purpose of these statistics though, we want new counts when
438 // switching since we switch histogram name. On every reset of the
439 // UmaSamplesContainer, we save the initial state of the counters, so that
440 // we can calculate the delta here and aggregate over all ssrcs.
441 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700442 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800443 auto kv = current_stats.substreams.find(ssrc);
444 if (kv == current_stats.substreams.end())
445 continue;
446
447 RtcpPacketTypeCounter stream_counters =
448 kv->second.rtcp_packet_type_counts;
449 kv = start_stats_.substreams.find(ssrc);
450 if (kv != start_stats_.substreams.end())
451 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
452
453 counters.Add(stream_counters);
454 }
asapersson1d02d3e2016-09-09 22:40:25 -0700455 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
456 uma_prefix_ + "NackPacketsReceivedPerMinute",
457 counters.nack_packets * 60 / elapsed_sec);
458 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
459 uma_prefix_ + "FirPacketsReceivedPerMinute",
460 counters.fir_packets * 60 / elapsed_sec);
461 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
462 uma_prefix_ + "PliPacketsReceivedPerMinute",
463 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800464 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700465 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800466 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
467 counters.UniqueNackRequestsInPercent());
468 }
sprange2d83d62016-02-19 09:03:26 -0800469 }
470 }
Erik Språng22c2b482016-03-01 09:40:42 +0100471
472 if (first_rtp_stats_time_ms_ != -1) {
473 int64_t elapsed_sec =
474 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
475 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800476 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
477 target_rate_updates_.pause_resume_events);
asapersson2077f2f2017-05-11 05:37:35 -0700478 LOG(LS_INFO) << uma_prefix_ << "NumberOfPauseEvents "
479 << target_rate_updates_.pause_resume_events;
asapersson66d4b372016-12-19 06:50:53 -0800480
481 int paused_time_percent =
482 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
483 if (paused_time_percent != -1) {
484 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
485 paused_time_percent);
asapersson2077f2f2017-05-11 05:37:35 -0700486 LOG(LS_INFO) << uma_prefix_ << "PausedTimeInPercent "
487 << paused_time_percent;
asapersson66d4b372016-12-19 06:50:53 -0800488 }
asapersson93e1e232017-02-06 05:18:35 -0800489 }
490 }
asapersson66d4b372016-12-19 06:50:53 -0800491
asapersson8d75ac72017-09-15 06:41:15 -0700492 if (fallback_info_.is_possible) {
493 // Double interval since there is some time before fallback may occur.
494 const int kMinRunTimeMs = 2 * metrics::kMinRunTimeInSeconds * 1000;
495 int64_t elapsed_ms = fallback_info_.elapsed_ms;
496 int fallback_time_percent = fallback_active_counter_.Percent(kMinRunTimeMs);
497 if (fallback_time_percent != -1 && elapsed_ms >= kMinRunTimeMs) {
498 RTC_HISTOGRAMS_PERCENTAGE(
499 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackTimeInPercent.Vp8",
500 fallback_time_percent);
501 RTC_HISTOGRAMS_COUNTS_100(
502 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackChangesPerMinute.Vp8",
503 fallback_info_.on_off_events * 60 / (elapsed_ms / 1000));
504 }
505 }
506
asapersson93e1e232017-02-06 05:18:35 -0800507 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
508 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
509 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
510 total_bytes_per_sec.average * 8 / 1000);
511 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
512 << total_bytes_per_sec.ToStringWithMultiplier(8);
513 }
514 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
515 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
516 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
517 media_bytes_per_sec.average * 8 / 1000);
518 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
519 << media_bytes_per_sec.ToStringWithMultiplier(8);
520 }
521 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
522 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
523 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
524 uma_prefix_ + "PaddingBitrateSentInKbps",
525 padding_bytes_per_sec.average * 8 / 1000);
526 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
527 << padding_bytes_per_sec.ToStringWithMultiplier(8);
528 }
529 AggregatedStats retransmit_bytes_per_sec =
530 retransmit_byte_counter_.GetStats();
531 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
532 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
533 uma_prefix_ + "RetransmittedBitrateSentInKbps",
534 retransmit_bytes_per_sec.average * 8 / 1000);
535 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
536 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
537 }
538 if (!rtp_config.rtx.ssrcs.empty()) {
539 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
540 int rtx_bytes_per_sec_avg = -1;
541 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
542 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
543 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
544 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
545 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
546 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
547 }
548 if (rtx_bytes_per_sec_avg != -1) {
549 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
550 rtx_bytes_per_sec_avg * 8 / 1000);
551 }
552 }
553 if (rtp_config.flexfec.payload_type != -1 ||
554 rtp_config.ulpfec.red_payload_type != -1) {
555 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
556 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
557 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
558 fec_bytes_per_sec.average * 8 / 1000);
559 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
560 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100561 }
562 }
Ilya Nikolaevskiy4b1a3632017-10-19 11:36:02 +0200563 LOG(LS_INFO) << "Frames encoded " << current_stats.frames_encoded;
564 LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Capturer "
565 << current_stats.frames_dropped_by_capturer;
566 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Capturer",
567 current_stats.frames_dropped_by_capturer);
568 LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.EncoderQueue "
569 << current_stats.frames_dropped_by_encoder_queue;
570 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.EncoderQueue",
571 current_stats.frames_dropped_by_encoder_queue);
572 LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Encoder "
573 << current_stats.frames_dropped_by_encoder;
574 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Encoder",
575 current_stats.frames_dropped_by_encoder);
576 LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Ratelimiter "
577 << current_stats.frames_dropped_by_rate_limiter;
578 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Ratelimiter",
579 current_stats.frames_dropped_by_rate_limiter);
sprangb4a1ae52015-12-03 08:10:08 -0800580}
581
Pera48ddb72016-09-29 11:48:50 +0200582void SendStatisticsProxy::OnEncoderReconfigured(
583 const VideoEncoderConfig& config,
584 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800585 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200586 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
587
588 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700589 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200590 uma_container_.reset(new UmaSamplesContainer(
591 GetUmaPrefix(config.content_type), stats_, clock_));
592 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800593 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200594}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000595
Peter Boströme4499152016-02-05 11:13:28 +0100596void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
597 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000598 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200599 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100600 uma_container_->encode_time_counter_.Add(encode_time_ms);
601 encode_time_.Apply(1.0f, encode_time_ms);
602 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000603 stats_.encode_usage_percent = metrics.encode_usage_percent;
604}
605
Peter Boström7083e112015-09-22 16:28:51 +0200606void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700607 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200608 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000609 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800610 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800611 // Pause framerate (add min pause time since there may be frames/packets
612 // that are not yet sent).
613 const int64_t kMinMs = 500;
614 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
615 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
616 // Pause bitrate stats.
617 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
618 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
619 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
620 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
621 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
622 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700623 // Stop adaptation stats.
asapersson09f05612017-05-15 23:40:18 -0700624 uma_container_->cpu_adapt_timer_.Stop(now_ms);
625 uma_container_->quality_adapt_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800626 } else {
asapersson0944a802017-04-07 00:57:58 -0700627 // Start adaptation stats if scaling is enabled.
628 if (cpu_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700629 uma_container_->cpu_adapt_timer_.Start(now_ms);
asapersson0944a802017-04-07 00:57:58 -0700630 if (quality_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700631 uma_container_->quality_adapt_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800632 // Stop pause explicitly for stats that may be zero/not updated for some
633 // time.
634 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
635 uma_container_->padding_byte_counter_.ProcessAndStopPause();
636 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
637 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800638 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000639}
640
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000641VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200642 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000643 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000644 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800645 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
ilnik50864a82017-09-06 12:32:35 -0700646 stats_.content_type =
647 content_type_ == VideoEncoderConfig::ContentType::kRealtimeVideo
648 ? VideoContentType::UNSPECIFIED
649 : VideoContentType::SCREENSHARE;
Åsa Persson0122e842017-10-16 12:19:23 +0200650 stats_.encode_frame_rate = round(encoded_frame_rate_tracker_.ComputeRate());
651 stats_.media_bitrate_bps = media_byte_rate_tracker_.ComputeRate() * 8;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000652 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000653}
654
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000655void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200656 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000657 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
658 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000659 it != stats_.substreams.end(); ++it) {
660 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200661 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
662 it->second.width = 0;
663 it->second.height = 0;
664 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000665 }
666}
667
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000668VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
669 uint32_t ssrc) {
670 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
671 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000672 if (it != stats_.substreams.end())
673 return &it->second;
674
brandtrcd188f62016-11-15 08:21:52 -0800675 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
676 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800677 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
678 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800679 bool is_rtx =
680 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
681 ssrc) != rtp_config_.rtx.ssrcs.end();
682 if (!is_media && !is_flexfec && !is_rtx)
683 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000684
asapersson2e5cfcd2016-08-11 08:41:18 -0700685 // Insert new entry and return ptr.
686 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
687 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800688 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700689
690 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000691}
692
Peter Boström20f3f942015-05-15 11:33:39 +0200693void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
694 rtc::CritScope lock(&crit_);
695 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200696 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200697 return;
698
699 stats->total_bitrate_bps = 0;
700 stats->retransmit_bitrate_bps = 0;
701 stats->height = 0;
702 stats->width = 0;
703}
704
perkjf5b2e512016-07-05 08:34:04 -0700705void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200706 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800707 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
708 return; // Start on first non-zero bitrate, may initially be zero.
709
710 int64_t now = clock_->TimeInMilliseconds();
711 if (uma_container_->target_rate_updates_.last_ms != -1) {
712 bool was_paused = stats_.target_media_bitrate_bps == 0;
713 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
714 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
715
716 // Use last to not include update when stream is stopped and video disabled.
717 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
718 ++uma_container_->target_rate_updates_.pause_resume_events;
719
720 // Check if video is paused/resumed.
721 uma_container_->target_rate_updates_.last_paused_or_resumed =
722 (bitrate_bps == 0) != was_paused;
723 }
724 uma_container_->target_rate_updates_.last_ms = now;
725
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000726 stats_.target_media_bitrate_bps = bitrate_bps;
727}
728
asapersson8d75ac72017-09-15 06:41:15 -0700729void SendStatisticsProxy::UpdateEncoderFallbackStats(
730 const CodecSpecificInfo* codec_info) {
731 if (!min_first_fallback_interval_ms_ ||
732 !uma_container_->fallback_info_.is_possible) {
733 return;
734 }
735
736 if (!IsForcedFallbackPossible(codec_info)) {
737 uma_container_->fallback_info_.is_possible = false;
738 return;
739 }
740
741 FallbackEncoderInfo* fallback_info = &uma_container_->fallback_info_;
742
743 const int64_t now_ms = clock_->TimeInMilliseconds();
744 bool is_active = fallback_info->is_active;
745 if (codec_info->codec_name != stats_.encoder_implementation_name) {
746 // Implementation changed.
747 is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
748 if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
749 // First or not a VP8 SW change, update stats on next call.
750 return;
751 }
752 if (is_active && fallback_info->on_off_events == 0) {
753 // The minimum set time should have passed for the first fallback (else
754 // skip to avoid fallback due to failure).
755 int64_t elapsed_ms = fallback_info->elapsed_ms;
756 if (fallback_info->last_update_ms)
757 elapsed_ms += now_ms - *(fallback_info->last_update_ms);
758 if (elapsed_ms < *min_first_fallback_interval_ms_) {
759 fallback_info->is_possible = false;
760 return;
761 }
762 }
763 ++fallback_info->on_off_events;
764 }
765
766 if (fallback_info->last_update_ms) {
767 int64_t diff_ms = now_ms - *(fallback_info->last_update_ms);
768 // If the time diff since last update is greater than |max_frame_diff_ms|,
769 // video is considered paused/muted and the change is not included.
770 if (diff_ms < fallback_info->max_frame_diff_ms) {
771 uma_container_->fallback_active_counter_.Add(fallback_info->is_active,
772 diff_ms);
773 fallback_info->elapsed_ms += diff_ms;
774 }
775 }
776 fallback_info->is_active = is_active;
777 fallback_info->last_update_ms.emplace(now_ms);
778}
779
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000780void SendStatisticsProxy::OnSendEncodedImage(
781 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700782 const CodecSpecificInfo* codec_info) {
783 size_t simulcast_idx = 0;
784
perkj275afc52016-09-01 00:21:16 -0700785 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700786 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700787 if (codec_info) {
788 if (codec_info->codecType == kVideoCodecVP8) {
789 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
790 } else if (codec_info->codecType == kVideoCodecGeneric) {
791 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
792 }
perkj275afc52016-09-01 00:21:16 -0700793 if (codec_info->codec_name) {
asapersson8d75ac72017-09-15 06:41:15 -0700794 UpdateEncoderFallbackStats(codec_info);
perkj275afc52016-09-01 00:21:16 -0700795 stats_.encoder_implementation_name = codec_info->codec_name;
796 }
kjellander02b3d272016-04-20 05:05:54 -0700797 }
798
perkj26091b12016-09-01 01:17:40 -0700799 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000800 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700801 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000802 return;
803 }
perkj26091b12016-09-01 01:17:40 -0700804 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000805
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000806 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200807 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000808 return;
809
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000810 stats->width = encoded_image._encodedWidth;
811 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000812 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700813
sprangb4a1ae52015-12-03 08:10:08 -0800814 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
815 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800816 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800817 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
818 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800819
kthelgason0cd27ba2016-12-19 06:32:16 -0800820 if (quality_downscales_ != -1) {
821 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
822 if (quality_downscales_ > 0)
823 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700824 }
asaperssonda535c42015-10-19 23:32:41 -0700825 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
826 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800827 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700828 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800829 uma_container_->bw_resolutions_disabled_counter_.Add(
830 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700831 }
832 }
asapersson4306fc72015-10-19 00:35:21 -0700833
sakal87da4042016-10-31 06:53:47 -0700834 if (encoded_image.qp_ != -1) {
835 if (!stats_.qp_sum)
836 stats_.qp_sum = rtc::Optional<uint64_t>(0);
837 *stats_.qp_sum += encoded_image.qp_;
838
839 if (codec_info) {
840 if (codec_info->codecType == kVideoCodecVP8) {
841 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
842 ? -1
843 : static_cast<int>(simulcast_idx);
844 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
845 } else if (codec_info->codecType == kVideoCodecVP9) {
846 int spatial_idx =
847 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
848 ? -1
849 : codec_info->codecSpecific.VP9.spatial_idx;
850 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700851 } else if (codec_info->codecType == kVideoCodecH264) {
852 int spatial_idx = -1;
853 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700854 }
asapersson5265fed2016-04-18 02:58:47 -0700855 }
asapersson118ef002016-03-31 00:00:19 -0700856 }
857
Åsa Persson0122e842017-10-16 12:19:23 +0200858 media_byte_rate_tracker_.AddSamples(encoded_image._length);
859 if (uma_container_->InsertEncodedFrame(encoded_image))
860 encoded_frame_rate_tracker_.AddSamples(1);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000861}
862
Per69b332d2016-06-02 15:45:42 +0200863int SendStatisticsProxy::GetSendFrameRate() const {
864 rtc::CritScope lock(&crit_);
Åsa Persson0122e842017-10-16 12:19:23 +0200865 return round(encoded_frame_rate_tracker_.ComputeRate());
Per69b332d2016-06-02 15:45:42 +0200866}
867
asaperssond89920b2015-07-22 06:52:00 -0700868void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200869 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800870 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800871 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800872 uma_container_->input_width_counter_.Add(width);
873 uma_container_->input_height_counter_.Add(height);
asaperssonf4e44af2017-04-19 02:01:06 -0700874 if (cpu_downscales_ >= 0) {
875 uma_container_->cpu_limited_frame_counter_.Add(
876 stats_.cpu_limited_resolution);
877 }
Åsa Perssond29b54c2017-10-19 17:32:17 +0200878 if (encoded_frame_rate_tracker_.TotalSampleCount() == 0) {
879 // Set start time now instead of when first key frame is encoded to avoid a
880 // too high initial estimate.
881 encoded_frame_rate_tracker_.AddSamples(0);
882 }
perkj803d97f2016-11-01 11:45:46 -0700883}
884
Ilya Nikolaevskiy4b1a3632017-10-19 11:36:02 +0200885void SendStatisticsProxy::OnFrameDroppedBySource() {
886 rtc::CritScope lock(&crit_);
887 ++stats_.frames_dropped_by_capturer;
888}
889
890void SendStatisticsProxy::OnFrameDroppedInEncoderQueue() {
891 rtc::CritScope lock(&crit_);
892 ++stats_.frames_dropped_by_encoder_queue;
893}
894
895void SendStatisticsProxy::OnFrameDroppedByEncoder() {
896 rtc::CritScope lock(&crit_);
897 ++stats_.frames_dropped_by_encoder;
898}
899
900void SendStatisticsProxy::OnFrameDroppedByMediaOptimizations() {
901 rtc::CritScope lock(&crit_);
902 ++stats_.frames_dropped_by_rate_limiter;
903}
904
asapersson09f05612017-05-15 23:40:18 -0700905void SendStatisticsProxy::SetAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700906 const VideoStreamEncoder::AdaptCounts& cpu_counts,
907 const VideoStreamEncoder::AdaptCounts& quality_counts) {
perkj803d97f2016-11-01 11:45:46 -0700908 rtc::CritScope lock(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700909 SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
910 SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
911 UpdateAdaptationStats(cpu_counts, quality_counts);
asapersson36e9eb42017-03-31 05:29:12 -0700912}
913
asapersson09f05612017-05-15 23:40:18 -0700914void SendStatisticsProxy::OnCpuAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700915 const VideoStreamEncoder::AdaptCounts& cpu_counts,
916 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson36e9eb42017-03-31 05:29:12 -0700917 rtc::CritScope lock(&crit_);
perkj803d97f2016-11-01 11:45:46 -0700918 ++stats_.number_of_cpu_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700919 UpdateAdaptationStats(cpu_counts, quality_counts);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000920}
921
asapersson09f05612017-05-15 23:40:18 -0700922void SendStatisticsProxy::OnQualityAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700923 const VideoStreamEncoder::AdaptCounts& cpu_counts,
924 const VideoStreamEncoder::AdaptCounts& quality_counts) {
kthelgason876222f2016-11-29 01:44:11 -0800925 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700926 ++stats_.number_of_quality_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700927 UpdateAdaptationStats(cpu_counts, quality_counts);
928}
929
930void SendStatisticsProxy::UpdateAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700931 const VideoStreamEncoder::AdaptCounts& cpu_counts,
932 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson09f05612017-05-15 23:40:18 -0700933 cpu_downscales_ = cpu_counts.resolution;
934 quality_downscales_ = quality_counts.resolution;
935
936 stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
937 stats_.cpu_limited_framerate = cpu_counts.fps > 0;
938 stats_.bw_limited_resolution = quality_counts.resolution > 0;
939 stats_.bw_limited_framerate = quality_counts.fps > 0;
940}
941
mflodmancc3d4422017-08-03 08:27:51 -0700942void SendStatisticsProxy::SetAdaptTimer(
943 const VideoStreamEncoder::AdaptCounts& counts,
944 StatsTimer* timer) {
asapersson09f05612017-05-15 23:40:18 -0700945 if (counts.resolution >= 0 || counts.fps >= 0) {
946 // Adaptation enabled.
947 if (!stats_.suspended)
948 timer->Start(clock_->TimeInMilliseconds());
949 return;
950 }
951 timer->Stop(clock_->TimeInMilliseconds());
kthelgason876222f2016-11-29 01:44:11 -0800952}
953
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000954void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
955 uint32_t ssrc,
956 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200957 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000958 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200959 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000960 return;
961
962 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800963 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
964 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000965}
966
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000967void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
968 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200969 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000970 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200971 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000972 return;
973
974 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800975 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000976}
977
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100978void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000979
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000980void SendStatisticsProxy::DataCountersUpdated(
981 const StreamDataCounters& counters,
982 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200983 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000984 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800985 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000986
asaperssona6a699a2016-11-25 03:52:46 -0800987 if (stats->is_flexfec) {
988 // The same counters are reported for both the media ssrc and flexfec ssrc.
989 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
990 return;
991 }
992
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000993 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -0700994 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
995 int64_t now_ms = clock_->TimeInMilliseconds();
996 uma_container_->first_rtp_stats_time_ms_ = now_ms;
asapersson09f05612017-05-15 23:40:18 -0700997 uma_container_->cpu_adapt_timer_.Restart(now_ms);
998 uma_container_->quality_adapt_timer_.Restart(now_ms);
asapersson6eca98b2017-04-04 23:40:50 -0700999 }
asapersson93e1e232017-02-06 05:18:35 -08001000
1001 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
1002 ssrc);
1003 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
1004 ssrc);
1005 uma_container_->retransmit_byte_counter_.Set(
1006 counters.retransmitted.TotalBytes(), ssrc);
1007 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
1008 if (stats->is_rtx) {
1009 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
1010 ssrc);
1011 } else {
1012 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
1013 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001014}
1015
sprangcd349d92016-07-13 09:11:28 -07001016void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
1017 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001018 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001019 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001020 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001021 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001022 return;
1023
sprangcd349d92016-07-13 09:11:28 -07001024 stats->total_bitrate_bps = total_bitrate_bps;
1025 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001026}
1027
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001028void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
1029 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001030 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001031 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001032 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001033 return;
1034
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001035 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001036}
1037
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001038void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
1039 int max_delay_ms,
1040 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001041 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001042 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001043 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001044 return;
1045 stats->avg_delay_ms = avg_delay_ms;
1046 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -08001047
sprangb4a1ae52015-12-03 08:10:08 -08001048 uma_container_->delay_counter_.Add(avg_delay_ms);
1049 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001050}
1051
asapersson6eca98b2017-04-04 23:40:50 -07001052void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
1053 if (start_ms == -1)
1054 start_ms = now_ms;
1055}
1056
1057void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
1058 if (start_ms != -1) {
1059 total_ms += now_ms - start_ms;
1060 start_ms = -1;
1061 }
1062}
1063
1064void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
1065 total_ms = 0;
1066 if (start_ms != -1)
1067 start_ms = now_ms;
1068}
1069
asaperssond89920b2015-07-22 06:52:00 -07001070void SendStatisticsProxy::SampleCounter::Add(int sample) {
1071 sum += sample;
1072 ++num_samples;
1073}
1074
asapersson66d4b372016-12-19 06:50:53 -08001075int SendStatisticsProxy::SampleCounter::Avg(
1076 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -07001077 if (num_samples < min_required_samples || num_samples == 0)
1078 return -1;
asapersson66d4b372016-12-19 06:50:53 -08001079 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -07001080}
1081
asaperssondec5ebf2015-10-05 02:36:17 -07001082void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
1083 if (sample)
1084 ++sum;
1085 ++num_samples;
1086}
1087
asapersson66d4b372016-12-19 06:50:53 -08001088void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
1089 if (sample)
1090 sum += count;
1091 num_samples += count;
1092}
asaperssondec5ebf2015-10-05 02:36:17 -07001093int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -08001094 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001095 return Fraction(min_required_samples, 100.0f);
1096}
1097
1098int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -08001099 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001100 return Fraction(min_required_samples, 1000.0f);
1101}
1102
1103int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -08001104 int64_t min_required_samples,
1105 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001106 if (num_samples < min_required_samples || num_samples == 0)
1107 return -1;
1108 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
1109}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001110} // namespace webrtc