blob: 822ed976953850087dc49d76fc0b125dcbf45508 [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
11#include "webrtc/video/send_statistics_proxy.h"
12
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
pbos@webrtc.org49096de2015-02-24 22:37:52 +000018#include "webrtc/base/checks.h"
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.h"
ehmaldonadof7f7fb92017-03-15 10:45:49 -070020#include "webrtc/base/trace_event.h"
deadbeefc964d0b2017-04-03 10:03:35 -070021#include "webrtc/common_types.h"
kjellander02b3d272016-04-20 05:05:54 -070022#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010023#include "webrtc/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;
28
asapersson2a0a2a42015-10-27 01:32:00 -070029// Used by histograms. Values of entries should not be changed.
30enum HistogramCodecType {
31 kVideoUnknown = 0,
32 kVideoVp8 = 1,
33 kVideoVp9 = 2,
34 kVideoH264 = 3,
35 kVideoMax = 64,
36};
37
asaperssonc2148a52016-02-04 00:33:21 -080038const char* kRealtimePrefix = "WebRTC.Video.";
39const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
40
sprangb4a1ae52015-12-03 08:10:08 -080041const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
42 switch (content_type) {
43 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080044 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080045 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080046 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080047 }
48 RTC_NOTREACHED();
49 return nullptr;
50}
51
asapersson2a0a2a42015-10-27 01:32:00 -070052HistogramCodecType PayloadNameToHistogramCodecType(
53 const std::string& payload_name) {
deadbeefc964d0b2017-04-03 10:03:35 -070054 rtc::Optional<VideoCodecType> codecType =
55 PayloadNameToCodecType(payload_name);
56 if (!codecType) {
asapersson2a0a2a42015-10-27 01:32:00 -070057 return kVideoUnknown;
58 }
deadbeefc964d0b2017-04-03 10:03:35 -070059 switch (*codecType) {
60 case kVideoCodecVP8:
61 return kVideoVp8;
62 case kVideoCodecVP9:
63 return kVideoVp9;
64 case kVideoCodecH264:
65 return kVideoH264;
66 default:
67 return kVideoUnknown;
68 }
asapersson2a0a2a42015-10-27 01:32:00 -070069}
70
71void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080072 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
73 PayloadNameToHistogramCodecType(payload_name),
74 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070075}
76} // namespace
77
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000078
pbos@webrtc.org273a4142014-12-01 15:23:21 +000079const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
80
sprangb4a1ae52015-12-03 08:10:08 -080081SendStatisticsProxy::SendStatisticsProxy(
82 Clock* clock,
83 const VideoSendStream::Config& config,
84 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070085 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -070086 payload_name_(config.encoder_settings.payload_name),
87 rtp_config_(config.rtp),
sprangb4a1ae52015-12-03 08:10:08 -080088 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -070089 start_ms_(clock->TimeInMilliseconds()),
asaperssond89920b2015-07-22 06:52:00 -070090 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080091 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -070092 quality_downscales_(-1),
93 cpu_downscales_(-1),
sprang07fb9be2016-02-24 07:55:00 -080094 uma_container_(
95 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000096}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000097
sprang07fb9be2016-02-24 07:55:00 -080098SendStatisticsProxy::~SendStatisticsProxy() {
99 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -0700100 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -0700101
102 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700103 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
104 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700105
106 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700107 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800108}
sprangb4a1ae52015-12-03 08:10:08 -0800109
110SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800111 const char* prefix,
112 const VideoSendStream::Stats& stats,
113 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800114 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800115 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800116 max_sent_width_per_timestamp_(0),
117 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700118 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800119 input_fps_counter_(clock, nullptr, true),
120 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800121 total_byte_counter_(clock, nullptr, true),
122 media_byte_counter_(clock, nullptr, true),
123 rtx_byte_counter_(clock, nullptr, true),
124 padding_byte_counter_(clock, nullptr, true),
125 retransmit_byte_counter_(clock, nullptr, true),
126 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800127 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100128 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800129 start_stats_(stats) {
130 InitializeBitrateCounters(stats);
131}
sprangb4a1ae52015-12-03 08:10:08 -0800132
sprang07fb9be2016-02-24 07:55:00 -0800133SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200134
asapersson93e1e232017-02-06 05:18:35 -0800135void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
136 const VideoSendStream::Stats& stats) {
137 for (const auto& it : stats.substreams) {
138 uint32_t ssrc = it.first;
139 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
140 ssrc);
141 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
142 ssrc);
143 retransmit_byte_counter_.SetLast(
144 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
145 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
146 if (it.second.is_rtx) {
147 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
148 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100149 } else {
asapersson93e1e232017-02-06 05:18:35 -0800150 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
151 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100152 }
153 }
154}
155
sprang07fb9be2016-02-24 07:55:00 -0800156void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700157 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800158 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800159 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
160 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800161 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700162 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
163 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700164 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700165 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
166 in_width);
167 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
168 in_height);
asaperssond89920b2015-07-22 06:52:00 -0700169 }
asapersson320e45a2016-11-29 01:40:35 -0800170 AggregatedStats in_fps = input_fps_counter_.GetStats();
171 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
172 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
173 in_fps.average);
174 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
175 }
176
perkj803d97f2016-11-01 11:45:46 -0700177 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
178 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700179 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700180 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
181 sent_width);
182 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
183 sent_height);
asaperssond89920b2015-07-22 06:52:00 -0700184 }
asapersson320e45a2016-11-29 01:40:35 -0800185 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
186 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
187 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
188 sent_fps.average);
189 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
190 << sent_fps.ToString();
191 }
192
perkj803d97f2016-11-01 11:45:46 -0700193 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800194 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700195 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
196 encode_ms);
asaperssonc2148a52016-02-04 00:33:21 -0800197 }
perkj803d97f2016-11-01 11:45:46 -0700198 int key_frames_permille =
199 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700200 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700201 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
202 key_frames_permille);
asaperssondec5ebf2015-10-05 02:36:17 -0700203 }
asapersson4306fc72015-10-19 00:35:21 -0700204 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700205 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700206 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700207 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
208 uma_prefix_ + "QualityLimitedResolutionInPercent",
209 quality_limited);
asapersson4306fc72015-10-19 00:35:21 -0700210 }
perkj803d97f2016-11-01 11:45:46 -0700211 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700212 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700213 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800214 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
215 20);
asapersson4306fc72015-10-19 00:35:21 -0700216 }
perkj803d97f2016-11-01 11:45:46 -0700217 int cpu_limited =
218 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
219 if (cpu_limited != -1) {
220 RTC_HISTOGRAMS_PERCENTAGE(
221 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
222 }
223 int bw_limited =
224 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700225 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700226 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800227 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
228 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700229 }
perkj803d97f2016-11-01 11:45:46 -0700230 int num_disabled =
231 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700232 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700233 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800234 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
235 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700236 }
perkj803d97f2016-11-01 11:45:46 -0700237 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800238 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700239 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
240 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800241
perkj803d97f2016-11-01 11:45:46 -0700242 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800243 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700244 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
245 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800246 }
sprang07fb9be2016-02-24 07:55:00 -0800247
asapersson118ef002016-03-31 00:00:19 -0700248 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700249 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700250 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700251 int spatial_idx = it.first;
252 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700253 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
254 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700255 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700256 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
257 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700258 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700259 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
260 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700261 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700262 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
263 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700264 } else {
265 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
266 << spatial_idx;
267 }
268 }
perkj803d97f2016-11-01 11:45:46 -0700269 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700270 if (qp_vp9 != -1) {
271 int spatial_idx = it.first;
272 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700273 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
274 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700275 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700276 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
277 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700278 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700279 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
280 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700281 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700282 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
283 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700284 } else {
285 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
286 << spatial_idx;
287 }
288 }
asapersson827cab32016-11-02 09:08:47 -0700289 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
290 if (qp_h264 != -1) {
291 int spatial_idx = it.first;
292 RTC_DCHECK_EQ(-1, spatial_idx);
293 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
294 qp_h264);
295 }
asapersson118ef002016-03-31 00:00:19 -0700296 }
297
asapersson0944a802017-04-07 00:57:58 -0700298 if (first_rtp_stats_time_ms_ != -1) {
299 quality_scaling_timer_.Stop(clock_->TimeInMilliseconds());
300 int64_t elapsed_sec = quality_scaling_timer_.total_ms / 1000;
301 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
302 int quality_changes = current_stats.number_of_quality_adapt_changes -
303 start_stats_.number_of_quality_adapt_changes;
304 RTC_HISTOGRAMS_COUNTS_100(kIndex,
305 uma_prefix_ + "AdaptChangesPerMinute.Quality",
306 quality_changes * 60 / elapsed_sec);
307 }
308 cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds());
309 elapsed_sec = cpu_scaling_timer_.total_ms / 1000;
310 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
311 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
312 start_stats_.number_of_cpu_adapt_changes;
313 RTC_HISTOGRAMS_COUNTS_100(kIndex,
314 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
315 cpu_changes * 60 / elapsed_sec);
316 }
asapersson6eca98b2017-04-04 23:40:50 -0700317 }
318
sprange2d83d62016-02-19 09:03:26 -0800319 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800320 int64_t elapsed_sec =
321 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
322 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
323 int fraction_lost = report_block_stats_.FractionLostInPercent();
324 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700325 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800326 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
327 }
328
329 // The RTCP packet type counters, delivered via the
330 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
331 // life of the send stream and are not reset when switching content type.
332 // For the purpose of these statistics though, we want new counts when
333 // switching since we switch histogram name. On every reset of the
334 // UmaSamplesContainer, we save the initial state of the counters, so that
335 // we can calculate the delta here and aggregate over all ssrcs.
336 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700337 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800338 auto kv = current_stats.substreams.find(ssrc);
339 if (kv == current_stats.substreams.end())
340 continue;
341
342 RtcpPacketTypeCounter stream_counters =
343 kv->second.rtcp_packet_type_counts;
344 kv = start_stats_.substreams.find(ssrc);
345 if (kv != start_stats_.substreams.end())
346 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
347
348 counters.Add(stream_counters);
349 }
asapersson1d02d3e2016-09-09 22:40:25 -0700350 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
351 uma_prefix_ + "NackPacketsReceivedPerMinute",
352 counters.nack_packets * 60 / elapsed_sec);
353 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
354 uma_prefix_ + "FirPacketsReceivedPerMinute",
355 counters.fir_packets * 60 / elapsed_sec);
356 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
357 uma_prefix_ + "PliPacketsReceivedPerMinute",
358 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800359 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700360 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800361 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
362 counters.UniqueNackRequestsInPercent());
363 }
sprange2d83d62016-02-19 09:03:26 -0800364 }
365 }
Erik Språng22c2b482016-03-01 09:40:42 +0100366
367 if (first_rtp_stats_time_ms_ != -1) {
368 int64_t elapsed_sec =
369 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
370 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800371 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
372 target_rate_updates_.pause_resume_events);
373
374 int paused_time_percent =
375 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
376 if (paused_time_percent != -1) {
377 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
378 paused_time_percent);
379 }
asapersson93e1e232017-02-06 05:18:35 -0800380 }
381 }
asapersson66d4b372016-12-19 06:50:53 -0800382
asapersson93e1e232017-02-06 05:18:35 -0800383 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
384 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
385 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
386 total_bytes_per_sec.average * 8 / 1000);
387 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
388 << total_bytes_per_sec.ToStringWithMultiplier(8);
389 }
390 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
391 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
392 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
393 media_bytes_per_sec.average * 8 / 1000);
394 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
395 << media_bytes_per_sec.ToStringWithMultiplier(8);
396 }
397 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
398 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
399 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
400 uma_prefix_ + "PaddingBitrateSentInKbps",
401 padding_bytes_per_sec.average * 8 / 1000);
402 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
403 << padding_bytes_per_sec.ToStringWithMultiplier(8);
404 }
405 AggregatedStats retransmit_bytes_per_sec =
406 retransmit_byte_counter_.GetStats();
407 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
408 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
409 uma_prefix_ + "RetransmittedBitrateSentInKbps",
410 retransmit_bytes_per_sec.average * 8 / 1000);
411 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
412 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
413 }
414 if (!rtp_config.rtx.ssrcs.empty()) {
415 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
416 int rtx_bytes_per_sec_avg = -1;
417 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
418 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
419 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
420 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
421 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
422 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
423 }
424 if (rtx_bytes_per_sec_avg != -1) {
425 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
426 rtx_bytes_per_sec_avg * 8 / 1000);
427 }
428 }
429 if (rtp_config.flexfec.payload_type != -1 ||
430 rtp_config.ulpfec.red_payload_type != -1) {
431 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
432 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
433 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
434 fec_bytes_per_sec.average * 8 / 1000);
435 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
436 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100437 }
438 }
sprangb4a1ae52015-12-03 08:10:08 -0800439}
440
Pera48ddb72016-09-29 11:48:50 +0200441void SendStatisticsProxy::OnEncoderReconfigured(
442 const VideoEncoderConfig& config,
443 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800444 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200445 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
446
447 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700448 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200449 uma_container_.reset(new UmaSamplesContainer(
450 GetUmaPrefix(config.content_type), stats_, clock_));
451 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800452 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200453}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000454
perkj275afc52016-09-01 00:21:16 -0700455void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
456 uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200457 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000458 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000459 stats_.media_bitrate_bps = bitrate;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700460 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FrameRateSent",
461 "frame_rate", framerate, "ssrc", rtp_config_.ssrcs[0]);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000462}
463
Peter Boströme4499152016-02-05 11:13:28 +0100464void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
465 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000466 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200467 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100468 uma_container_->encode_time_counter_.Add(encode_time_ms);
469 encode_time_.Apply(1.0f, encode_time_ms);
470 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000471 stats_.encode_usage_percent = metrics.encode_usage_percent;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700472 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeTimeInMs",
473 "encode_time_ms", stats_.avg_encode_time_ms,
474 "ssrc", rtp_config_.ssrcs[0]);
475 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeUsagePercent",
476 "encode_usage_percent", stats_.encode_usage_percent,
477 "ssrc", rtp_config_.ssrcs[0]);
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000478}
479
Peter Boström7083e112015-09-22 16:28:51 +0200480void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700481 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200482 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000483 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800484 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800485 // Pause framerate (add min pause time since there may be frames/packets
486 // that are not yet sent).
487 const int64_t kMinMs = 500;
488 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
489 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
490 // Pause bitrate stats.
491 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
492 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
493 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
494 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
495 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
496 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700497 // Stop adaptation stats.
498 uma_container_->cpu_scaling_timer_.Stop(now_ms);
499 uma_container_->quality_scaling_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800500 } else {
asapersson0944a802017-04-07 00:57:58 -0700501 // Start adaptation stats if scaling is enabled.
502 if (cpu_downscales_ >= 0)
503 uma_container_->cpu_scaling_timer_.Start(now_ms);
504 if (quality_downscales_ >= 0)
505 uma_container_->quality_scaling_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800506 // Stop pause explicitly for stats that may be zero/not updated for some
507 // time.
508 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
509 uma_container_->padding_byte_counter_.ProcessAndStopPause();
510 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
511 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800512 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000513}
514
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000515VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200516 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000517 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000518 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800519 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000520 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000521}
522
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000523void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200524 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000525 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
526 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000527 it != stats_.substreams.end(); ++it) {
528 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200529 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
530 it->second.width = 0;
531 it->second.height = 0;
532 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000533 }
534}
535
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000536VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
537 uint32_t ssrc) {
538 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
539 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000540 if (it != stats_.substreams.end())
541 return &it->second;
542
brandtrcd188f62016-11-15 08:21:52 -0800543 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
544 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800545 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
546 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800547 bool is_rtx =
548 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
549 ssrc) != rtp_config_.rtx.ssrcs.end();
550 if (!is_media && !is_flexfec && !is_rtx)
551 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000552
asapersson2e5cfcd2016-08-11 08:41:18 -0700553 // Insert new entry and return ptr.
554 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
555 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800556 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700557
558 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000559}
560
Peter Boström20f3f942015-05-15 11:33:39 +0200561void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
562 rtc::CritScope lock(&crit_);
563 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200564 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200565 return;
566
567 stats->total_bitrate_bps = 0;
568 stats->retransmit_bitrate_bps = 0;
569 stats->height = 0;
570 stats->width = 0;
571}
572
perkjf5b2e512016-07-05 08:34:04 -0700573void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200574 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800575 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
576 return; // Start on first non-zero bitrate, may initially be zero.
577
578 int64_t now = clock_->TimeInMilliseconds();
579 if (uma_container_->target_rate_updates_.last_ms != -1) {
580 bool was_paused = stats_.target_media_bitrate_bps == 0;
581 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
582 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
583
584 // Use last to not include update when stream is stopped and video disabled.
585 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
586 ++uma_container_->target_rate_updates_.pause_resume_events;
587
588 // Check if video is paused/resumed.
589 uma_container_->target_rate_updates_.last_paused_or_resumed =
590 (bitrate_bps == 0) != was_paused;
591 }
592 uma_container_->target_rate_updates_.last_ms = now;
593
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000594 stats_.target_media_bitrate_bps = bitrate_bps;
595}
596
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000597void SendStatisticsProxy::OnSendEncodedImage(
598 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700599 const CodecSpecificInfo* codec_info) {
600 size_t simulcast_idx = 0;
601
perkj275afc52016-09-01 00:21:16 -0700602 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700603 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700604 if (codec_info) {
605 if (codec_info->codecType == kVideoCodecVP8) {
606 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
607 } else if (codec_info->codecType == kVideoCodecGeneric) {
608 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
609 }
perkj275afc52016-09-01 00:21:16 -0700610 if (codec_info->codec_name) {
611 stats_.encoder_implementation_name = codec_info->codec_name;
612 }
kjellander02b3d272016-04-20 05:05:54 -0700613 }
614
perkj26091b12016-09-01 01:17:40 -0700615 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000616 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700617 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000618 return;
619 }
perkj26091b12016-09-01 01:17:40 -0700620 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000621
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000622 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200623 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000624 return;
625
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000626 stats->width = encoded_image._encodedWidth;
627 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000628 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700629
sprangb4a1ae52015-12-03 08:10:08 -0800630 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
631 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800632 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800633 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
634 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800635
kthelgason0cd27ba2016-12-19 06:32:16 -0800636 if (quality_downscales_ != -1) {
637 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
638 if (quality_downscales_ > 0)
639 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700640 }
asaperssonda535c42015-10-19 23:32:41 -0700641 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
642 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800643 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700644 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800645 uma_container_->bw_resolutions_disabled_counter_.Add(
646 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700647 }
648 }
asapersson4306fc72015-10-19 00:35:21 -0700649
sakal87da4042016-10-31 06:53:47 -0700650 if (encoded_image.qp_ != -1) {
651 if (!stats_.qp_sum)
652 stats_.qp_sum = rtc::Optional<uint64_t>(0);
653 *stats_.qp_sum += encoded_image.qp_;
654
655 if (codec_info) {
656 if (codec_info->codecType == kVideoCodecVP8) {
657 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
658 ? -1
659 : static_cast<int>(simulcast_idx);
660 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
661 } else if (codec_info->codecType == kVideoCodecVP9) {
662 int spatial_idx =
663 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
664 ? -1
665 : codec_info->codecSpecific.VP9.spatial_idx;
666 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700667 } else if (codec_info->codecType == kVideoCodecH264) {
668 int spatial_idx = -1;
669 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700670 }
asapersson5265fed2016-04-18 02:58:47 -0700671 }
asapersson118ef002016-03-31 00:00:19 -0700672 }
673
asaperssond89920b2015-07-22 06:52:00 -0700674 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
675 // different threads and there is no guarantee that one frame of all layers
676 // are encoded before the next start.
677 if (last_sent_frame_timestamp_ > 0 &&
678 encoded_image._timeStamp != last_sent_frame_timestamp_) {
asapersson320e45a2016-11-29 01:40:35 -0800679 uma_container_->sent_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800680 uma_container_->sent_width_counter_.Add(
681 uma_container_->max_sent_width_per_timestamp_);
682 uma_container_->sent_height_counter_.Add(
683 uma_container_->max_sent_height_per_timestamp_);
684 uma_container_->max_sent_width_per_timestamp_ = 0;
685 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200686 }
asaperssond89920b2015-07-22 06:52:00 -0700687 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800688 uma_container_->max_sent_width_per_timestamp_ =
689 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700690 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800691 uma_container_->max_sent_height_per_timestamp_ =
692 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700693 static_cast<int>(encoded_image._encodedHeight));
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700694
695 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentWidthInPixels",
696 "frame_width", encoded_image._encodedWidth, "ssrc", ssrc);
697 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentHeightInPixels",
698 "frame_height", encoded_image._encodedHeight, "ssrc", ssrc);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000699}
700
Per69b332d2016-06-02 15:45:42 +0200701int SendStatisticsProxy::GetSendFrameRate() const {
702 rtc::CritScope lock(&crit_);
703 return stats_.encode_frame_rate;
704}
705
asaperssond89920b2015-07-22 06:52:00 -0700706void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200707 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800708 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800709 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800710 uma_container_->input_width_counter_.Add(width);
711 uma_container_->input_height_counter_.Add(height);
perkj803d97f2016-11-01 11:45:46 -0700712 uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700713 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.InputFrameRate",
714 "frame_rate", round(
715 uma_container_->input_frame_rate_tracker_.ComputeRate()),
716 "ssrc", rtp_config_.ssrcs[0]);
perkj803d97f2016-11-01 11:45:46 -0700717}
718
asapersson6eca98b2017-04-04 23:40:50 -0700719void SendStatisticsProxy::SetCpuScalingStats(int num_cpu_downscales) {
perkj803d97f2016-11-01 11:45:46 -0700720 rtc::CritScope lock(&crit_);
asapersson0944a802017-04-07 00:57:58 -0700721 cpu_downscales_ = num_cpu_downscales;
asapersson6eca98b2017-04-04 23:40:50 -0700722 stats_.cpu_limited_resolution = num_cpu_downscales > 0;
723
724 if (num_cpu_downscales >= 0) {
725 // Scaling enabled.
asapersson0944a802017-04-07 00:57:58 -0700726 if (!stats_.suspended)
727 uma_container_->cpu_scaling_timer_.Start(clock_->TimeInMilliseconds());
728 return;
asapersson6eca98b2017-04-04 23:40:50 -0700729 }
asapersson0944a802017-04-07 00:57:58 -0700730 uma_container_->cpu_scaling_timer_.Stop(clock_->TimeInMilliseconds());
asapersson36e9eb42017-03-31 05:29:12 -0700731}
732
733void SendStatisticsProxy::SetQualityScalingStats(int num_quality_downscales) {
734 rtc::CritScope lock(&crit_);
735 quality_downscales_ = num_quality_downscales;
736 stats_.bw_limited_resolution = quality_downscales_ > 0;
asapersson6eca98b2017-04-04 23:40:50 -0700737
738 if (num_quality_downscales >= 0) {
739 // Scaling enabled.
asapersson0944a802017-04-07 00:57:58 -0700740 if (!stats_.suspended) {
741 uma_container_->quality_scaling_timer_.Start(
742 clock_->TimeInMilliseconds());
743 }
744 return;
asapersson6eca98b2017-04-04 23:40:50 -0700745 }
asapersson0944a802017-04-07 00:57:58 -0700746 uma_container_->quality_scaling_timer_.Stop(clock_->TimeInMilliseconds());
perkj803d97f2016-11-01 11:45:46 -0700747}
748
749void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
750 bool cpu_restricted_resolution) {
751 rtc::CritScope lock(&crit_);
752 stats_.cpu_limited_resolution = cpu_restricted_resolution;
753 ++stats_.number_of_cpu_adapt_changes;
asapersson6eca98b2017-04-04 23:40:50 -0700754 TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.CpuAdaptationChanges");
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000755}
756
kthelgason876222f2016-11-29 01:44:11 -0800757void SendStatisticsProxy::OnQualityRestrictedResolutionChanged(
kthelgason0cd27ba2016-12-19 06:32:16 -0800758 int num_quality_downscales) {
kthelgason876222f2016-11-29 01:44:11 -0800759 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700760 ++stats_.number_of_quality_adapt_changes;
kthelgason0cd27ba2016-12-19 06:32:16 -0800761 quality_downscales_ = num_quality_downscales;
762 stats_.bw_limited_resolution = quality_downscales_ > 0;
kthelgason876222f2016-11-29 01:44:11 -0800763}
764
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000765void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
766 uint32_t ssrc,
767 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200768 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000769 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200770 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000771 return;
772
773 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800774 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
775 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700776
777 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FirPacketsReceived",
778 "fir_packets_received", packet_counter.fir_packets, "ssrc", ssrc);
779 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.NackPacketsReceived",
780 "nack_packets_received", packet_counter.nack_packets, "ssrc", ssrc);
781 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.PliPacketsReceived",
782 "pli_packets_received", packet_counter.pli_packets, "ssrc", ssrc);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000783}
784
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000785void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
786 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200787 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000788 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200789 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000790 return;
791
792 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800793 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700794
795 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPacketsLost",
796 "packets_lost", statistics.cumulative_lost, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000797}
798
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100799void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000800
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000801void SendStatisticsProxy::DataCountersUpdated(
802 const StreamDataCounters& counters,
803 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200804 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000805 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800806 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000807
asaperssona6a699a2016-11-25 03:52:46 -0800808 if (stats->is_flexfec) {
809 // The same counters are reported for both the media ssrc and flexfec ssrc.
810 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
811 return;
812 }
813
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000814 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -0700815 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
816 int64_t now_ms = clock_->TimeInMilliseconds();
817 uma_container_->first_rtp_stats_time_ms_ = now_ms;
818 uma_container_->cpu_scaling_timer_.Restart(now_ms);
819 uma_container_->quality_scaling_timer_.Restart(now_ms);
820 }
asapersson93e1e232017-02-06 05:18:35 -0800821
822 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
823 ssrc);
824 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
825 ssrc);
826 uma_container_->retransmit_byte_counter_.Set(
827 counters.retransmitted.TotalBytes(), ssrc);
828 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
829 if (stats->is_rtx) {
830 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
831 ssrc);
832 } else {
833 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
834 }
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700835
836 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPackets",
837 "packets_sent", counters.transmitted.packets, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000838}
839
sprangcd349d92016-07-13 09:11:28 -0700840void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
841 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000842 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200843 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000844 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200845 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000846 return;
847
sprangcd349d92016-07-13 09:11:28 -0700848 stats->total_bitrate_bps = total_bitrate_bps;
849 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000850}
851
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000852void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
853 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200854 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000855 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200856 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000857 return;
858
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000859 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000860}
861
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000862void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
863 int max_delay_ms,
864 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200865 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000866 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200867 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000868 return;
869 stats->avg_delay_ms = avg_delay_ms;
870 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800871
sprangb4a1ae52015-12-03 08:10:08 -0800872 uma_container_->delay_counter_.Add(avg_delay_ms);
873 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000874}
875
asapersson6eca98b2017-04-04 23:40:50 -0700876void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
877 if (start_ms == -1)
878 start_ms = now_ms;
879}
880
881void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
882 if (start_ms != -1) {
883 total_ms += now_ms - start_ms;
884 start_ms = -1;
885 }
886}
887
888void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
889 total_ms = 0;
890 if (start_ms != -1)
891 start_ms = now_ms;
892}
893
asaperssond89920b2015-07-22 06:52:00 -0700894void SendStatisticsProxy::SampleCounter::Add(int sample) {
895 sum += sample;
896 ++num_samples;
897}
898
asapersson66d4b372016-12-19 06:50:53 -0800899int SendStatisticsProxy::SampleCounter::Avg(
900 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -0700901 if (num_samples < min_required_samples || num_samples == 0)
902 return -1;
asapersson66d4b372016-12-19 06:50:53 -0800903 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -0700904}
905
asaperssondec5ebf2015-10-05 02:36:17 -0700906void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
907 if (sample)
908 ++sum;
909 ++num_samples;
910}
911
asapersson66d4b372016-12-19 06:50:53 -0800912void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
913 if (sample)
914 sum += count;
915 num_samples += count;
916}
asaperssondec5ebf2015-10-05 02:36:17 -0700917int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -0800918 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700919 return Fraction(min_required_samples, 100.0f);
920}
921
922int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -0800923 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700924 return Fraction(min_required_samples, 1000.0f);
925}
926
927int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -0800928 int64_t min_required_samples,
929 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700930 if (num_samples < min_required_samples || num_samples == 0)
931 return -1;
932 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
933}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000934} // namespace webrtc