blob: 3eff46e0b246ec916f8ad43a6c06668af394a1ce [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"
22#include "system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000023
24namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070025namespace {
asapersson1aa420b2015-12-07 03:12:22 -080026const float kEncodeTimeWeigthFactor = 0.5f;
27
asapersson2a0a2a42015-10-27 01:32:00 -070028// Used by histograms. Values of entries should not be changed.
29enum HistogramCodecType {
30 kVideoUnknown = 0,
31 kVideoVp8 = 1,
32 kVideoVp9 = 2,
33 kVideoH264 = 3,
34 kVideoMax = 64,
35};
36
asaperssonc2148a52016-02-04 00:33:21 -080037const char* kRealtimePrefix = "WebRTC.Video.";
38const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
39
sprangb4a1ae52015-12-03 08:10:08 -080040const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
41 switch (content_type) {
42 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080043 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080044 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080045 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080046 }
47 RTC_NOTREACHED();
48 return nullptr;
49}
50
asapersson2a0a2a42015-10-27 01:32:00 -070051HistogramCodecType PayloadNameToHistogramCodecType(
52 const std::string& payload_name) {
kthelgason1cdddc92017-08-24 03:52:48 -070053 VideoCodecType codecType = PayloadStringToCodecType(payload_name);
54 switch (codecType) {
deadbeefc964d0b2017-04-03 10:03:35 -070055 case kVideoCodecVP8:
56 return kVideoVp8;
57 case kVideoCodecVP9:
58 return kVideoVp9;
59 case kVideoCodecH264:
60 return kVideoH264;
61 default:
62 return kVideoUnknown;
63 }
asapersson2a0a2a42015-10-27 01:32:00 -070064}
65
66void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080067 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
68 PayloadNameToHistogramCodecType(payload_name),
69 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070070}
71} // namespace
72
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000073
pbos@webrtc.org273a4142014-12-01 15:23:21 +000074const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
75
sprangb4a1ae52015-12-03 08:10:08 -080076SendStatisticsProxy::SendStatisticsProxy(
77 Clock* clock,
78 const VideoSendStream::Config& config,
79 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070080 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -070081 payload_name_(config.encoder_settings.payload_name),
82 rtp_config_(config.rtp),
sprangb4a1ae52015-12-03 08:10:08 -080083 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -070084 start_ms_(clock->TimeInMilliseconds()),
asaperssond89920b2015-07-22 06:52:00 -070085 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080086 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -070087 quality_downscales_(-1),
88 cpu_downscales_(-1),
sprang07fb9be2016-02-24 07:55:00 -080089 uma_container_(
90 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000091}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000092
sprang07fb9be2016-02-24 07:55:00 -080093SendStatisticsProxy::~SendStatisticsProxy() {
94 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -070095 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -070096
97 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -070098 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
99 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700100
101 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700102 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800103}
sprangb4a1ae52015-12-03 08:10:08 -0800104
105SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800106 const char* prefix,
107 const VideoSendStream::Stats& stats,
108 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800109 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800110 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800111 max_sent_width_per_timestamp_(0),
112 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700113 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800114 input_fps_counter_(clock, nullptr, true),
115 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800116 total_byte_counter_(clock, nullptr, true),
117 media_byte_counter_(clock, nullptr, true),
118 rtx_byte_counter_(clock, nullptr, true),
119 padding_byte_counter_(clock, nullptr, true),
120 retransmit_byte_counter_(clock, nullptr, true),
121 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800122 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100123 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800124 start_stats_(stats) {
125 InitializeBitrateCounters(stats);
126}
sprangb4a1ae52015-12-03 08:10:08 -0800127
sprang07fb9be2016-02-24 07:55:00 -0800128SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200129
asapersson93e1e232017-02-06 05:18:35 -0800130void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
131 const VideoSendStream::Stats& stats) {
132 for (const auto& it : stats.substreams) {
133 uint32_t ssrc = it.first;
134 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
135 ssrc);
136 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
137 ssrc);
138 retransmit_byte_counter_.SetLast(
139 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
140 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
141 if (it.second.is_rtx) {
142 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
143 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100144 } else {
asapersson93e1e232017-02-06 05:18:35 -0800145 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
146 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100147 }
148 }
149}
150
sprang07fb9be2016-02-24 07:55:00 -0800151void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700152 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800153 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800154 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
155 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800156 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700157 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
158 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700159 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700160 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
161 in_width);
162 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
163 in_height);
asapersson2077f2f2017-05-11 05:37:35 -0700164 LOG(LS_INFO) << uma_prefix_ << "InputWidthInPixels " << in_width;
165 LOG(LS_INFO) << uma_prefix_ << "InputHeightInPixels " << in_height;
asaperssond89920b2015-07-22 06:52:00 -0700166 }
asapersson320e45a2016-11-29 01:40:35 -0800167 AggregatedStats in_fps = input_fps_counter_.GetStats();
168 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
169 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
170 in_fps.average);
171 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
172 }
173
perkj803d97f2016-11-01 11:45:46 -0700174 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
175 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700176 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700177 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
178 sent_width);
179 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
180 sent_height);
asapersson2077f2f2017-05-11 05:37:35 -0700181 LOG(LS_INFO) << uma_prefix_ << "SentWidthInPixels " << sent_width;
182 LOG(LS_INFO) << uma_prefix_ << "SentHeightInPixels " << sent_height;
asaperssond89920b2015-07-22 06:52:00 -0700183 }
asapersson320e45a2016-11-29 01:40:35 -0800184 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
185 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
186 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
187 sent_fps.average);
188 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
189 << sent_fps.ToString();
190 }
191
ilnikf4ded682017-08-30 02:30:20 -0700192 if (in_fps.num_samples > kMinRequiredPeriodicSamples &&
193 sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
194 int in_fps_avg = in_fps.average;
195 if (in_fps_avg > 0) {
196 int sent_fps_avg = sent_fps.average;
197 int sent_to_in_fps_ratio_percent =
198 (100 * sent_fps_avg + in_fps_avg / 2) / in_fps_avg;
199 // If reported period is small, it may happen that sent_fps is larger than
200 // input_fps briefly on average. This should be treated as 100% sent to
201 // input ratio.
202 if (sent_to_in_fps_ratio_percent > 100)
203 sent_to_in_fps_ratio_percent = 100;
204 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
205 uma_prefix_ + "SentToInputFpsRatioPercent",
206 sent_to_in_fps_ratio_percent);
207 LOG(LS_INFO) << uma_prefix_ << "SentToInputFpsRatioPercent "
208 << sent_to_in_fps_ratio_percent;
209 }
210 }
211
perkj803d97f2016-11-01 11:45:46 -0700212 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800213 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700214 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
215 encode_ms);
asapersson2077f2f2017-05-11 05:37:35 -0700216 LOG(LS_INFO) << uma_prefix_ << "EncodeTimeInMs " << encode_ms;
asaperssonc2148a52016-02-04 00:33:21 -0800217 }
perkj803d97f2016-11-01 11:45:46 -0700218 int key_frames_permille =
219 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700220 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700221 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
222 key_frames_permille);
asapersson2077f2f2017-05-11 05:37:35 -0700223 LOG(LS_INFO) << uma_prefix_ << "KeyFramesSentInPermille "
224 << key_frames_permille;
asaperssondec5ebf2015-10-05 02:36:17 -0700225 }
asapersson4306fc72015-10-19 00:35:21 -0700226 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700227 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700228 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700229 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
230 uma_prefix_ + "QualityLimitedResolutionInPercent",
231 quality_limited);
asapersson2077f2f2017-05-11 05:37:35 -0700232 LOG(LS_INFO) << uma_prefix_ << "QualityLimitedResolutionInPercent "
233 << quality_limited;
asapersson4306fc72015-10-19 00:35:21 -0700234 }
perkj803d97f2016-11-01 11:45:46 -0700235 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700236 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700237 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800238 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
239 20);
asapersson4306fc72015-10-19 00:35:21 -0700240 }
perkj803d97f2016-11-01 11:45:46 -0700241 int cpu_limited =
242 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
243 if (cpu_limited != -1) {
244 RTC_HISTOGRAMS_PERCENTAGE(
245 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
246 }
247 int bw_limited =
248 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700249 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700250 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800251 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
252 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700253 }
perkj803d97f2016-11-01 11:45:46 -0700254 int num_disabled =
255 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700256 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700257 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800258 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
259 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700260 }
perkj803d97f2016-11-01 11:45:46 -0700261 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800262 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700263 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
264 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800265
perkj803d97f2016-11-01 11:45:46 -0700266 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800267 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700268 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
269 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800270 }
sprang07fb9be2016-02-24 07:55:00 -0800271
asapersson118ef002016-03-31 00:00:19 -0700272 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700273 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700274 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700275 int spatial_idx = it.first;
276 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700277 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
278 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700279 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700280 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
281 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700282 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700283 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
284 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700285 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700286 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
287 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700288 } else {
289 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
290 << spatial_idx;
291 }
292 }
perkj803d97f2016-11-01 11:45:46 -0700293 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700294 if (qp_vp9 != -1) {
295 int spatial_idx = it.first;
296 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700297 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
298 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700299 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700300 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
301 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700302 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700303 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
304 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700305 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700306 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
307 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700308 } else {
309 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
310 << spatial_idx;
311 }
312 }
asapersson827cab32016-11-02 09:08:47 -0700313 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
314 if (qp_h264 != -1) {
315 int spatial_idx = it.first;
316 RTC_DCHECK_EQ(-1, spatial_idx);
317 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
318 qp_h264);
319 }
asapersson118ef002016-03-31 00:00:19 -0700320 }
321
asapersson0944a802017-04-07 00:57:58 -0700322 if (first_rtp_stats_time_ms_ != -1) {
asapersson09f05612017-05-15 23:40:18 -0700323 quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
324 int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700325 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
326 int quality_changes = current_stats.number_of_quality_adapt_changes -
327 start_stats_.number_of_quality_adapt_changes;
328 RTC_HISTOGRAMS_COUNTS_100(kIndex,
329 uma_prefix_ + "AdaptChangesPerMinute.Quality",
330 quality_changes * 60 / elapsed_sec);
331 }
asapersson09f05612017-05-15 23:40:18 -0700332 cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
333 elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700334 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
335 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
336 start_stats_.number_of_cpu_adapt_changes;
337 RTC_HISTOGRAMS_COUNTS_100(kIndex,
338 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
339 cpu_changes * 60 / elapsed_sec);
340 }
asapersson6eca98b2017-04-04 23:40:50 -0700341 }
342
sprange2d83d62016-02-19 09:03:26 -0800343 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800344 int64_t elapsed_sec =
345 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
346 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
347 int fraction_lost = report_block_stats_.FractionLostInPercent();
348 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700349 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800350 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
asapersson2077f2f2017-05-11 05:37:35 -0700351 LOG(LS_INFO) << uma_prefix_ << "SentPacketsLostInPercent "
352 << fraction_lost;
sprang07fb9be2016-02-24 07:55:00 -0800353 }
354
355 // The RTCP packet type counters, delivered via the
356 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
357 // life of the send stream and are not reset when switching content type.
358 // For the purpose of these statistics though, we want new counts when
359 // switching since we switch histogram name. On every reset of the
360 // UmaSamplesContainer, we save the initial state of the counters, so that
361 // we can calculate the delta here and aggregate over all ssrcs.
362 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700363 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800364 auto kv = current_stats.substreams.find(ssrc);
365 if (kv == current_stats.substreams.end())
366 continue;
367
368 RtcpPacketTypeCounter stream_counters =
369 kv->second.rtcp_packet_type_counts;
370 kv = start_stats_.substreams.find(ssrc);
371 if (kv != start_stats_.substreams.end())
372 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
373
374 counters.Add(stream_counters);
375 }
asapersson1d02d3e2016-09-09 22:40:25 -0700376 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
377 uma_prefix_ + "NackPacketsReceivedPerMinute",
378 counters.nack_packets * 60 / elapsed_sec);
379 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
380 uma_prefix_ + "FirPacketsReceivedPerMinute",
381 counters.fir_packets * 60 / elapsed_sec);
382 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
383 uma_prefix_ + "PliPacketsReceivedPerMinute",
384 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800385 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700386 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800387 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
388 counters.UniqueNackRequestsInPercent());
389 }
sprange2d83d62016-02-19 09:03:26 -0800390 }
391 }
Erik Språng22c2b482016-03-01 09:40:42 +0100392
393 if (first_rtp_stats_time_ms_ != -1) {
394 int64_t elapsed_sec =
395 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
396 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800397 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
398 target_rate_updates_.pause_resume_events);
asapersson2077f2f2017-05-11 05:37:35 -0700399 LOG(LS_INFO) << uma_prefix_ << "NumberOfPauseEvents "
400 << target_rate_updates_.pause_resume_events;
asapersson66d4b372016-12-19 06:50:53 -0800401
402 int paused_time_percent =
403 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
404 if (paused_time_percent != -1) {
405 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
406 paused_time_percent);
asapersson2077f2f2017-05-11 05:37:35 -0700407 LOG(LS_INFO) << uma_prefix_ << "PausedTimeInPercent "
408 << paused_time_percent;
asapersson66d4b372016-12-19 06:50:53 -0800409 }
asapersson93e1e232017-02-06 05:18:35 -0800410 }
411 }
asapersson66d4b372016-12-19 06:50:53 -0800412
asapersson93e1e232017-02-06 05:18:35 -0800413 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
414 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
415 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
416 total_bytes_per_sec.average * 8 / 1000);
417 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
418 << total_bytes_per_sec.ToStringWithMultiplier(8);
419 }
420 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
421 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
422 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
423 media_bytes_per_sec.average * 8 / 1000);
424 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
425 << media_bytes_per_sec.ToStringWithMultiplier(8);
426 }
427 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
428 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
429 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
430 uma_prefix_ + "PaddingBitrateSentInKbps",
431 padding_bytes_per_sec.average * 8 / 1000);
432 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
433 << padding_bytes_per_sec.ToStringWithMultiplier(8);
434 }
435 AggregatedStats retransmit_bytes_per_sec =
436 retransmit_byte_counter_.GetStats();
437 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
438 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
439 uma_prefix_ + "RetransmittedBitrateSentInKbps",
440 retransmit_bytes_per_sec.average * 8 / 1000);
441 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
442 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
443 }
444 if (!rtp_config.rtx.ssrcs.empty()) {
445 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
446 int rtx_bytes_per_sec_avg = -1;
447 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
448 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
449 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
450 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
451 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
452 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
453 }
454 if (rtx_bytes_per_sec_avg != -1) {
455 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
456 rtx_bytes_per_sec_avg * 8 / 1000);
457 }
458 }
459 if (rtp_config.flexfec.payload_type != -1 ||
460 rtp_config.ulpfec.red_payload_type != -1) {
461 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
462 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
463 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
464 fec_bytes_per_sec.average * 8 / 1000);
465 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
466 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100467 }
468 }
sprangb4a1ae52015-12-03 08:10:08 -0800469}
470
Pera48ddb72016-09-29 11:48:50 +0200471void SendStatisticsProxy::OnEncoderReconfigured(
472 const VideoEncoderConfig& config,
473 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800474 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200475 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
476
477 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700478 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200479 uma_container_.reset(new UmaSamplesContainer(
480 GetUmaPrefix(config.content_type), stats_, clock_));
481 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800482 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200483}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000484
perkj275afc52016-09-01 00:21:16 -0700485void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
486 uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200487 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000488 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000489 stats_.media_bitrate_bps = bitrate;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000490}
491
Peter Boströme4499152016-02-05 11:13:28 +0100492void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
493 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000494 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200495 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100496 uma_container_->encode_time_counter_.Add(encode_time_ms);
497 encode_time_.Apply(1.0f, encode_time_ms);
498 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000499 stats_.encode_usage_percent = metrics.encode_usage_percent;
500}
501
Peter Boström7083e112015-09-22 16:28:51 +0200502void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700503 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200504 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000505 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800506 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800507 // Pause framerate (add min pause time since there may be frames/packets
508 // that are not yet sent).
509 const int64_t kMinMs = 500;
510 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
511 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
512 // Pause bitrate stats.
513 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
514 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
515 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
516 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
517 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
518 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700519 // Stop adaptation stats.
asapersson09f05612017-05-15 23:40:18 -0700520 uma_container_->cpu_adapt_timer_.Stop(now_ms);
521 uma_container_->quality_adapt_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800522 } else {
asapersson0944a802017-04-07 00:57:58 -0700523 // Start adaptation stats if scaling is enabled.
524 if (cpu_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700525 uma_container_->cpu_adapt_timer_.Start(now_ms);
asapersson0944a802017-04-07 00:57:58 -0700526 if (quality_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700527 uma_container_->quality_adapt_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800528 // Stop pause explicitly for stats that may be zero/not updated for some
529 // time.
530 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
531 uma_container_->padding_byte_counter_.ProcessAndStopPause();
532 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
533 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800534 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000535}
536
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000537VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200538 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000539 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000540 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800541 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
ilnik50864a82017-09-06 12:32:35 -0700542 stats_.content_type =
543 content_type_ == VideoEncoderConfig::ContentType::kRealtimeVideo
544 ? VideoContentType::UNSPECIFIED
545 : VideoContentType::SCREENSHARE;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000546 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000547}
548
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000549void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200550 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000551 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
552 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000553 it != stats_.substreams.end(); ++it) {
554 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200555 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
556 it->second.width = 0;
557 it->second.height = 0;
558 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000559 }
560}
561
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000562VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
563 uint32_t ssrc) {
564 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
565 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000566 if (it != stats_.substreams.end())
567 return &it->second;
568
brandtrcd188f62016-11-15 08:21:52 -0800569 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
570 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800571 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
572 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800573 bool is_rtx =
574 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
575 ssrc) != rtp_config_.rtx.ssrcs.end();
576 if (!is_media && !is_flexfec && !is_rtx)
577 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000578
asapersson2e5cfcd2016-08-11 08:41:18 -0700579 // Insert new entry and return ptr.
580 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
581 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800582 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700583
584 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000585}
586
Peter Boström20f3f942015-05-15 11:33:39 +0200587void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
588 rtc::CritScope lock(&crit_);
589 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200590 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200591 return;
592
593 stats->total_bitrate_bps = 0;
594 stats->retransmit_bitrate_bps = 0;
595 stats->height = 0;
596 stats->width = 0;
597}
598
perkjf5b2e512016-07-05 08:34:04 -0700599void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200600 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800601 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
602 return; // Start on first non-zero bitrate, may initially be zero.
603
604 int64_t now = clock_->TimeInMilliseconds();
605 if (uma_container_->target_rate_updates_.last_ms != -1) {
606 bool was_paused = stats_.target_media_bitrate_bps == 0;
607 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
608 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
609
610 // Use last to not include update when stream is stopped and video disabled.
611 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
612 ++uma_container_->target_rate_updates_.pause_resume_events;
613
614 // Check if video is paused/resumed.
615 uma_container_->target_rate_updates_.last_paused_or_resumed =
616 (bitrate_bps == 0) != was_paused;
617 }
618 uma_container_->target_rate_updates_.last_ms = now;
619
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000620 stats_.target_media_bitrate_bps = bitrate_bps;
621}
622
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000623void SendStatisticsProxy::OnSendEncodedImage(
624 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700625 const CodecSpecificInfo* codec_info) {
626 size_t simulcast_idx = 0;
627
perkj275afc52016-09-01 00:21:16 -0700628 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700629 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700630 if (codec_info) {
631 if (codec_info->codecType == kVideoCodecVP8) {
632 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
633 } else if (codec_info->codecType == kVideoCodecGeneric) {
634 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
635 }
perkj275afc52016-09-01 00:21:16 -0700636 if (codec_info->codec_name) {
637 stats_.encoder_implementation_name = codec_info->codec_name;
638 }
kjellander02b3d272016-04-20 05:05:54 -0700639 }
640
perkj26091b12016-09-01 01:17:40 -0700641 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000642 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700643 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000644 return;
645 }
perkj26091b12016-09-01 01:17:40 -0700646 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000647
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000648 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200649 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000650 return;
651
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000652 stats->width = encoded_image._encodedWidth;
653 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000654 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700655
sprangb4a1ae52015-12-03 08:10:08 -0800656 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
657 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800658 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800659 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
660 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800661
kthelgason0cd27ba2016-12-19 06:32:16 -0800662 if (quality_downscales_ != -1) {
663 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
664 if (quality_downscales_ > 0)
665 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700666 }
asaperssonda535c42015-10-19 23:32:41 -0700667 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
668 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800669 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700670 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800671 uma_container_->bw_resolutions_disabled_counter_.Add(
672 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700673 }
674 }
asapersson4306fc72015-10-19 00:35:21 -0700675
sakal87da4042016-10-31 06:53:47 -0700676 if (encoded_image.qp_ != -1) {
677 if (!stats_.qp_sum)
678 stats_.qp_sum = rtc::Optional<uint64_t>(0);
679 *stats_.qp_sum += encoded_image.qp_;
680
681 if (codec_info) {
682 if (codec_info->codecType == kVideoCodecVP8) {
683 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
684 ? -1
685 : static_cast<int>(simulcast_idx);
686 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
687 } else if (codec_info->codecType == kVideoCodecVP9) {
688 int spatial_idx =
689 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
690 ? -1
691 : codec_info->codecSpecific.VP9.spatial_idx;
692 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700693 } else if (codec_info->codecType == kVideoCodecH264) {
694 int spatial_idx = -1;
695 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700696 }
asapersson5265fed2016-04-18 02:58:47 -0700697 }
asapersson118ef002016-03-31 00:00:19 -0700698 }
699
asaperssond89920b2015-07-22 06:52:00 -0700700 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
701 // different threads and there is no guarantee that one frame of all layers
702 // are encoded before the next start.
703 if (last_sent_frame_timestamp_ > 0 &&
704 encoded_image._timeStamp != last_sent_frame_timestamp_) {
asapersson320e45a2016-11-29 01:40:35 -0800705 uma_container_->sent_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800706 uma_container_->sent_width_counter_.Add(
707 uma_container_->max_sent_width_per_timestamp_);
708 uma_container_->sent_height_counter_.Add(
709 uma_container_->max_sent_height_per_timestamp_);
710 uma_container_->max_sent_width_per_timestamp_ = 0;
711 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200712 }
asaperssond89920b2015-07-22 06:52:00 -0700713 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800714 uma_container_->max_sent_width_per_timestamp_ =
715 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700716 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800717 uma_container_->max_sent_height_per_timestamp_ =
718 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700719 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000720}
721
Per69b332d2016-06-02 15:45:42 +0200722int SendStatisticsProxy::GetSendFrameRate() const {
723 rtc::CritScope lock(&crit_);
724 return stats_.encode_frame_rate;
725}
726
asaperssond89920b2015-07-22 06:52:00 -0700727void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200728 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800729 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800730 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800731 uma_container_->input_width_counter_.Add(width);
732 uma_container_->input_height_counter_.Add(height);
asaperssonf4e44af2017-04-19 02:01:06 -0700733 if (cpu_downscales_ >= 0) {
734 uma_container_->cpu_limited_frame_counter_.Add(
735 stats_.cpu_limited_resolution);
736 }
perkj803d97f2016-11-01 11:45:46 -0700737}
738
asapersson09f05612017-05-15 23:40:18 -0700739void SendStatisticsProxy::SetAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700740 const VideoStreamEncoder::AdaptCounts& cpu_counts,
741 const VideoStreamEncoder::AdaptCounts& quality_counts) {
perkj803d97f2016-11-01 11:45:46 -0700742 rtc::CritScope lock(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700743 SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
744 SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
745 UpdateAdaptationStats(cpu_counts, quality_counts);
asapersson36e9eb42017-03-31 05:29:12 -0700746}
747
asapersson09f05612017-05-15 23:40:18 -0700748void SendStatisticsProxy::OnCpuAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700749 const VideoStreamEncoder::AdaptCounts& cpu_counts,
750 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson36e9eb42017-03-31 05:29:12 -0700751 rtc::CritScope lock(&crit_);
perkj803d97f2016-11-01 11:45:46 -0700752 ++stats_.number_of_cpu_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700753 UpdateAdaptationStats(cpu_counts, quality_counts);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000754}
755
asapersson09f05612017-05-15 23:40:18 -0700756void SendStatisticsProxy::OnQualityAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700757 const VideoStreamEncoder::AdaptCounts& cpu_counts,
758 const VideoStreamEncoder::AdaptCounts& quality_counts) {
kthelgason876222f2016-11-29 01:44:11 -0800759 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700760 ++stats_.number_of_quality_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700761 UpdateAdaptationStats(cpu_counts, quality_counts);
762}
763
764void SendStatisticsProxy::UpdateAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700765 const VideoStreamEncoder::AdaptCounts& cpu_counts,
766 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson09f05612017-05-15 23:40:18 -0700767 cpu_downscales_ = cpu_counts.resolution;
768 quality_downscales_ = quality_counts.resolution;
769
770 stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
771 stats_.cpu_limited_framerate = cpu_counts.fps > 0;
772 stats_.bw_limited_resolution = quality_counts.resolution > 0;
773 stats_.bw_limited_framerate = quality_counts.fps > 0;
774}
775
mflodmancc3d4422017-08-03 08:27:51 -0700776void SendStatisticsProxy::SetAdaptTimer(
777 const VideoStreamEncoder::AdaptCounts& counts,
778 StatsTimer* timer) {
asapersson09f05612017-05-15 23:40:18 -0700779 if (counts.resolution >= 0 || counts.fps >= 0) {
780 // Adaptation enabled.
781 if (!stats_.suspended)
782 timer->Start(clock_->TimeInMilliseconds());
783 return;
784 }
785 timer->Stop(clock_->TimeInMilliseconds());
kthelgason876222f2016-11-29 01:44:11 -0800786}
787
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000788void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
789 uint32_t ssrc,
790 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200791 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000792 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200793 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000794 return;
795
796 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800797 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
798 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000799}
800
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000801void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
802 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200803 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000804 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200805 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000806 return;
807
808 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800809 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000810}
811
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100812void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000813
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000814void SendStatisticsProxy::DataCountersUpdated(
815 const StreamDataCounters& counters,
816 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200817 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000818 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800819 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000820
asaperssona6a699a2016-11-25 03:52:46 -0800821 if (stats->is_flexfec) {
822 // The same counters are reported for both the media ssrc and flexfec ssrc.
823 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
824 return;
825 }
826
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000827 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -0700828 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
829 int64_t now_ms = clock_->TimeInMilliseconds();
830 uma_container_->first_rtp_stats_time_ms_ = now_ms;
asapersson09f05612017-05-15 23:40:18 -0700831 uma_container_->cpu_adapt_timer_.Restart(now_ms);
832 uma_container_->quality_adapt_timer_.Restart(now_ms);
asapersson6eca98b2017-04-04 23:40:50 -0700833 }
asapersson93e1e232017-02-06 05:18:35 -0800834
835 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
836 ssrc);
837 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
838 ssrc);
839 uma_container_->retransmit_byte_counter_.Set(
840 counters.retransmitted.TotalBytes(), ssrc);
841 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
842 if (stats->is_rtx) {
843 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
844 ssrc);
845 } else {
846 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
847 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000848}
849
sprangcd349d92016-07-13 09:11:28 -0700850void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
851 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000852 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200853 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000854 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200855 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000856 return;
857
sprangcd349d92016-07-13 09:11:28 -0700858 stats->total_bitrate_bps = total_bitrate_bps;
859 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000860}
861
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000862void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
863 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200864 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000865 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200866 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000867 return;
868
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000869 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000870}
871
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000872void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
873 int max_delay_ms,
874 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200875 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000876 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200877 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000878 return;
879 stats->avg_delay_ms = avg_delay_ms;
880 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800881
sprangb4a1ae52015-12-03 08:10:08 -0800882 uma_container_->delay_counter_.Add(avg_delay_ms);
883 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000884}
885
asapersson6eca98b2017-04-04 23:40:50 -0700886void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
887 if (start_ms == -1)
888 start_ms = now_ms;
889}
890
891void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
892 if (start_ms != -1) {
893 total_ms += now_ms - start_ms;
894 start_ms = -1;
895 }
896}
897
898void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
899 total_ms = 0;
900 if (start_ms != -1)
901 start_ms = now_ms;
902}
903
asaperssond89920b2015-07-22 06:52:00 -0700904void SendStatisticsProxy::SampleCounter::Add(int sample) {
905 sum += sample;
906 ++num_samples;
907}
908
asapersson66d4b372016-12-19 06:50:53 -0800909int SendStatisticsProxy::SampleCounter::Avg(
910 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -0700911 if (num_samples < min_required_samples || num_samples == 0)
912 return -1;
asapersson66d4b372016-12-19 06:50:53 -0800913 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -0700914}
915
asaperssondec5ebf2015-10-05 02:36:17 -0700916void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
917 if (sample)
918 ++sum;
919 ++num_samples;
920}
921
asapersson66d4b372016-12-19 06:50:53 -0800922void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
923 if (sample)
924 sum += count;
925 num_samples += count;
926}
asaperssondec5ebf2015-10-05 02:36:17 -0700927int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -0800928 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700929 return Fraction(min_required_samples, 100.0f);
930}
931
932int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -0800933 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700934 return Fraction(min_required_samples, 1000.0f);
935}
936
937int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -0800938 int64_t min_required_samples,
939 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700940 if (num_samples < min_required_samples || num_samples == 0)
941 return -1;
942 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
943}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000944} // namespace webrtc