blob: 7cefa294e60cdf4741f685220ee0136762d3081f [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"
kjellander02b3d272016-04-20 05:05:54 -070021#include "webrtc/modules/video_coding/include/video_codec_interface.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) {
53 if (payload_name == "VP8") {
54 return kVideoVp8;
55 } else if (payload_name == "VP9") {
56 return kVideoVp9;
57 } else if (payload_name == "H264") {
58 return kVideoH264;
59 } else {
60 return kVideoUnknown;
61 }
62}
63
64void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080065 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
66 PayloadNameToHistogramCodecType(payload_name),
67 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070068}
69} // namespace
70
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000071
pbos@webrtc.org273a4142014-12-01 15:23:21 +000072const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
73
sprangb4a1ae52015-12-03 08:10:08 -080074SendStatisticsProxy::SendStatisticsProxy(
75 Clock* clock,
76 const VideoSendStream::Config& config,
77 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070078 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -070079 payload_name_(config.encoder_settings.payload_name),
80 rtp_config_(config.rtp),
sprangb4a1ae52015-12-03 08:10:08 -080081 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -070082 start_ms_(clock->TimeInMilliseconds()),
asaperssond89920b2015-07-22 06:52:00 -070083 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080084 encode_time_(kEncodeTimeWeigthFactor),
sprang07fb9be2016-02-24 07:55:00 -080085 uma_container_(
86 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000087}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000088
sprang07fb9be2016-02-24 07:55:00 -080089SendStatisticsProxy::~SendStatisticsProxy() {
90 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -070091 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -070092
93 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -070094 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
95 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -070096
97 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -070098 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -080099}
sprangb4a1ae52015-12-03 08:10:08 -0800100
101SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800102 const char* prefix,
103 const VideoSendStream::Stats& stats,
104 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800105 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800106 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800107 max_sent_width_per_timestamp_(0),
108 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700109 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800110 input_fps_counter_(clock, nullptr, true),
111 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800112 total_byte_counter_(clock, nullptr, true),
113 media_byte_counter_(clock, nullptr, true),
114 rtx_byte_counter_(clock, nullptr, true),
115 padding_byte_counter_(clock, nullptr, true),
116 retransmit_byte_counter_(clock, nullptr, true),
117 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800118 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100119 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800120 start_stats_(stats) {
121 InitializeBitrateCounters(stats);
122}
sprangb4a1ae52015-12-03 08:10:08 -0800123
sprang07fb9be2016-02-24 07:55:00 -0800124SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200125
asapersson93e1e232017-02-06 05:18:35 -0800126void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
127 const VideoSendStream::Stats& stats) {
128 for (const auto& it : stats.substreams) {
129 uint32_t ssrc = it.first;
130 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
131 ssrc);
132 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
133 ssrc);
134 retransmit_byte_counter_.SetLast(
135 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
136 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
137 if (it.second.is_rtx) {
138 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
139 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100140 } else {
asapersson93e1e232017-02-06 05:18:35 -0800141 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
142 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100143 }
144 }
145}
146
sprang07fb9be2016-02-24 07:55:00 -0800147void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700148 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800149 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800150 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
151 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800152 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700153 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
154 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700155 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700156 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
157 in_width);
158 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
159 in_height);
asaperssond89920b2015-07-22 06:52:00 -0700160 }
asapersson320e45a2016-11-29 01:40:35 -0800161 AggregatedStats in_fps = input_fps_counter_.GetStats();
162 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
163 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
164 in_fps.average);
165 LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, " << in_fps.ToString();
166 }
167
perkj803d97f2016-11-01 11:45:46 -0700168 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
169 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700170 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700171 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
172 sent_width);
173 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
174 sent_height);
asaperssond89920b2015-07-22 06:52:00 -0700175 }
asapersson320e45a2016-11-29 01:40:35 -0800176 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
177 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
178 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
179 sent_fps.average);
180 LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
181 << sent_fps.ToString();
182 }
183
perkj803d97f2016-11-01 11:45:46 -0700184 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800185 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700186 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
187 encode_ms);
asaperssonc2148a52016-02-04 00:33:21 -0800188 }
perkj803d97f2016-11-01 11:45:46 -0700189 int key_frames_permille =
190 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700191 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700192 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
193 key_frames_permille);
asaperssondec5ebf2015-10-05 02:36:17 -0700194 }
asapersson4306fc72015-10-19 00:35:21 -0700195 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700196 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700197 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700198 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
199 uma_prefix_ + "QualityLimitedResolutionInPercent",
200 quality_limited);
asapersson4306fc72015-10-19 00:35:21 -0700201 }
perkj803d97f2016-11-01 11:45:46 -0700202 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700203 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700204 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800205 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
206 20);
asapersson4306fc72015-10-19 00:35:21 -0700207 }
perkj803d97f2016-11-01 11:45:46 -0700208 int cpu_limited =
209 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
210 if (cpu_limited != -1) {
211 RTC_HISTOGRAMS_PERCENTAGE(
212 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
213 }
214 int bw_limited =
215 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700216 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700217 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800218 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
219 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700220 }
perkj803d97f2016-11-01 11:45:46 -0700221 int num_disabled =
222 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700223 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700224 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800225 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
226 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700227 }
perkj803d97f2016-11-01 11:45:46 -0700228 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800229 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700230 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
231 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800232
perkj803d97f2016-11-01 11:45:46 -0700233 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800234 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700235 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
236 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800237 }
sprang07fb9be2016-02-24 07:55:00 -0800238
asapersson118ef002016-03-31 00:00:19 -0700239 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700240 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700241 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700242 int spatial_idx = it.first;
243 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700244 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
245 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700246 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700247 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
248 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700249 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700250 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
251 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700252 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700253 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
254 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700255 } else {
256 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
257 << spatial_idx;
258 }
259 }
perkj803d97f2016-11-01 11:45:46 -0700260 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700261 if (qp_vp9 != -1) {
262 int spatial_idx = it.first;
263 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700264 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
265 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700266 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700267 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
268 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700269 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700270 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
271 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700272 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700273 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
274 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700275 } else {
276 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
277 << spatial_idx;
278 }
279 }
asapersson827cab32016-11-02 09:08:47 -0700280 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
281 if (qp_h264 != -1) {
282 int spatial_idx = it.first;
283 RTC_DCHECK_EQ(-1, spatial_idx);
284 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
285 qp_h264);
286 }
asapersson118ef002016-03-31 00:00:19 -0700287 }
288
sprange2d83d62016-02-19 09:03:26 -0800289 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800290 int64_t elapsed_sec =
291 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
292 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
293 int fraction_lost = report_block_stats_.FractionLostInPercent();
294 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700295 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800296 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
297 }
298
299 // The RTCP packet type counters, delivered via the
300 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
301 // life of the send stream and are not reset when switching content type.
302 // For the purpose of these statistics though, we want new counts when
303 // switching since we switch histogram name. On every reset of the
304 // UmaSamplesContainer, we save the initial state of the counters, so that
305 // we can calculate the delta here and aggregate over all ssrcs.
306 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700307 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800308 auto kv = current_stats.substreams.find(ssrc);
309 if (kv == current_stats.substreams.end())
310 continue;
311
312 RtcpPacketTypeCounter stream_counters =
313 kv->second.rtcp_packet_type_counts;
314 kv = start_stats_.substreams.find(ssrc);
315 if (kv != start_stats_.substreams.end())
316 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
317
318 counters.Add(stream_counters);
319 }
asapersson1d02d3e2016-09-09 22:40:25 -0700320 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
321 uma_prefix_ + "NackPacketsReceivedPerMinute",
322 counters.nack_packets * 60 / elapsed_sec);
323 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
324 uma_prefix_ + "FirPacketsReceivedPerMinute",
325 counters.fir_packets * 60 / elapsed_sec);
326 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
327 uma_prefix_ + "PliPacketsReceivedPerMinute",
328 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800329 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700330 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800331 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
332 counters.UniqueNackRequestsInPercent());
333 }
sprange2d83d62016-02-19 09:03:26 -0800334 }
335 }
Erik Språng22c2b482016-03-01 09:40:42 +0100336
337 if (first_rtp_stats_time_ms_ != -1) {
338 int64_t elapsed_sec =
339 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
340 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800341 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
342 target_rate_updates_.pause_resume_events);
343
344 int paused_time_percent =
345 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
346 if (paused_time_percent != -1) {
347 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
348 paused_time_percent);
349 }
asapersson93e1e232017-02-06 05:18:35 -0800350 }
351 }
asapersson66d4b372016-12-19 06:50:53 -0800352
asapersson93e1e232017-02-06 05:18:35 -0800353 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
354 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
355 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
356 total_bytes_per_sec.average * 8 / 1000);
357 LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
358 << total_bytes_per_sec.ToStringWithMultiplier(8);
359 }
360 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
361 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
362 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
363 media_bytes_per_sec.average * 8 / 1000);
364 LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
365 << media_bytes_per_sec.ToStringWithMultiplier(8);
366 }
367 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
368 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
369 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
370 uma_prefix_ + "PaddingBitrateSentInKbps",
371 padding_bytes_per_sec.average * 8 / 1000);
372 LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
373 << padding_bytes_per_sec.ToStringWithMultiplier(8);
374 }
375 AggregatedStats retransmit_bytes_per_sec =
376 retransmit_byte_counter_.GetStats();
377 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
378 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
379 uma_prefix_ + "RetransmittedBitrateSentInKbps",
380 retransmit_bytes_per_sec.average * 8 / 1000);
381 LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
382 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
383 }
384 if (!rtp_config.rtx.ssrcs.empty()) {
385 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
386 int rtx_bytes_per_sec_avg = -1;
387 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
388 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
389 LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
390 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
391 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
392 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
393 }
394 if (rtx_bytes_per_sec_avg != -1) {
395 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
396 rtx_bytes_per_sec_avg * 8 / 1000);
397 }
398 }
399 if (rtp_config.flexfec.payload_type != -1 ||
400 rtp_config.ulpfec.red_payload_type != -1) {
401 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
402 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
403 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
404 fec_bytes_per_sec.average * 8 / 1000);
405 LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
406 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100407 }
408 }
sprangb4a1ae52015-12-03 08:10:08 -0800409}
410
Pera48ddb72016-09-29 11:48:50 +0200411void SendStatisticsProxy::OnEncoderReconfigured(
412 const VideoEncoderConfig& config,
413 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800414 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200415 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
416
417 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700418 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200419 uma_container_.reset(new UmaSamplesContainer(
420 GetUmaPrefix(config.content_type), stats_, clock_));
421 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800422 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200423}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000424
perkj275afc52016-09-01 00:21:16 -0700425void SendStatisticsProxy::OnEncoderStatsUpdate(uint32_t framerate,
426 uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200427 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000428 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000429 stats_.media_bitrate_bps = bitrate;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700430 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FrameRateSent",
431 "frame_rate", framerate, "ssrc", rtp_config_.ssrcs[0]);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000432}
433
Peter Boströme4499152016-02-05 11:13:28 +0100434void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
435 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000436 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200437 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100438 uma_container_->encode_time_counter_.Add(encode_time_ms);
439 encode_time_.Apply(1.0f, encode_time_ms);
440 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000441 stats_.encode_usage_percent = metrics.encode_usage_percent;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700442 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeTimeInMs",
443 "encode_time_ms", stats_.avg_encode_time_ms,
444 "ssrc", rtp_config_.ssrcs[0]);
445 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.EncodeUsagePercent",
446 "encode_usage_percent", stats_.encode_usage_percent,
447 "ssrc", rtp_config_.ssrcs[0]);
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000448}
449
Peter Boström7083e112015-09-22 16:28:51 +0200450void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200451 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000452 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800453 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800454 // Pause framerate (add min pause time since there may be frames/packets
455 // that are not yet sent).
456 const int64_t kMinMs = 500;
457 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
458 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
459 // Pause bitrate stats.
460 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
461 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
462 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
463 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
464 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
465 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
466 } else {
467 // Stop pause explicitly for stats that may be zero/not updated for some
468 // time.
469 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
470 uma_container_->padding_byte_counter_.ProcessAndStopPause();
471 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
472 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800473 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000474}
475
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000476VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200477 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000478 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000479 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800480 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000481 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000482}
483
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000484void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200485 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000486 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
487 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000488 it != stats_.substreams.end(); ++it) {
489 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200490 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
491 it->second.width = 0;
492 it->second.height = 0;
493 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000494 }
495}
496
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000497VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
498 uint32_t ssrc) {
499 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
500 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000501 if (it != stats_.substreams.end())
502 return &it->second;
503
brandtrcd188f62016-11-15 08:21:52 -0800504 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
505 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800506 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
507 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800508 bool is_rtx =
509 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
510 ssrc) != rtp_config_.rtx.ssrcs.end();
511 if (!is_media && !is_flexfec && !is_rtx)
512 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000513
asapersson2e5cfcd2016-08-11 08:41:18 -0700514 // Insert new entry and return ptr.
515 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
516 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800517 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700518
519 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000520}
521
Peter Boström20f3f942015-05-15 11:33:39 +0200522void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
523 rtc::CritScope lock(&crit_);
524 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200525 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200526 return;
527
528 stats->total_bitrate_bps = 0;
529 stats->retransmit_bitrate_bps = 0;
530 stats->height = 0;
531 stats->width = 0;
532}
533
perkjf5b2e512016-07-05 08:34:04 -0700534void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200535 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800536 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
537 return; // Start on first non-zero bitrate, may initially be zero.
538
539 int64_t now = clock_->TimeInMilliseconds();
540 if (uma_container_->target_rate_updates_.last_ms != -1) {
541 bool was_paused = stats_.target_media_bitrate_bps == 0;
542 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
543 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
544
545 // Use last to not include update when stream is stopped and video disabled.
546 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
547 ++uma_container_->target_rate_updates_.pause_resume_events;
548
549 // Check if video is paused/resumed.
550 uma_container_->target_rate_updates_.last_paused_or_resumed =
551 (bitrate_bps == 0) != was_paused;
552 }
553 uma_container_->target_rate_updates_.last_ms = now;
554
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000555 stats_.target_media_bitrate_bps = bitrate_bps;
556}
557
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000558void SendStatisticsProxy::OnSendEncodedImage(
559 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700560 const CodecSpecificInfo* codec_info) {
561 size_t simulcast_idx = 0;
562
perkj275afc52016-09-01 00:21:16 -0700563 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700564 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700565 if (codec_info) {
566 if (codec_info->codecType == kVideoCodecVP8) {
567 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
568 } else if (codec_info->codecType == kVideoCodecGeneric) {
569 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
570 }
perkj275afc52016-09-01 00:21:16 -0700571 if (codec_info->codec_name) {
572 stats_.encoder_implementation_name = codec_info->codec_name;
573 }
kjellander02b3d272016-04-20 05:05:54 -0700574 }
575
perkj26091b12016-09-01 01:17:40 -0700576 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000577 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
perkj26091b12016-09-01 01:17:40 -0700578 << " >= " << rtp_config_.ssrcs.size() << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000579 return;
580 }
perkj26091b12016-09-01 01:17:40 -0700581 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000582
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000583 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200584 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000585 return;
586
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000587 stats->width = encoded_image._encodedWidth;
588 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000589 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700590
sprangb4a1ae52015-12-03 08:10:08 -0800591 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
592 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800593 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800594 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
595 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800596
kthelgason0cd27ba2016-12-19 06:32:16 -0800597 if (quality_downscales_ != -1) {
598 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
599 if (quality_downscales_ > 0)
600 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700601 }
asaperssonda535c42015-10-19 23:32:41 -0700602 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
603 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800604 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700605 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800606 uma_container_->bw_resolutions_disabled_counter_.Add(
607 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700608 }
609 }
asapersson4306fc72015-10-19 00:35:21 -0700610
sakal87da4042016-10-31 06:53:47 -0700611 if (encoded_image.qp_ != -1) {
612 if (!stats_.qp_sum)
613 stats_.qp_sum = rtc::Optional<uint64_t>(0);
614 *stats_.qp_sum += encoded_image.qp_;
615
616 if (codec_info) {
617 if (codec_info->codecType == kVideoCodecVP8) {
618 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
619 ? -1
620 : static_cast<int>(simulcast_idx);
621 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
622 } else if (codec_info->codecType == kVideoCodecVP9) {
623 int spatial_idx =
624 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
625 ? -1
626 : codec_info->codecSpecific.VP9.spatial_idx;
627 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700628 } else if (codec_info->codecType == kVideoCodecH264) {
629 int spatial_idx = -1;
630 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700631 }
asapersson5265fed2016-04-18 02:58:47 -0700632 }
asapersson118ef002016-03-31 00:00:19 -0700633 }
634
asaperssond89920b2015-07-22 06:52:00 -0700635 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
636 // different threads and there is no guarantee that one frame of all layers
637 // are encoded before the next start.
638 if (last_sent_frame_timestamp_ > 0 &&
639 encoded_image._timeStamp != last_sent_frame_timestamp_) {
asapersson320e45a2016-11-29 01:40:35 -0800640 uma_container_->sent_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800641 uma_container_->sent_width_counter_.Add(
642 uma_container_->max_sent_width_per_timestamp_);
643 uma_container_->sent_height_counter_.Add(
644 uma_container_->max_sent_height_per_timestamp_);
645 uma_container_->max_sent_width_per_timestamp_ = 0;
646 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200647 }
asaperssond89920b2015-07-22 06:52:00 -0700648 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800649 uma_container_->max_sent_width_per_timestamp_ =
650 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700651 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800652 uma_container_->max_sent_height_per_timestamp_ =
653 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700654 static_cast<int>(encoded_image._encodedHeight));
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700655
656 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentWidthInPixels",
657 "frame_width", encoded_image._encodedWidth, "ssrc", ssrc);
658 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentHeightInPixels",
659 "frame_height", encoded_image._encodedHeight, "ssrc", ssrc);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000660}
661
Per69b332d2016-06-02 15:45:42 +0200662int SendStatisticsProxy::GetSendFrameRate() const {
663 rtc::CritScope lock(&crit_);
664 return stats_.encode_frame_rate;
665}
666
asaperssond89920b2015-07-22 06:52:00 -0700667void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200668 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800669 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800670 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800671 uma_container_->input_width_counter_.Add(width);
672 uma_container_->input_height_counter_.Add(height);
perkj803d97f2016-11-01 11:45:46 -0700673 uma_container_->cpu_limited_frame_counter_.Add(stats_.cpu_limited_resolution);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700674 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.InputFrameRate",
675 "frame_rate", round(
676 uma_container_->input_frame_rate_tracker_.ComputeRate()),
677 "ssrc", rtp_config_.ssrcs[0]);
perkj803d97f2016-11-01 11:45:46 -0700678}
679
asapersson36e9eb42017-03-31 05:29:12 -0700680void SendStatisticsProxy::SetCpuScalingStats(bool cpu_restricted_resolution) {
perkj803d97f2016-11-01 11:45:46 -0700681 rtc::CritScope lock(&crit_);
asapersson36e9eb42017-03-31 05:29:12 -0700682 stats_.cpu_limited_resolution = cpu_restricted_resolution;
683}
684
685void SendStatisticsProxy::SetQualityScalingStats(int num_quality_downscales) {
686 rtc::CritScope lock(&crit_);
687 quality_downscales_ = num_quality_downscales;
688 stats_.bw_limited_resolution = quality_downscales_ > 0;
perkj803d97f2016-11-01 11:45:46 -0700689}
690
691void SendStatisticsProxy::OnCpuRestrictedResolutionChanged(
692 bool cpu_restricted_resolution) {
693 rtc::CritScope lock(&crit_);
694 stats_.cpu_limited_resolution = cpu_restricted_resolution;
695 ++stats_.number_of_cpu_adapt_changes;
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700696 TRACE_EVENT_INSTANT0("webrtc_stats", "WebRTC.Video.AdaptationChanges");
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000697}
698
kthelgason876222f2016-11-29 01:44:11 -0800699void SendStatisticsProxy::OnQualityRestrictedResolutionChanged(
kthelgason0cd27ba2016-12-19 06:32:16 -0800700 int num_quality_downscales) {
kthelgason876222f2016-11-29 01:44:11 -0800701 rtc::CritScope lock(&crit_);
kthelgason0cd27ba2016-12-19 06:32:16 -0800702 quality_downscales_ = num_quality_downscales;
703 stats_.bw_limited_resolution = quality_downscales_ > 0;
kthelgason876222f2016-11-29 01:44:11 -0800704}
705
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000706void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
707 uint32_t ssrc,
708 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200709 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000710 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200711 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000712 return;
713
714 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800715 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
716 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700717
718 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.FirPacketsReceived",
719 "fir_packets_received", packet_counter.fir_packets, "ssrc", ssrc);
720 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.NackPacketsReceived",
721 "nack_packets_received", packet_counter.nack_packets, "ssrc", ssrc);
722 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.PliPacketsReceived",
723 "pli_packets_received", packet_counter.pli_packets, "ssrc", ssrc);
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000724}
725
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000726void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
727 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200728 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000729 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200730 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000731 return;
732
733 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800734 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700735
736 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPacketsLost",
737 "packets_lost", statistics.cumulative_lost, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000738}
739
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100740void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000741
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000742void SendStatisticsProxy::DataCountersUpdated(
743 const StreamDataCounters& counters,
744 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200745 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000746 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -0800747 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000748
asaperssona6a699a2016-11-25 03:52:46 -0800749 if (stats->is_flexfec) {
750 // The same counters are reported for both the media ssrc and flexfec ssrc.
751 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
752 return;
753 }
754
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000755 stats->rtp_stats = counters;
Erik Språng22c2b482016-03-01 09:40:42 +0100756 if (uma_container_->first_rtp_stats_time_ms_ == -1)
757 uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
asapersson93e1e232017-02-06 05:18:35 -0800758
759 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
760 ssrc);
761 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
762 ssrc);
763 uma_container_->retransmit_byte_counter_.Set(
764 counters.retransmitted.TotalBytes(), ssrc);
765 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
766 if (stats->is_rtx) {
767 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
768 ssrc);
769 } else {
770 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
771 }
ehmaldonadof7f7fb92017-03-15 10:45:49 -0700772
773 TRACE_EVENT_INSTANT2("webrtc_stats", "WebRTC.Video.SentPackets",
774 "packets_sent", counters.transmitted.packets, "ssrc", ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000775}
776
sprangcd349d92016-07-13 09:11:28 -0700777void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
778 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000779 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200780 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000781 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200782 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000783 return;
784
sprangcd349d92016-07-13 09:11:28 -0700785 stats->total_bitrate_bps = total_bitrate_bps;
786 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000787}
788
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000789void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
790 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200791 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000792 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200793 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000794 return;
795
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000796 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000797}
798
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000799void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
800 int max_delay_ms,
801 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200802 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000803 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200804 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000805 return;
806 stats->avg_delay_ms = avg_delay_ms;
807 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800808
sprangb4a1ae52015-12-03 08:10:08 -0800809 uma_container_->delay_counter_.Add(avg_delay_ms);
810 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000811}
812
asaperssond89920b2015-07-22 06:52:00 -0700813void SendStatisticsProxy::SampleCounter::Add(int sample) {
814 sum += sample;
815 ++num_samples;
816}
817
asapersson66d4b372016-12-19 06:50:53 -0800818int SendStatisticsProxy::SampleCounter::Avg(
819 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -0700820 if (num_samples < min_required_samples || num_samples == 0)
821 return -1;
asapersson66d4b372016-12-19 06:50:53 -0800822 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -0700823}
824
asaperssondec5ebf2015-10-05 02:36:17 -0700825void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
826 if (sample)
827 ++sum;
828 ++num_samples;
829}
830
asapersson66d4b372016-12-19 06:50:53 -0800831void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
832 if (sample)
833 sum += count;
834 num_samples += count;
835}
asaperssondec5ebf2015-10-05 02:36:17 -0700836int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -0800837 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700838 return Fraction(min_required_samples, 100.0f);
839}
840
841int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -0800842 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700843 return Fraction(min_required_samples, 1000.0f);
844}
845
846int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -0800847 int64_t min_required_samples,
848 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -0700849 if (num_samples < min_required_samples || num_samples == 0)
850 return -1;
851 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
852}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000853} // namespace webrtc