blob: de9ee766214c56985074fcc6a142cb5d64326a73 [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
deadbeefc964d0b2017-04-03 10:03:35 -070018#include "webrtc/common_types.h"
kjellander02b3d272016-04-20 05:05:54 -070019#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020020#include "webrtc/rtc_base/checks.h"
21#include "webrtc/rtc_base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010022#include "webrtc/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) {
deadbeefc964d0b2017-04-03 10:03:35 -070053 rtc::Optional<VideoCodecType> codecType =
54 PayloadNameToCodecType(payload_name);
55 if (!codecType) {
asapersson2a0a2a42015-10-27 01:32:00 -070056 return kVideoUnknown;
57 }
deadbeefc964d0b2017-04-03 10:03:35 -070058 switch (*codecType) {
59 case kVideoCodecVP8:
60 return kVideoVp8;
61 case kVideoCodecVP9:
62 return kVideoVp9;
63 case kVideoCodecH264:
64 return kVideoH264;
65 default:
66 return kVideoUnknown;
67 }
asapersson2a0a2a42015-10-27 01:32:00 -070068}
69
70void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080071 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
72 PayloadNameToHistogramCodecType(payload_name),
73 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070074}
75} // namespace
76
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000077
pbos@webrtc.org273a4142014-12-01 15:23:21 +000078const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
79
sprangb4a1ae52015-12-03 08:10:08 -080080SendStatisticsProxy::SendStatisticsProxy(
81 Clock* clock,
82 const VideoSendStream::Config& config,
83 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070084 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -070085 payload_name_(config.encoder_settings.payload_name),
86 rtp_config_(config.rtp),
sprangb4a1ae52015-12-03 08:10:08 -080087 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -070088 start_ms_(clock->TimeInMilliseconds()),
asaperssond89920b2015-07-22 06:52:00 -070089 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080090 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -070091 quality_downscales_(-1),
92 cpu_downscales_(-1),
sprang07fb9be2016-02-24 07:55:00 -080093 uma_container_(
94 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000095}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000096
sprang07fb9be2016-02-24 07:55:00 -080097SendStatisticsProxy::~SendStatisticsProxy() {
98 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -070099 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -0700100
101 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700102 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
103 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700104
105 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700106 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800107}
sprangb4a1ae52015-12-03 08:10:08 -0800108
109SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800110 const char* prefix,
111 const VideoSendStream::Stats& stats,
112 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800113 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800114 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800115 max_sent_width_per_timestamp_(0),
116 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700117 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800118 input_fps_counter_(clock, nullptr, true),
119 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800120 total_byte_counter_(clock, nullptr, true),
121 media_byte_counter_(clock, nullptr, true),
122 rtx_byte_counter_(clock, nullptr, true),
123 padding_byte_counter_(clock, nullptr, true),
124 retransmit_byte_counter_(clock, nullptr, true),
125 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800126 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100127 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800128 start_stats_(stats) {
129 InitializeBitrateCounters(stats);
130}
sprangb4a1ae52015-12-03 08:10:08 -0800131
sprang07fb9be2016-02-24 07:55:00 -0800132SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200133
asapersson93e1e232017-02-06 05:18:35 -0800134void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
135 const VideoSendStream::Stats& stats) {
136 for (const auto& it : stats.substreams) {
137 uint32_t ssrc = it.first;
138 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
139 ssrc);
140 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
141 ssrc);
142 retransmit_byte_counter_.SetLast(
143 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
144 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
145 if (it.second.is_rtx) {
146 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
147 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100148 } else {
asapersson93e1e232017-02-06 05:18:35 -0800149 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
150 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100151 }
152 }
153}
154
sprang07fb9be2016-02-24 07:55:00 -0800155void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700156 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800157 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800158 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
159 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800160 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700161 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
162 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700163 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700164 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
165 in_width);
166 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
167 in_height);
asapersson2077f2f2017-05-11 05:37:35 -0700168 LOG(LS_INFO) << uma_prefix_ << "InputWidthInPixels " << in_width;
169 LOG(LS_INFO) << uma_prefix_ << "InputHeightInPixels " << in_height;
asaperssond89920b2015-07-22 06:52:00 -0700170 }
asapersson320e45a2016-11-29 01:40:35 -0800171 AggregatedStats in_fps = input_fps_counter_.GetStats();
172 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
173 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
174 in_fps.average);
175 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
176 }
177
perkj803d97f2016-11-01 11:45:46 -0700178 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
179 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700180 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700181 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
182 sent_width);
183 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
184 sent_height);
asapersson2077f2f2017-05-11 05:37:35 -0700185 LOG(LS_INFO) << uma_prefix_ << "SentWidthInPixels " << sent_width;
186 LOG(LS_INFO) << uma_prefix_ << "SentHeightInPixels " << sent_height;
asaperssond89920b2015-07-22 06:52:00 -0700187 }
asapersson320e45a2016-11-29 01:40:35 -0800188 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
189 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
190 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
191 sent_fps.average);
192 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
193 << sent_fps.ToString();
194 }
195
perkj803d97f2016-11-01 11:45:46 -0700196 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800197 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700198 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
199 encode_ms);
asapersson2077f2f2017-05-11 05:37:35 -0700200 LOG(LS_INFO) << uma_prefix_ << "EncodeTimeInMs " << encode_ms;
asaperssonc2148a52016-02-04 00:33:21 -0800201 }
perkj803d97f2016-11-01 11:45:46 -0700202 int key_frames_permille =
203 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700204 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700205 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
206 key_frames_permille);
asapersson2077f2f2017-05-11 05:37:35 -0700207 LOG(LS_INFO) << uma_prefix_ << "KeyFramesSentInPermille "
208 << key_frames_permille;
asaperssondec5ebf2015-10-05 02:36:17 -0700209 }
asapersson4306fc72015-10-19 00:35:21 -0700210 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700211 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700212 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700213 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
214 uma_prefix_ + "QualityLimitedResolutionInPercent",
215 quality_limited);
asapersson2077f2f2017-05-11 05:37:35 -0700216 LOG(LS_INFO) << uma_prefix_ << "QualityLimitedResolutionInPercent "
217 << quality_limited;
asapersson4306fc72015-10-19 00:35:21 -0700218 }
perkj803d97f2016-11-01 11:45:46 -0700219 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700220 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700221 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800222 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
223 20);
asapersson4306fc72015-10-19 00:35:21 -0700224 }
perkj803d97f2016-11-01 11:45:46 -0700225 int cpu_limited =
226 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
227 if (cpu_limited != -1) {
228 RTC_HISTOGRAMS_PERCENTAGE(
229 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
230 }
231 int bw_limited =
232 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700233 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700234 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800235 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
236 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700237 }
perkj803d97f2016-11-01 11:45:46 -0700238 int num_disabled =
239 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700240 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700241 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800242 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
243 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700244 }
perkj803d97f2016-11-01 11:45:46 -0700245 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800246 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700247 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
248 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800249
perkj803d97f2016-11-01 11:45:46 -0700250 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800251 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700252 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
253 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800254 }
sprang07fb9be2016-02-24 07:55:00 -0800255
asapersson118ef002016-03-31 00:00:19 -0700256 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700257 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700258 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700259 int spatial_idx = it.first;
260 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700261 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
262 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700263 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700264 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
265 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700266 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700267 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
268 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700269 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700270 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
271 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700272 } else {
273 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
274 << spatial_idx;
275 }
276 }
perkj803d97f2016-11-01 11:45:46 -0700277 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700278 if (qp_vp9 != -1) {
279 int spatial_idx = it.first;
280 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700281 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
282 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700283 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700284 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
285 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700286 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700287 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
288 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700289 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700290 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
291 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700292 } else {
293 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
294 << spatial_idx;
295 }
296 }
asapersson827cab32016-11-02 09:08:47 -0700297 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
298 if (qp_h264 != -1) {
299 int spatial_idx = it.first;
300 RTC_DCHECK_EQ(-1, spatial_idx);
301 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
302 qp_h264);
303 }
asapersson118ef002016-03-31 00:00:19 -0700304 }
305
asapersson0944a802017-04-07 00:57:58 -0700306 if (first_rtp_stats_time_ms_ != -1) {
asapersson09f05612017-05-15 23:40:18 -0700307 quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
308 int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700309 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
310 int quality_changes = current_stats.number_of_quality_adapt_changes -
311 start_stats_.number_of_quality_adapt_changes;
312 RTC_HISTOGRAMS_COUNTS_100(kIndex,
313 uma_prefix_ + "AdaptChangesPerMinute.Quality",
314 quality_changes * 60 / elapsed_sec);
315 }
asapersson09f05612017-05-15 23:40:18 -0700316 cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
317 elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700318 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
319 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
320 start_stats_.number_of_cpu_adapt_changes;
321 RTC_HISTOGRAMS_COUNTS_100(kIndex,
322 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
323 cpu_changes * 60 / elapsed_sec);
324 }
asapersson6eca98b2017-04-04 23:40:50 -0700325 }
326
sprange2d83d62016-02-19 09:03:26 -0800327 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800328 int64_t elapsed_sec =
329 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
330 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
331 int fraction_lost = report_block_stats_.FractionLostInPercent();
332 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700333 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800334 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
asapersson2077f2f2017-05-11 05:37:35 -0700335 LOG(LS_INFO) << uma_prefix_ << "SentPacketsLostInPercent "
336 << fraction_lost;
sprang07fb9be2016-02-24 07:55:00 -0800337 }
338
339 // The RTCP packet type counters, delivered via the
340 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
341 // life of the send stream and are not reset when switching content type.
342 // For the purpose of these statistics though, we want new counts when
343 // switching since we switch histogram name. On every reset of the
344 // UmaSamplesContainer, we save the initial state of the counters, so that
345 // we can calculate the delta here and aggregate over all ssrcs.
346 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700347 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800348 auto kv = current_stats.substreams.find(ssrc);
349 if (kv == current_stats.substreams.end())
350 continue;
351
352 RtcpPacketTypeCounter stream_counters =
353 kv->second.rtcp_packet_type_counts;
354 kv = start_stats_.substreams.find(ssrc);
355 if (kv != start_stats_.substreams.end())
356 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
357
358 counters.Add(stream_counters);
359 }
asapersson1d02d3e2016-09-09 22:40:25 -0700360 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
361 uma_prefix_ + "NackPacketsReceivedPerMinute",
362 counters.nack_packets * 60 / elapsed_sec);
363 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
364 uma_prefix_ + "FirPacketsReceivedPerMinute",
365 counters.fir_packets * 60 / elapsed_sec);
366 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
367 uma_prefix_ + "PliPacketsReceivedPerMinute",
368 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800369 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700370 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800371 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
372 counters.UniqueNackRequestsInPercent());
373 }
sprange2d83d62016-02-19 09:03:26 -0800374 }
375 }
Erik Språng22c2b482016-03-01 09:40:42 +0100376
377 if (first_rtp_stats_time_ms_ != -1) {
378 int64_t elapsed_sec =
379 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
380 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800381 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
382 target_rate_updates_.pause_resume_events);
asapersson2077f2f2017-05-11 05:37:35 -0700383 LOG(LS_INFO) << uma_prefix_ << "NumberOfPauseEvents "
384 << target_rate_updates_.pause_resume_events;
asapersson66d4b372016-12-19 06:50:53 -0800385
386 int paused_time_percent =
387 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
388 if (paused_time_percent != -1) {
389 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
390 paused_time_percent);
asapersson2077f2f2017-05-11 05:37:35 -0700391 LOG(LS_INFO) << uma_prefix_ << "PausedTimeInPercent "
392 << paused_time_percent;
asapersson66d4b372016-12-19 06:50:53 -0800393 }
asapersson93e1e232017-02-06 05:18:35 -0800394 }
395 }
asapersson66d4b372016-12-19 06:50:53 -0800396
asapersson93e1e232017-02-06 05:18:35 -0800397 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
398 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
399 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
400 total_bytes_per_sec.average * 8 / 1000);
401 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
402 << total_bytes_per_sec.ToStringWithMultiplier(8);
403 }
404 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
405 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
406 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
407 media_bytes_per_sec.average * 8 / 1000);
408 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
409 << media_bytes_per_sec.ToStringWithMultiplier(8);
410 }
411 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
412 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
413 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
414 uma_prefix_ + "PaddingBitrateSentInKbps",
415 padding_bytes_per_sec.average * 8 / 1000);
416 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
417 << padding_bytes_per_sec.ToStringWithMultiplier(8);
418 }
419 AggregatedStats retransmit_bytes_per_sec =
420 retransmit_byte_counter_.GetStats();
421 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
422 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
423 uma_prefix_ + "RetransmittedBitrateSentInKbps",
424 retransmit_bytes_per_sec.average * 8 / 1000);
425 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
426 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
427 }
428 if (!rtp_config.rtx.ssrcs.empty()) {
429 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
430 int rtx_bytes_per_sec_avg = -1;
431 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
432 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
433 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
434 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
435 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
436 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
437 }
438 if (rtx_bytes_per_sec_avg != -1) {
439 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
440 rtx_bytes_per_sec_avg * 8 / 1000);
441 }
442 }
443 if (rtp_config.flexfec.payload_type != -1 ||
444 rtp_config.ulpfec.red_payload_type != -1) {
445 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
446 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
447 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
448 fec_bytes_per_sec.average * 8 / 1000);
449 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
450 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100451 }
452 }
sprangb4a1ae52015-12-03 08:10:08 -0800453}
454
Pera48ddb72016-09-29 11:48:50 +0200455void SendStatisticsProxy::OnEncoderReconfigured(
456 const VideoEncoderConfig& config,
457 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800458 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200459 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
460
461 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700462 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200463 uma_container_.reset(new UmaSamplesContainer(
464 GetUmaPrefix(config.content_type), stats_, clock_));
465 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800466 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200467}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000468
perkj275afc52016-09-01 00:21:16 -0700469void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
470 uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200471 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000472 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000473 stats_.media_bitrate_bps = bitrate;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000474}
475
Peter Boströme4499152016-02-05 11:13:28 +0100476void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
477 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000478 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200479 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100480 uma_container_->encode_time_counter_.Add(encode_time_ms);
481 encode_time_.Apply(1.0f, encode_time_ms);
482 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000483 stats_.encode_usage_percent = metrics.encode_usage_percent;
484}
485
Peter Boström7083e112015-09-22 16:28:51 +0200486void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700487 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200488 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000489 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800490 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800491 // Pause framerate (add min pause time since there may be frames/packets
492 // that are not yet sent).
493 const int64_t kMinMs = 500;
494 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
495 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
496 // Pause bitrate stats.
497 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
498 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
499 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
500 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
501 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
502 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700503 // Stop adaptation stats.
asapersson09f05612017-05-15 23:40:18 -0700504 uma_container_->cpu_adapt_timer_.Stop(now_ms);
505 uma_container_->quality_adapt_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800506 } else {
asapersson0944a802017-04-07 00:57:58 -0700507 // Start adaptation stats if scaling is enabled.
508 if (cpu_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700509 uma_container_->cpu_adapt_timer_.Start(now_ms);
asapersson0944a802017-04-07 00:57:58 -0700510 if (quality_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700511 uma_container_->quality_adapt_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800512 // Stop pause explicitly for stats that may be zero/not updated for some
513 // time.
514 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
515 uma_container_->padding_byte_counter_.ProcessAndStopPause();
516 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
517 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800518 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000519}
520
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000521VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200522 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000523 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000524 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800525 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000526 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000527}
528
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000529void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200530 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000531 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
532 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000533 it != stats_.substreams.end(); ++it) {
534 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200535 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
536 it->second.width = 0;
537 it->second.height = 0;
538 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000539 }
540}
541
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000542VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
543 uint32_t ssrc) {
544 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
545 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000546 if (it != stats_.substreams.end())
547 return &it->second;
548
brandtrcd188f62016-11-15 08:21:52 -0800549 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
550 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800551 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
552 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800553 bool is_rtx =
554 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
555 ssrc) != rtp_config_.rtx.ssrcs.end();
556 if (!is_media && !is_flexfec && !is_rtx)
557 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000558
asapersson2e5cfcd2016-08-11 08:41:18 -0700559 // Insert new entry and return ptr.
560 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
561 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800562 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700563
564 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000565}
566
Peter Boström20f3f942015-05-15 11:33:39 +0200567void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
568 rtc::CritScope lock(&crit_);
569 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200570 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200571 return;
572
573 stats->total_bitrate_bps = 0;
574 stats->retransmit_bitrate_bps = 0;
575 stats->height = 0;
576 stats->width = 0;
577}
578
perkjf5b2e512016-07-05 08:34:04 -0700579void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200580 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800581 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
582 return; // Start on first non-zero bitrate, may initially be zero.
583
584 int64_t now = clock_->TimeInMilliseconds();
585 if (uma_container_->target_rate_updates_.last_ms != -1) {
586 bool was_paused = stats_.target_media_bitrate_bps == 0;
587 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
588 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
589
590 // Use last to not include update when stream is stopped and video disabled.
591 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
592 ++uma_container_->target_rate_updates_.pause_resume_events;
593
594 // Check if video is paused/resumed.
595 uma_container_->target_rate_updates_.last_paused_or_resumed =
596 (bitrate_bps == 0) != was_paused;
597 }
598 uma_container_->target_rate_updates_.last_ms = now;
599
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000600 stats_.target_media_bitrate_bps = bitrate_bps;
601}
602
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000603void SendStatisticsProxy::OnSendEncodedImage(
604 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700605 const CodecSpecificInfo* codec_info) {
606 size_t simulcast_idx = 0;
607
perkj275afc52016-09-01 00:21:16 -0700608 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700609 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700610 if (codec_info) {
611 if (codec_info->codecType == kVideoCodecVP8) {
612 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
613 } else if (codec_info->codecType == kVideoCodecGeneric) {
614 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
615 }
perkj275afc52016-09-01 00:21:16 -0700616 if (codec_info->codec_name) {
617 stats_.encoder_implementation_name = codec_info->codec_name;
618 }
kjellander02b3d272016-04-20 05:05:54 -0700619 }
620
perkj26091b12016-09-01 01:17:40 -0700621 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000622 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700623 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000624 return;
625 }
perkj26091b12016-09-01 01:17:40 -0700626 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000627
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000628 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200629 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000630 return;
631
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000632 stats->width = encoded_image._encodedWidth;
633 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000634 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700635
sprangb4a1ae52015-12-03 08:10:08 -0800636 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
637 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800638 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800639 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
640 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800641
kthelgason0cd27ba2016-12-19 06:32:16 -0800642 if (quality_downscales_ != -1) {
643 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
644 if (quality_downscales_ > 0)
645 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700646 }
asaperssonda535c42015-10-19 23:32:41 -0700647 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
648 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800649 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700650 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800651 uma_container_->bw_resolutions_disabled_counter_.Add(
652 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700653 }
654 }
asapersson4306fc72015-10-19 00:35:21 -0700655
sakal87da4042016-10-31 06:53:47 -0700656 if (encoded_image.qp_ != -1) {
657 if (!stats_.qp_sum)
658 stats_.qp_sum = rtc::Optional<uint64_t>(0);
659 *stats_.qp_sum += encoded_image.qp_;
660
661 if (codec_info) {
662 if (codec_info->codecType == kVideoCodecVP8) {
663 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
664 ? -1
665 : static_cast<int>(simulcast_idx);
666 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
667 } else if (codec_info->codecType == kVideoCodecVP9) {
668 int spatial_idx =
669 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
670 ? -1
671 : codec_info->codecSpecific.VP9.spatial_idx;
672 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700673 } else if (codec_info->codecType == kVideoCodecH264) {
674 int spatial_idx = -1;
675 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700676 }
asapersson5265fed2016-04-18 02:58:47 -0700677 }
asapersson118ef002016-03-31 00:00:19 -0700678 }
679
asaperssond89920b2015-07-22 06:52:00 -0700680 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
681 // different threads and there is no guarantee that one frame of all layers
682 // are encoded before the next start.
683 if (last_sent_frame_timestamp_ > 0 &&
684 encoded_image._timeStamp != last_sent_frame_timestamp_) {
asapersson320e45a2016-11-29 01:40:35 -0800685 uma_container_->sent_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800686 uma_container_->sent_width_counter_.Add(
687 uma_container_->max_sent_width_per_timestamp_);
688 uma_container_->sent_height_counter_.Add(
689 uma_container_->max_sent_height_per_timestamp_);
690 uma_container_->max_sent_width_per_timestamp_ = 0;
691 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200692 }
asaperssond89920b2015-07-22 06:52:00 -0700693 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800694 uma_container_->max_sent_width_per_timestamp_ =
695 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700696 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800697 uma_container_->max_sent_height_per_timestamp_ =
698 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700699 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000700}
701
Per69b332d2016-06-02 15:45:42 +0200702int SendStatisticsProxy::GetSendFrameRate() const {
703 rtc::CritScope lock(&crit_);
704 return stats_.encode_frame_rate;
705}
706
asaperssond89920b2015-07-22 06:52:00 -0700707void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200708 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800709 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800710 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800711 uma_container_->input_width_counter_.Add(width);
712 uma_container_->input_height_counter_.Add(height);
asaperssonf4e44af2017-04-19 02:01:06 -0700713 if (cpu_downscales_ >= 0) {
714 uma_container_->cpu_limited_frame_counter_.Add(
715 stats_.cpu_limited_resolution);
716 }
perkj803d97f2016-11-01 11:45:46 -0700717}
718
asapersson09f05612017-05-15 23:40:18 -0700719void SendStatisticsProxy::SetAdaptationStats(
720 const ViEEncoder::AdaptCounts& cpu_counts,
721 const ViEEncoder::AdaptCounts& quality_counts) {
perkj803d97f2016-11-01 11:45:46 -0700722 rtc::CritScope lock(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700723 SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
724 SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
725 UpdateAdaptationStats(cpu_counts, quality_counts);
asapersson36e9eb42017-03-31 05:29:12 -0700726}
727
asapersson09f05612017-05-15 23:40:18 -0700728void SendStatisticsProxy::OnCpuAdaptationChanged(
729 const ViEEncoder::AdaptCounts& cpu_counts,
730 const ViEEncoder::AdaptCounts& quality_counts) {
asapersson36e9eb42017-03-31 05:29:12 -0700731 rtc::CritScope lock(&crit_);
perkj803d97f2016-11-01 11:45:46 -0700732 ++stats_.number_of_cpu_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700733 UpdateAdaptationStats(cpu_counts, quality_counts);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000734}
735
asapersson09f05612017-05-15 23:40:18 -0700736void SendStatisticsProxy::OnQualityAdaptationChanged(
737 const ViEEncoder::AdaptCounts& cpu_counts,
738 const ViEEncoder::AdaptCounts& quality_counts) {
kthelgason876222f2016-11-29 01:44:11 -0800739 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700740 ++stats_.number_of_quality_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700741 UpdateAdaptationStats(cpu_counts, quality_counts);
742}
743
744void SendStatisticsProxy::UpdateAdaptationStats(
745 const ViEEncoder::AdaptCounts& cpu_counts,
746 const ViEEncoder::AdaptCounts& quality_counts) {
747 cpu_downscales_ = cpu_counts.resolution;
748 quality_downscales_ = quality_counts.resolution;
749
750 stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
751 stats_.cpu_limited_framerate = cpu_counts.fps > 0;
752 stats_.bw_limited_resolution = quality_counts.resolution > 0;
753 stats_.bw_limited_framerate = quality_counts.fps > 0;
754}
755
756void SendStatisticsProxy::SetAdaptTimer(const ViEEncoder::AdaptCounts& counts,
757 StatsTimer* timer) {
758 if (counts.resolution >= 0 || counts.fps >= 0) {
759 // Adaptation enabled.
760 if (!stats_.suspended)
761 timer->Start(clock_->TimeInMilliseconds());
762 return;
763 }
764 timer->Stop(clock_->TimeInMilliseconds());
kthelgason876222f2016-11-29 01:44:11 -0800765}
766
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000767void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
768 uint32_t ssrc,
769 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200770 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000771 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200772 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000773 return;
774
775 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800776 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
777 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000778}
779
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000780void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
781 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200782 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000783 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200784 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000785 return;
786
787 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800788 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000789}
790
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100791void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000792
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000793void SendStatisticsProxy::DataCountersUpdated(
794 const StreamDataCounters& counters,
795 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200796 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000797 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800798 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000799
asaperssona6a699a2016-11-25 03:52:46 -0800800 if (stats->is_flexfec) {
801 // The same counters are reported for both the media ssrc and flexfec ssrc.
802 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
803 return;
804 }
805
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000806 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -0700807 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
808 int64_t now_ms = clock_->TimeInMilliseconds();
809 uma_container_->first_rtp_stats_time_ms_ = now_ms;
asapersson09f05612017-05-15 23:40:18 -0700810 uma_container_->cpu_adapt_timer_.Restart(now_ms);
811 uma_container_->quality_adapt_timer_.Restart(now_ms);
asapersson6eca98b2017-04-04 23:40:50 -0700812 }
asapersson93e1e232017-02-06 05:18:35 -0800813
814 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
815 ssrc);
816 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
817 ssrc);
818 uma_container_->retransmit_byte_counter_.Set(
819 counters.retransmitted.TotalBytes(), ssrc);
820 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
821 if (stats->is_rtx) {
822 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
823 ssrc);
824 } else {
825 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
826 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000827}
828
sprangcd349d92016-07-13 09:11:28 -0700829void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
830 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000831 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200832 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000833 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200834 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000835 return;
836
sprangcd349d92016-07-13 09:11:28 -0700837 stats->total_bitrate_bps = total_bitrate_bps;
838 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000839}
840
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000841void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
842 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
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000848 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000849}
850
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000851void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
852 int max_delay_ms,
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)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000857 return;
858 stats->avg_delay_ms = avg_delay_ms;
859 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800860
sprangb4a1ae52015-12-03 08:10:08 -0800861 uma_container_->delay_counter_.Add(avg_delay_ms);
862 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000863}
864
asapersson6eca98b2017-04-04 23:40:50 -0700865void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
866 if (start_ms == -1)
867 start_ms = now_ms;
868}
869
870void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
871 if (start_ms != -1) {
872 total_ms += now_ms - start_ms;
873 start_ms = -1;
874 }
875}
876
877void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
878 total_ms = 0;
879 if (start_ms != -1)
880 start_ms = now_ms;
881}
882
asaperssond89920b2015-07-22 06:52:00 -0700883void SendStatisticsProxy::SampleCounter::Add(int sample) {
884 sum += sample;
885 ++num_samples;
886}
887
asapersson66d4b372016-12-19 06:50:53 -0800888int SendStatisticsProxy::SampleCounter::Avg(
889 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -0700890 if (num_samples < min_required_samples || num_samples == 0)
891 return -1;
asapersson66d4b372016-12-19 06:50:53 -0800892 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -0700893}
894
asaperssondec5ebf2015-10-05 02:36:17 -0700895void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
896 if (sample)
897 ++sum;
898 ++num_samples;
899}
900
asapersson66d4b372016-12-19 06:50:53 -0800901void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
902 if (sample)
903 sum += count;
904 num_samples += count;
905}
asaperssondec5ebf2015-10-05 02:36:17 -0700906int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -0800907 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700908 return Fraction(min_required_samples, 100.0f);
909}
910
911int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -0800912 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700913 return Fraction(min_required_samples, 1000.0f);
914}
915
916int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -0800917 int64_t min_required_samples,
918 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700919 if (num_samples < min_required_samples || num_samples == 0)
920 return -1;
921 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
922}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000923} // namespace webrtc