blob: 58751a6d82e1b99e26b91823b2c69bc06a34d13e [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),
sprang07fb9be2016-02-24 07:55:00 -080092 uma_container_(
93 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000094}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000095
sprang07fb9be2016-02-24 07:55:00 -080096SendStatisticsProxy::~SendStatisticsProxy() {
97 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -070098 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -070099
100 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700101 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
102 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700103
104 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700105 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800106}
sprangb4a1ae52015-12-03 08:10:08 -0800107
108SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800109 const char* prefix,
110 const VideoSendStream::Stats& stats,
111 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800112 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800113 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800114 max_sent_width_per_timestamp_(0),
115 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700116 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800117 input_fps_counter_(clock, nullptr, true),
118 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800119 total_byte_counter_(clock, nullptr, true),
120 media_byte_counter_(clock, nullptr, true),
121 rtx_byte_counter_(clock, nullptr, true),
122 padding_byte_counter_(clock, nullptr, true),
123 retransmit_byte_counter_(clock, nullptr, true),
124 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800125 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100126 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800127 start_stats_(stats) {
128 InitializeBitrateCounters(stats);
129}
sprangb4a1ae52015-12-03 08:10:08 -0800130
sprang07fb9be2016-02-24 07:55:00 -0800131SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200132
asapersson93e1e232017-02-06 05:18:35 -0800133void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
134 const VideoSendStream::Stats& stats) {
135 for (const auto& it : stats.substreams) {
136 uint32_t ssrc = it.first;
137 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
138 ssrc);
139 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
140 ssrc);
141 retransmit_byte_counter_.SetLast(
142 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
143 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
144 if (it.second.is_rtx) {
145 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
146 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100147 } else {
asapersson93e1e232017-02-06 05:18:35 -0800148 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
149 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100150 }
151 }
152}
153
sprang07fb9be2016-02-24 07:55:00 -0800154void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700155 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800156 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800157 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
158 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800159 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700160 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
161 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700162 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700163 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
164 in_width);
165 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
166 in_height);
asaperssond89920b2015-07-22 06:52:00 -0700167 }
asapersson320e45a2016-11-29 01:40:35 -0800168 AggregatedStats in_fps = input_fps_counter_.GetStats();
169 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
170 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
171 in_fps.average);
172 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
173 }
174
perkj803d97f2016-11-01 11:45:46 -0700175 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
176 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700177 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700178 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
179 sent_width);
180 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
181 sent_height);
asaperssond89920b2015-07-22 06:52:00 -0700182 }
asapersson320e45a2016-11-29 01:40:35 -0800183 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
184 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
185 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
186 sent_fps.average);
187 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
188 << sent_fps.ToString();
189 }
190
perkj803d97f2016-11-01 11:45:46 -0700191 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800192 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700193 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
194 encode_ms);
asaperssonc2148a52016-02-04 00:33:21 -0800195 }
perkj803d97f2016-11-01 11:45:46 -0700196 int key_frames_permille =
197 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700198 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700199 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
200 key_frames_permille);
asaperssondec5ebf2015-10-05 02:36:17 -0700201 }
asapersson4306fc72015-10-19 00:35:21 -0700202 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700203 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700204 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700205 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
206 uma_prefix_ + "QualityLimitedResolutionInPercent",
207 quality_limited);
asapersson4306fc72015-10-19 00:35:21 -0700208 }
perkj803d97f2016-11-01 11:45:46 -0700209 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700210 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700211 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800212 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
213 20);
asapersson4306fc72015-10-19 00:35:21 -0700214 }
perkj803d97f2016-11-01 11:45:46 -0700215 int cpu_limited =
216 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
217 if (cpu_limited != -1) {
218 RTC_HISTOGRAMS_PERCENTAGE(
219 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
220 }
221 int bw_limited =
222 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700223 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700224 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800225 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
226 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700227 }
perkj803d97f2016-11-01 11:45:46 -0700228 int num_disabled =
229 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700230 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700231 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800232 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
233 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700234 }
perkj803d97f2016-11-01 11:45:46 -0700235 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800236 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700237 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
238 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800239
perkj803d97f2016-11-01 11:45:46 -0700240 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800241 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700242 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
243 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800244 }
sprang07fb9be2016-02-24 07:55:00 -0800245
asapersson118ef002016-03-31 00:00:19 -0700246 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700247 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700248 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700249 int spatial_idx = it.first;
250 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700251 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
252 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700253 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700254 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
255 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700256 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700257 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
258 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700259 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700260 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
261 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700262 } else {
263 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
264 << spatial_idx;
265 }
266 }
perkj803d97f2016-11-01 11:45:46 -0700267 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700268 if (qp_vp9 != -1) {
269 int spatial_idx = it.first;
270 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700271 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
272 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700273 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700274 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
275 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700276 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700277 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
278 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700279 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700280 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
281 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700282 } else {
283 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
284 << spatial_idx;
285 }
286 }
asapersson827cab32016-11-02 09:08:47 -0700287 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
288 if (qp_h264 != -1) {
289 int spatial_idx = it.first;
290 RTC_DCHECK_EQ(-1, spatial_idx);
291 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
292 qp_h264);
293 }
asapersson118ef002016-03-31 00:00:19 -0700294 }
295
sprange2d83d62016-02-19 09:03:26 -0800296 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800297 int64_t elapsed_sec =
298 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
299 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
300 int fraction_lost = report_block_stats_.FractionLostInPercent();
301 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700302 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800303 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
304 }
305
306 // The RTCP packet type counters, delivered via the
307 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
308 // life of the send stream and are not reset when switching content type.
309 // For the purpose of these statistics though, we want new counts when
310 // switching since we switch histogram name. On every reset of the
311 // UmaSamplesContainer, we save the initial state of the counters, so that
312 // we can calculate the delta here and aggregate over all ssrcs.
313 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700314 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800315 auto kv = current_stats.substreams.find(ssrc);
316 if (kv == current_stats.substreams.end())
317 continue;
318
319 RtcpPacketTypeCounter stream_counters =
320 kv->second.rtcp_packet_type_counts;
321 kv = start_stats_.substreams.find(ssrc);
322 if (kv != start_stats_.substreams.end())
323 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
324
325 counters.Add(stream_counters);
326 }
asapersson1d02d3e2016-09-09 22:40:25 -0700327 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
328 uma_prefix_ + "NackPacketsReceivedPerMinute",
329 counters.nack_packets * 60 / elapsed_sec);
330 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
331 uma_prefix_ + "FirPacketsReceivedPerMinute",
332 counters.fir_packets * 60 / elapsed_sec);
333 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
334 uma_prefix_ + "PliPacketsReceivedPerMinute",
335 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800336 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700337 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800338 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
339 counters.UniqueNackRequestsInPercent());
340 }
sprange2d83d62016-02-19 09:03:26 -0800341 }
342 }
Erik Språng22c2b482016-03-01 09:40:42 +0100343
344 if (first_rtp_stats_time_ms_ != -1) {
345 int64_t elapsed_sec =
346 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
347 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800348 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
349 target_rate_updates_.pause_resume_events);
350
351 int paused_time_percent =
352 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
353 if (paused_time_percent != -1) {
354 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
355 paused_time_percent);
356 }
asapersson93e1e232017-02-06 05:18:35 -0800357 }
358 }
asapersson66d4b372016-12-19 06:50:53 -0800359
asapersson93e1e232017-02-06 05:18:35 -0800360 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
361 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
362 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
363 total_bytes_per_sec.average * 8 / 1000);
364 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
365 << total_bytes_per_sec.ToStringWithMultiplier(8);
366 }
367 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
368 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
369 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
370 media_bytes_per_sec.average * 8 / 1000);
371 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
372 << media_bytes_per_sec.ToStringWithMultiplier(8);
373 }
374 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
375 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
376 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
377 uma_prefix_ + "PaddingBitrateSentInKbps",
378 padding_bytes_per_sec.average * 8 / 1000);
379 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
380 << padding_bytes_per_sec.ToStringWithMultiplier(8);
381 }
382 AggregatedStats retransmit_bytes_per_sec =
383 retransmit_byte_counter_.GetStats();
384 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
385 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
386 uma_prefix_ + "RetransmittedBitrateSentInKbps",
387 retransmit_bytes_per_sec.average * 8 / 1000);
388 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
389 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
390 }
391 if (!rtp_config.rtx.ssrcs.empty()) {
392 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
393 int rtx_bytes_per_sec_avg = -1;
394 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
395 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
396 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
397 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
398 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
399 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
400 }
401 if (rtx_bytes_per_sec_avg != -1) {
402 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
403 rtx_bytes_per_sec_avg * 8 / 1000);
404 }
405 }
406 if (rtp_config.flexfec.payload_type != -1 ||
407 rtp_config.ulpfec.red_payload_type != -1) {
408 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
409 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
410 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
411 fec_bytes_per_sec.average * 8 / 1000);
412 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
413 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100414 }
415 }
sprangb4a1ae52015-12-03 08:10:08 -0800416}
417
Pera48ddb72016-09-29 11:48:50 +0200418void SendStatisticsProxy::OnEncoderReconfigured(
419 const VideoEncoderConfig& config,
420 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800421 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200422 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
423
424 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700425 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200426 uma_container_.reset(new UmaSamplesContainer(
427 GetUmaPrefix(config.content_type), stats_, clock_));
428 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800429 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200430}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000431
perkj275afc52016-09-01 00:21:16 -0700432void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
433 uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200434 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000435 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000436 stats_.media_bitrate_bps = bitrate;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700437 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FrameRateSent",
438 "frame_rate", framerate, "ssrc", rtp_config_.ssrcs[0]);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000439}
440
Peter Boströme4499152016-02-05 11:13:28 +0100441void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
442 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000443 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200444 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100445 uma_container_->encode_time_counter_.Add(encode_time_ms);
446 encode_time_.Apply(1.0f, encode_time_ms);
447 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000448 stats_.encode_usage_percent = metrics.encode_usage_percent;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700449 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeTimeInMs",
450 "encode_time_ms", stats_.avg_encode_time_ms,
451 "ssrc", rtp_config_.ssrcs[0]);
452 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeUsagePercent",
453 "encode_usage_percent", stats_.encode_usage_percent,
454 "ssrc", rtp_config_.ssrcs[0]);
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000455}
456
Peter Boström7083e112015-09-22 16:28:51 +0200457void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200458 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000459 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800460 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800461 // Pause framerate (add min pause time since there may be frames/packets
462 // that are not yet sent).
463 const int64_t kMinMs = 500;
464 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
465 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
466 // Pause bitrate stats.
467 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
468 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
469 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
470 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
471 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
472 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
473 } else {
474 // Stop pause explicitly for stats that may be zero/not updated for some
475 // time.
476 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
477 uma_container_->padding_byte_counter_.ProcessAndStopPause();
478 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
479 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800480 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000481}
482
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000483VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200484 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000485 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000486 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800487 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000488 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000489}
490
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000491void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200492 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000493 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
494 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000495 it != stats_.substreams.end(); ++it) {
496 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200497 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
498 it->second.width = 0;
499 it->second.height = 0;
500 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000501 }
502}
503
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000504VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
505 uint32_t ssrc) {
506 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
507 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000508 if (it != stats_.substreams.end())
509 return &it->second;
510
brandtrcd188f62016-11-15 08:21:52 -0800511 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
512 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800513 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
514 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800515 bool is_rtx =
516 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
517 ssrc) != rtp_config_.rtx.ssrcs.end();
518 if (!is_media && !is_flexfec && !is_rtx)
519 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000520
asapersson2e5cfcd2016-08-11 08:41:18 -0700521 // Insert new entry and return ptr.
522 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
523 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800524 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700525
526 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000527}
528
Peter Boström20f3f942015-05-15 11:33:39 +0200529void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
530 rtc::CritScope lock(&crit_);
531 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200532 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200533 return;
534
535 stats->total_bitrate_bps = 0;
536 stats->retransmit_bitrate_bps = 0;
537 stats->height = 0;
538 stats->width = 0;
539}
540
perkjf5b2e512016-07-05 08:34:04 -0700541void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200542 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800543 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
544 return; // Start on first non-zero bitrate, may initially be zero.
545
546 int64_t now = clock_->TimeInMilliseconds();
547 if (uma_container_->target_rate_updates_.last_ms != -1) {
548 bool was_paused = stats_.target_media_bitrate_bps == 0;
549 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
550 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
551
552 // Use last to not include update when stream is stopped and video disabled.
553 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
554 ++uma_container_->target_rate_updates_.pause_resume_events;
555
556 // Check if video is paused/resumed.
557 uma_container_->target_rate_updates_.last_paused_or_resumed =
558 (bitrate_bps == 0) != was_paused;
559 }
560 uma_container_->target_rate_updates_.last_ms = now;
561
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000562 stats_.target_media_bitrate_bps = bitrate_bps;
563}
564
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000565void SendStatisticsProxy::OnSendEncodedImage(
566 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700567 const CodecSpecificInfo* codec_info) {
568 size_t simulcast_idx = 0;
569
perkj275afc52016-09-01 00:21:16 -0700570 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700571 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700572 if (codec_info) {
573 if (codec_info->codecType == kVideoCodecVP8) {
574 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
575 } else if (codec_info->codecType == kVideoCodecGeneric) {
576 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
577 }
perkj275afc52016-09-01 00:21:16 -0700578 if (codec_info->codec_name) {
579 stats_.encoder_implementation_name = codec_info->codec_name;
580 }
kjellander02b3d272016-04-20 05:05:54 -0700581 }
582
perkj26091b12016-09-01 01:17:40 -0700583 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000584 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700585 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000586 return;
587 }
perkj26091b12016-09-01 01:17:40 -0700588 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000589
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000590 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200591 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000592 return;
593
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000594 stats->width = encoded_image._encodedWidth;
595 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000596 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700597
sprangb4a1ae52015-12-03 08:10:08 -0800598 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
599 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800600 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800601 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
602 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800603
kthelgason0cd27ba2016-12-19 06:32:16 -0800604 if (quality_downscales_ != -1) {
605 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
606 if (quality_downscales_ > 0)
607 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700608 }
asaperssonda535c42015-10-19 23:32:41 -0700609 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
610 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800611 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700612 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800613 uma_container_->bw_resolutions_disabled_counter_.Add(
614 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700615 }
616 }
asapersson4306fc72015-10-19 00:35:21 -0700617
sakal87da4042016-10-31 06:53:47 -0700618 if (encoded_image.qp_ != -1) {
619 if (!stats_.qp_sum)
620 stats_.qp_sum = rtc::Optional<uint64_t>(0);
621 *stats_.qp_sum += encoded_image.qp_;
622
623 if (codec_info) {
624 if (codec_info->codecType == kVideoCodecVP8) {
625 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
626 ? -1
627 : static_cast<int>(simulcast_idx);
628 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
629 } else if (codec_info->codecType == kVideoCodecVP9) {
630 int spatial_idx =
631 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
632 ? -1
633 : codec_info->codecSpecific.VP9.spatial_idx;
634 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700635 } else if (codec_info->codecType == kVideoCodecH264) {
636 int spatial_idx = -1;
637 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700638 }
asapersson5265fed2016-04-18 02:58:47 -0700639 }
asapersson118ef002016-03-31 00:00:19 -0700640 }
641
asaperssond89920b2015-07-22 06:52:00 -0700642 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
643 // different threads and there is no guarantee that one frame of all layers
644 // are encoded before the next start.
645 if (last_sent_frame_timestamp_ > 0 &&
646 encoded_image._timeStamp != last_sent_frame_timestamp_) {
asapersson320e45a2016-11-29 01:40:35 -0800647 uma_container_->sent_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800648 uma_container_->sent_width_counter_.Add(
649 uma_container_->max_sent_width_per_timestamp_);
650 uma_container_->sent_height_counter_.Add(
651 uma_container_->max_sent_height_per_timestamp_);
652 uma_container_->max_sent_width_per_timestamp_ = 0;
653 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200654 }
asaperssond89920b2015-07-22 06:52:00 -0700655 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800656 uma_container_->max_sent_width_per_timestamp_ =
657 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700658 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800659 uma_container_->max_sent_height_per_timestamp_ =
660 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700661 static_cast<int>(encoded_image._encodedHeight));
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700662
663 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentWidthInPixels",
664 "frame_width", encoded_image._encodedWidth, "ssrc", ssrc);
665 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentHeightInPixels",
666 "frame_height", encoded_image._encodedHeight, "ssrc", ssrc);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000667}
668
Per69b332d2016-06-02 15:45:42 +0200669int SendStatisticsProxy::GetSendFrameRate() const {
670 rtc::CritScope lock(&crit_);
671 return stats_.encode_frame_rate;
672}
673
asaperssond89920b2015-07-22 06:52:00 -0700674void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200675 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800676 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800677 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800678 uma_container_->input_width_counter_.Add(width);
679 uma_container_->input_height_counter_.Add(height);
perkj803d97f2016-11-01 11:45:46 -0700680 uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700681 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.InputFrameRate",
682 "frame_rate", round(
683 uma_container_->input_frame_rate_tracker_.ComputeRate()),
684 "ssrc", rtp_config_.ssrcs[0]);
perkj803d97f2016-11-01 11:45:46 -0700685}
686
asapersson36e9eb42017-03-31 05:29:12 -0700687void SendStatisticsProxy::SetCpuScalingStats(bool cpu_restricted_resolution) {
perkj803d97f2016-11-01 11:45:46 -0700688 rtc::CritScope lock(&crit_);
asapersson36e9eb42017-03-31 05:29:12 -0700689 stats_.cpu_limited_resolution = cpu_restricted_resolution;
690}
691
692void SendStatisticsProxy::SetQualityScalingStats(int num_quality_downscales) {
693 rtc::CritScope lock(&crit_);
694 quality_downscales_ = num_quality_downscales;
695 stats_.bw_limited_resolution = quality_downscales_ > 0;
perkj803d97f2016-11-01 11:45:46 -0700696}
697
698void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
699 bool cpu_restricted_resolution) {
700 rtc::CritScope lock(&crit_);
701 stats_.cpu_limited_resolution = cpu_restricted_resolution;
702 ++stats_.number_of_cpu_adapt_changes;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700703 TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.AdaptationChanges");
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000704}
705
kthelgason876222f2016-11-29 01:44:11 -0800706void SendStatisticsProxy::OnQualityRestrictedResolutionChanged(
kthelgason0cd27ba2016-12-19 06:32:16 -0800707 int num_quality_downscales) {
kthelgason876222f2016-11-29 01:44:11 -0800708 rtc::CritScope lock(&crit_);
kthelgason0cd27ba2016-12-19 06:32:16 -0800709 quality_downscales_ = num_quality_downscales;
710 stats_.bw_limited_resolution = quality_downscales_ > 0;
kthelgason876222f2016-11-29 01:44:11 -0800711}
712
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000713void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
714 uint32_t ssrc,
715 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200716 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000717 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200718 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000719 return;
720
721 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800722 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
723 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700724
725 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FirPacketsReceived",
726 "fir_packets_received", packet_counter.fir_packets, "ssrc", ssrc);
727 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.NackPacketsReceived",
728 "nack_packets_received", packet_counter.nack_packets, "ssrc", ssrc);
729 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.PliPacketsReceived",
730 "pli_packets_received", packet_counter.pli_packets, "ssrc", ssrc);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000731}
732
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000733void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
734 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200735 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000736 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200737 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000738 return;
739
740 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800741 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700742
743 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPacketsLost",
744 "packets_lost", statistics.cumulative_lost, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000745}
746
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100747void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000748
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000749void SendStatisticsProxy::DataCountersUpdated(
750 const StreamDataCounters& counters,
751 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200752 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000753 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800754 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000755
asaperssona6a699a2016-11-25 03:52:46 -0800756 if (stats->is_flexfec) {
757 // The same counters are reported for both the media ssrc and flexfec ssrc.
758 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
759 return;
760 }
761
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000762 stats->rtp_stats = counters;
Erik Språng22c2b482016-03-01 09:40:42 +0100763 if (uma_container_->first_rtp_stats_time_ms_ == -1)
764 uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
asapersson93e1e232017-02-06 05:18:35 -0800765
766 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
767 ssrc);
768 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
769 ssrc);
770 uma_container_->retransmit_byte_counter_.Set(
771 counters.retransmitted.TotalBytes(), ssrc);
772 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
773 if (stats->is_rtx) {
774 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
775 ssrc);
776 } else {
777 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
778 }
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700779
780 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPackets",
781 "packets_sent", counters.transmitted.packets, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000782}
783
sprangcd349d92016-07-13 09:11:28 -0700784void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
785 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000786 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
sprangcd349d92016-07-13 09:11:28 -0700792 stats->total_bitrate_bps = total_bitrate_bps;
793 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000794}
795
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000796void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
797 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200798 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000799 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200800 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000801 return;
802
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000803 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000804}
805
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000806void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
807 int max_delay_ms,
808 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200809 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000810 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200811 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000812 return;
813 stats->avg_delay_ms = avg_delay_ms;
814 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800815
sprangb4a1ae52015-12-03 08:10:08 -0800816 uma_container_->delay_counter_.Add(avg_delay_ms);
817 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000818}
819
asaperssond89920b2015-07-22 06:52:00 -0700820void SendStatisticsProxy::SampleCounter::Add(int sample) {
821 sum += sample;
822 ++num_samples;
823}
824
asapersson66d4b372016-12-19 06:50:53 -0800825int SendStatisticsProxy::SampleCounter::Avg(
826 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -0700827 if (num_samples < min_required_samples || num_samples == 0)
828 return -1;
asapersson66d4b372016-12-19 06:50:53 -0800829 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -0700830}
831
asaperssondec5ebf2015-10-05 02:36:17 -0700832void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
833 if (sample)
834 ++sum;
835 ++num_samples;
836}
837
asapersson66d4b372016-12-19 06:50:53 -0800838void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
839 if (sample)
840 sum += count;
841 num_samples += count;
842}
asaperssondec5ebf2015-10-05 02:36:17 -0700843int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -0800844 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700845 return Fraction(min_required_samples, 100.0f);
846}
847
848int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -0800849 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700850 return Fraction(min_required_samples, 1000.0f);
851}
852
853int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -0800854 int64_t min_required_samples,
855 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700856 if (num_samples < min_required_samples || num_samples == 0)
857 return -1;
858 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
859}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000860} // namespace webrtc