blob: 5325306b3c0ceb4faa1e5415aa91956b7013d4ef [file] [log] [blame]
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/send_statistics_proxy.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000012
asaperssond89920b2015-07-22 06:52:00 -070013#include <algorithm>
Tim Psiakiad13d2f2015-11-10 16:34:50 -080014#include <cmath>
Åsa Perssonaa329e72017-12-15 15:54:44 +010015#include <utility>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000016
Mirko Bonadei71207422017-09-15 13:58:09 +020017#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/video_coding/include/video_codec_interface.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
asapersson8d75ac72017-09-15 06:41:15 -070021#include "system_wrappers/include/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000023
24namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070025namespace {
asapersson1aa420b2015-12-07 03:12:22 -080026const float kEncodeTimeWeigthFactor = 0.5f;
Åsa Persson0122e842017-10-16 12:19:23 +020027const size_t kMaxEncodedFrameMapSize = 150;
28const int64_t kMaxEncodedFrameWindowMs = 800;
29const int64_t kBucketSizeMs = 100;
30const size_t kBucketCount = 10;
asapersson1aa420b2015-12-07 03:12:22 -080031
asapersson8d75ac72017-09-15 06:41:15 -070032const char kVp8ForcedFallbackEncoderFieldTrial[] =
Åsa Persson45bbc8a2017-11-13 10:16:47 +010033 "WebRTC-VP8-Forced-Fallback-Encoder-v2";
asapersson8d75ac72017-09-15 06:41:15 -070034const char kVp8SwCodecName[] = "libvpx";
35
asapersson2a0a2a42015-10-27 01:32:00 -070036// Used by histograms. Values of entries should not be changed.
37enum HistogramCodecType {
38 kVideoUnknown = 0,
39 kVideoVp8 = 1,
40 kVideoVp9 = 2,
41 kVideoH264 = 3,
42 kVideoMax = 64,
43};
44
asaperssonc2148a52016-02-04 00:33:21 -080045const char* kRealtimePrefix = "WebRTC.Video.";
46const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
47
sprangb4a1ae52015-12-03 08:10:08 -080048const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
49 switch (content_type) {
50 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080051 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080052 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080053 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080054 }
55 RTC_NOTREACHED();
56 return nullptr;
57}
58
asapersson2a0a2a42015-10-27 01:32:00 -070059HistogramCodecType PayloadNameToHistogramCodecType(
60 const std::string& payload_name) {
kthelgason1cdddc92017-08-24 03:52:48 -070061 VideoCodecType codecType = PayloadStringToCodecType(payload_name);
62 switch (codecType) {
deadbeefc964d0b2017-04-03 10:03:35 -070063 case kVideoCodecVP8:
64 return kVideoVp8;
65 case kVideoCodecVP9:
66 return kVideoVp9;
67 case kVideoCodecH264:
68 return kVideoH264;
69 default:
70 return kVideoUnknown;
71 }
asapersson2a0a2a42015-10-27 01:32:00 -070072}
73
74void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080075 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
76 PayloadNameToHistogramCodecType(payload_name),
77 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070078}
asapersson8d75ac72017-09-15 06:41:15 -070079
80bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) {
81 return codec_info->codecType == kVideoCodecVP8 &&
82 codec_info->codecSpecific.VP8.simulcastIdx == 0 &&
83 (codec_info->codecSpecific.VP8.temporalIdx == 0 ||
84 codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
85}
86
Åsa Perssonc3ed6302017-11-16 14:04:52 +010087rtc::Optional<int> GetFallbackMaxPixels(const std::string& group) {
asapersson8d75ac72017-09-15 06:41:15 -070088 if (group.empty())
89 return rtc::Optional<int>();
90
asapersson8d75ac72017-09-15 06:41:15 -070091 int min_pixels;
Åsa Persson45bbc8a2017-11-13 10:16:47 +010092 int max_pixels;
93 int min_bps;
Åsa Perssonc3ed6302017-11-16 14:04:52 +010094 if (sscanf(group.c_str(), "-%d,%d,%d", &min_pixels, &max_pixels, &min_bps) !=
95 3) {
asapersson8d75ac72017-09-15 06:41:15 -070096 return rtc::Optional<int>();
97 }
98
Åsa Perssonc3ed6302017-11-16 14:04:52 +010099 if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels)
100 return rtc::Optional<int>();
101
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100102 return rtc::Optional<int>(max_pixels);
asapersson8d75ac72017-09-15 06:41:15 -0700103}
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100104
105rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialEnabled() {
106 std::string group =
107 webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
108 return (group.find("Enabled") == 0) ? GetFallbackMaxPixels(group.substr(7))
109 : rtc::Optional<int>();
110}
111
112rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialDisabled() {
113 std::string group =
114 webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
115 return (group.find("Disabled") == 0) ? GetFallbackMaxPixels(group.substr(8))
116 : rtc::Optional<int>();
117}
asapersson2a0a2a42015-10-27 01:32:00 -0700118} // namespace
119
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000120
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000121const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
122
sprangb4a1ae52015-12-03 08:10:08 -0800123SendStatisticsProxy::SendStatisticsProxy(
124 Clock* clock,
125 const VideoSendStream::Config& config,
126 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -0700127 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -0700128 payload_name_(config.encoder_settings.payload_name),
129 rtp_config_(config.rtp),
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100130 fallback_max_pixels_(GetFallbackMaxPixelsIfFieldTrialEnabled()),
131 fallback_max_pixels_disabled_(GetFallbackMaxPixelsIfFieldTrialDisabled()),
sprangb4a1ae52015-12-03 08:10:08 -0800132 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -0700133 start_ms_(clock->TimeInMilliseconds()),
asapersson1aa420b2015-12-07 03:12:22 -0800134 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -0700135 quality_downscales_(-1),
136 cpu_downscales_(-1),
Åsa Persson0122e842017-10-16 12:19:23 +0200137 media_byte_rate_tracker_(kBucketSizeMs, kBucketCount),
138 encoded_frame_rate_tracker_(kBucketSizeMs, kBucketCount),
sprang07fb9be2016-02-24 07:55:00 -0800139 uma_container_(
140 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000141}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000142
sprang07fb9be2016-02-24 07:55:00 -0800143SendStatisticsProxy::~SendStatisticsProxy() {
144 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -0700145 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -0700146
147 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700148 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
149 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700150
151 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700152 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800153}
sprangb4a1ae52015-12-03 08:10:08 -0800154
155SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800156 const char* prefix,
157 const VideoSendStream::Stats& stats,
158 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800159 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800160 clock_(clock),
Honghai Zhang82d78622016-05-06 11:29:15 -0700161 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800162 input_fps_counter_(clock, nullptr, true),
163 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800164 total_byte_counter_(clock, nullptr, true),
165 media_byte_counter_(clock, nullptr, true),
166 rtx_byte_counter_(clock, nullptr, true),
167 padding_byte_counter_(clock, nullptr, true),
168 retransmit_byte_counter_(clock, nullptr, true),
169 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800170 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100171 first_rtp_stats_time_ms_(-1),
Åsa Perssonaa329e72017-12-15 15:54:44 +0100172 start_stats_(stats),
173 num_streams_(0),
174 num_pixels_highest_stream_(0) {
asapersson93e1e232017-02-06 05:18:35 -0800175 InitializeBitrateCounters(stats);
176}
sprangb4a1ae52015-12-03 08:10:08 -0800177
sprang07fb9be2016-02-24 07:55:00 -0800178SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200179
asapersson93e1e232017-02-06 05:18:35 -0800180void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
181 const VideoSendStream::Stats& stats) {
182 for (const auto& it : stats.substreams) {
183 uint32_t ssrc = it.first;
184 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
185 ssrc);
186 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
187 ssrc);
188 retransmit_byte_counter_.SetLast(
189 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
190 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
191 if (it.second.is_rtx) {
192 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
193 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100194 } else {
asapersson93e1e232017-02-06 05:18:35 -0800195 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
196 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100197 }
198 }
199}
200
Åsa Perssonaa329e72017-12-15 15:54:44 +0100201void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(
202 int64_t now_ms,
203 bool* is_limited_in_resolution) {
Åsa Persson0122e842017-10-16 12:19:23 +0200204 while (!encoded_frames_.empty()) {
205 auto it = encoded_frames_.begin();
206 if (now_ms - it->second.send_ms < kMaxEncodedFrameWindowMs)
207 break;
208
209 // Use max per timestamp.
210 sent_width_counter_.Add(it->second.max_width);
211 sent_height_counter_.Add(it->second.max_height);
Åsa Perssonaa329e72017-12-15 15:54:44 +0100212
213 // Check number of encoded streams per timestamp.
214 if (num_streams_ > it->second.max_simulcast_idx) {
215 *is_limited_in_resolution = false;
216 if (num_streams_ > 1) {
217 int disabled_streams =
218 static_cast<int>(num_streams_ - 1 - it->second.max_simulcast_idx);
219 // Can be limited in resolution or framerate.
220 uint32_t pixels = it->second.max_width * it->second.max_height;
221 bool bw_limited_resolution =
222 disabled_streams > 0 && pixels < num_pixels_highest_stream_;
223 bw_limited_frame_counter_.Add(bw_limited_resolution);
224 if (bw_limited_resolution) {
225 bw_resolutions_disabled_counter_.Add(disabled_streams);
226 *is_limited_in_resolution = true;
227 }
228 }
229 }
Åsa Persson0122e842017-10-16 12:19:23 +0200230 encoded_frames_.erase(it);
231 }
232}
233
234bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame(
Åsa Perssonaa329e72017-12-15 15:54:44 +0100235 const EncodedImage& encoded_frame,
236 size_t simulcast_idx,
237 bool* is_limited_in_resolution) {
Åsa Persson0122e842017-10-16 12:19:23 +0200238 int64_t now_ms = clock_->TimeInMilliseconds();
Åsa Perssonaa329e72017-12-15 15:54:44 +0100239 RemoveOld(now_ms, is_limited_in_resolution);
Åsa Persson0122e842017-10-16 12:19:23 +0200240 if (encoded_frames_.size() > kMaxEncodedFrameMapSize) {
241 encoded_frames_.clear();
242 }
243
244 auto it = encoded_frames_.find(encoded_frame._timeStamp);
245 if (it == encoded_frames_.end()) {
246 // First frame with this timestamp.
Åsa Perssonaa329e72017-12-15 15:54:44 +0100247 encoded_frames_.insert(
248 std::make_pair(encoded_frame._timeStamp,
249 Frame(now_ms, encoded_frame._encodedWidth,
250 encoded_frame._encodedHeight, simulcast_idx)));
Åsa Persson0122e842017-10-16 12:19:23 +0200251 sent_fps_counter_.Add(1);
252 return true;
253 }
254
255 it->second.max_width =
256 std::max(it->second.max_width, encoded_frame._encodedWidth);
257 it->second.max_height =
258 std::max(it->second.max_height, encoded_frame._encodedHeight);
Åsa Perssonaa329e72017-12-15 15:54:44 +0100259 it->second.max_simulcast_idx =
260 std::max(it->second.max_simulcast_idx, simulcast_idx);
Åsa Persson0122e842017-10-16 12:19:23 +0200261 return false;
262}
263
sprang07fb9be2016-02-24 07:55:00 -0800264void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700265 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800266 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800267 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
268 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800269 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700270 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
271 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700272 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700273 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
274 in_width);
275 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
276 in_height);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100277 RTC_LOG(LS_INFO) << uma_prefix_ << "InputWidthInPixels " << in_width;
278 RTC_LOG(LS_INFO) << uma_prefix_ << "InputHeightInPixels " << in_height;
asaperssond89920b2015-07-22 06:52:00 -0700279 }
asapersson320e45a2016-11-29 01:40:35 -0800280 AggregatedStats in_fps = input_fps_counter_.GetStats();
281 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
282 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
283 in_fps.average);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100284 RTC_LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, "
285 << in_fps.ToString();
asapersson320e45a2016-11-29 01:40:35 -0800286 }
287
perkj803d97f2016-11-01 11:45:46 -0700288 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
289 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700290 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700291 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
292 sent_width);
293 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
294 sent_height);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100295 RTC_LOG(LS_INFO) << uma_prefix_ << "SentWidthInPixels " << sent_width;
296 RTC_LOG(LS_INFO) << uma_prefix_ << "SentHeightInPixels " << sent_height;
asaperssond89920b2015-07-22 06:52:00 -0700297 }
asapersson320e45a2016-11-29 01:40:35 -0800298 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
299 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
300 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
301 sent_fps.average);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100302 RTC_LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
303 << sent_fps.ToString();
asapersson320e45a2016-11-29 01:40:35 -0800304 }
305
ilnikf4ded682017-08-30 02:30:20 -0700306 if (in_fps.num_samples > kMinRequiredPeriodicSamples &&
307 sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
308 int in_fps_avg = in_fps.average;
309 if (in_fps_avg > 0) {
310 int sent_fps_avg = sent_fps.average;
311 int sent_to_in_fps_ratio_percent =
312 (100 * sent_fps_avg + in_fps_avg / 2) / in_fps_avg;
313 // If reported period is small, it may happen that sent_fps is larger than
314 // input_fps briefly on average. This should be treated as 100% sent to
315 // input ratio.
316 if (sent_to_in_fps_ratio_percent > 100)
317 sent_to_in_fps_ratio_percent = 100;
318 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
319 uma_prefix_ + "SentToInputFpsRatioPercent",
320 sent_to_in_fps_ratio_percent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100321 RTC_LOG(LS_INFO) << uma_prefix_ << "SentToInputFpsRatioPercent "
322 << sent_to_in_fps_ratio_percent;
ilnikf4ded682017-08-30 02:30:20 -0700323 }
324 }
325
perkj803d97f2016-11-01 11:45:46 -0700326 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800327 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700328 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
329 encode_ms);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100330 RTC_LOG(LS_INFO) << uma_prefix_ << "EncodeTimeInMs " << encode_ms;
asaperssonc2148a52016-02-04 00:33:21 -0800331 }
perkj803d97f2016-11-01 11:45:46 -0700332 int key_frames_permille =
333 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700334 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700335 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
336 key_frames_permille);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100337 RTC_LOG(LS_INFO) << uma_prefix_ << "KeyFramesSentInPermille "
338 << key_frames_permille;
asaperssondec5ebf2015-10-05 02:36:17 -0700339 }
asapersson4306fc72015-10-19 00:35:21 -0700340 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700341 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700342 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700343 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
344 uma_prefix_ + "QualityLimitedResolutionInPercent",
345 quality_limited);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100346 RTC_LOG(LS_INFO) << uma_prefix_ << "QualityLimitedResolutionInPercent "
347 << quality_limited;
asapersson4306fc72015-10-19 00:35:21 -0700348 }
perkj803d97f2016-11-01 11:45:46 -0700349 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700350 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700351 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800352 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
353 20);
asapersson4306fc72015-10-19 00:35:21 -0700354 }
perkj803d97f2016-11-01 11:45:46 -0700355 int cpu_limited =
356 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
357 if (cpu_limited != -1) {
358 RTC_HISTOGRAMS_PERCENTAGE(
359 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
360 }
361 int bw_limited =
362 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700363 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700364 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800365 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
366 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700367 }
perkj803d97f2016-11-01 11:45:46 -0700368 int num_disabled =
369 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700370 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700371 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800372 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
373 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700374 }
perkj803d97f2016-11-01 11:45:46 -0700375 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800376 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700377 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
378 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800379
perkj803d97f2016-11-01 11:45:46 -0700380 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800381 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700382 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
383 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800384 }
sprang07fb9be2016-02-24 07:55:00 -0800385
asapersson118ef002016-03-31 00:00:19 -0700386 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700387 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700388 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700389 int spatial_idx = it.first;
390 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700391 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
392 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700393 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700394 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
395 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700396 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700397 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
398 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700399 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700400 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
401 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700402 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100403 RTC_LOG(LS_WARNING)
404 << "QP stats not recorded for VP8 spatial idx " << spatial_idx;
asapersson118ef002016-03-31 00:00:19 -0700405 }
406 }
perkj803d97f2016-11-01 11:45:46 -0700407 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700408 if (qp_vp9 != -1) {
409 int spatial_idx = it.first;
410 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700411 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
412 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700413 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700414 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
415 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700416 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700417 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
418 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700419 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700420 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
421 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700422 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100423 RTC_LOG(LS_WARNING)
424 << "QP stats not recorded for VP9 spatial layer " << spatial_idx;
asapersson5265fed2016-04-18 02:58:47 -0700425 }
426 }
asapersson827cab32016-11-02 09:08:47 -0700427 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
428 if (qp_h264 != -1) {
429 int spatial_idx = it.first;
430 RTC_DCHECK_EQ(-1, spatial_idx);
431 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
432 qp_h264);
433 }
asapersson118ef002016-03-31 00:00:19 -0700434 }
435
asapersson0944a802017-04-07 00:57:58 -0700436 if (first_rtp_stats_time_ms_ != -1) {
asapersson09f05612017-05-15 23:40:18 -0700437 quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
438 int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700439 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
440 int quality_changes = current_stats.number_of_quality_adapt_changes -
441 start_stats_.number_of_quality_adapt_changes;
442 RTC_HISTOGRAMS_COUNTS_100(kIndex,
443 uma_prefix_ + "AdaptChangesPerMinute.Quality",
444 quality_changes * 60 / elapsed_sec);
445 }
asapersson09f05612017-05-15 23:40:18 -0700446 cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
447 elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700448 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
449 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
450 start_stats_.number_of_cpu_adapt_changes;
451 RTC_HISTOGRAMS_COUNTS_100(kIndex,
452 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
453 cpu_changes * 60 / elapsed_sec);
454 }
asapersson6eca98b2017-04-04 23:40:50 -0700455 }
456
sprange2d83d62016-02-19 09:03:26 -0800457 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800458 int64_t elapsed_sec =
459 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
460 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
461 int fraction_lost = report_block_stats_.FractionLostInPercent();
462 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700463 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800464 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100465 RTC_LOG(LS_INFO) << uma_prefix_ << "SentPacketsLostInPercent "
466 << fraction_lost;
sprang07fb9be2016-02-24 07:55:00 -0800467 }
468
469 // The RTCP packet type counters, delivered via the
470 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
471 // life of the send stream and are not reset when switching content type.
472 // For the purpose of these statistics though, we want new counts when
473 // switching since we switch histogram name. On every reset of the
474 // UmaSamplesContainer, we save the initial state of the counters, so that
475 // we can calculate the delta here and aggregate over all ssrcs.
476 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700477 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800478 auto kv = current_stats.substreams.find(ssrc);
479 if (kv == current_stats.substreams.end())
480 continue;
481
482 RtcpPacketTypeCounter stream_counters =
483 kv->second.rtcp_packet_type_counts;
484 kv = start_stats_.substreams.find(ssrc);
485 if (kv != start_stats_.substreams.end())
486 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
487
488 counters.Add(stream_counters);
489 }
asapersson1d02d3e2016-09-09 22:40:25 -0700490 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
491 uma_prefix_ + "NackPacketsReceivedPerMinute",
492 counters.nack_packets * 60 / elapsed_sec);
493 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
494 uma_prefix_ + "FirPacketsReceivedPerMinute",
495 counters.fir_packets * 60 / elapsed_sec);
496 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
497 uma_prefix_ + "PliPacketsReceivedPerMinute",
498 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800499 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700500 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800501 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
502 counters.UniqueNackRequestsInPercent());
503 }
sprange2d83d62016-02-19 09:03:26 -0800504 }
505 }
Erik Språng22c2b482016-03-01 09:40:42 +0100506
507 if (first_rtp_stats_time_ms_ != -1) {
508 int64_t elapsed_sec =
509 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
510 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800511 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
512 target_rate_updates_.pause_resume_events);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100513 RTC_LOG(LS_INFO) << uma_prefix_ << "NumberOfPauseEvents "
514 << target_rate_updates_.pause_resume_events;
asapersson66d4b372016-12-19 06:50:53 -0800515
516 int paused_time_percent =
517 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
518 if (paused_time_percent != -1) {
519 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
520 paused_time_percent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100521 RTC_LOG(LS_INFO) << uma_prefix_ << "PausedTimeInPercent "
522 << paused_time_percent;
asapersson66d4b372016-12-19 06:50:53 -0800523 }
asapersson93e1e232017-02-06 05:18:35 -0800524 }
525 }
asapersson66d4b372016-12-19 06:50:53 -0800526
asapersson8d75ac72017-09-15 06:41:15 -0700527 if (fallback_info_.is_possible) {
528 // Double interval since there is some time before fallback may occur.
529 const int kMinRunTimeMs = 2 * metrics::kMinRunTimeInSeconds * 1000;
530 int64_t elapsed_ms = fallback_info_.elapsed_ms;
531 int fallback_time_percent = fallback_active_counter_.Percent(kMinRunTimeMs);
532 if (fallback_time_percent != -1 && elapsed_ms >= kMinRunTimeMs) {
533 RTC_HISTOGRAMS_PERCENTAGE(
534 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackTimeInPercent.Vp8",
535 fallback_time_percent);
536 RTC_HISTOGRAMS_COUNTS_100(
537 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackChangesPerMinute.Vp8",
538 fallback_info_.on_off_events * 60 / (elapsed_ms / 1000));
539 }
540 }
541
asapersson93e1e232017-02-06 05:18:35 -0800542 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
543 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
544 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
545 total_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100546 RTC_LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
547 << total_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800548 }
549 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
550 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
551 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
552 media_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100553 RTC_LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
554 << media_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800555 }
556 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
557 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
558 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
559 uma_prefix_ + "PaddingBitrateSentInKbps",
560 padding_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100561 RTC_LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
562 << padding_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800563 }
564 AggregatedStats retransmit_bytes_per_sec =
565 retransmit_byte_counter_.GetStats();
566 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
567 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
568 uma_prefix_ + "RetransmittedBitrateSentInKbps",
569 retransmit_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100570 RTC_LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
571 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800572 }
573 if (!rtp_config.rtx.ssrcs.empty()) {
574 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
575 int rtx_bytes_per_sec_avg = -1;
576 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
577 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100578 RTC_LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
579 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800580 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
581 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
582 }
583 if (rtx_bytes_per_sec_avg != -1) {
584 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
585 rtx_bytes_per_sec_avg * 8 / 1000);
586 }
587 }
588 if (rtp_config.flexfec.payload_type != -1 ||
589 rtp_config.ulpfec.red_payload_type != -1) {
590 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
591 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
592 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
593 fec_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100594 RTC_LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
595 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100596 }
597 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100598 RTC_LOG(LS_INFO) << "Frames encoded " << current_stats.frames_encoded;
599 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Capturer "
600 << current_stats.frames_dropped_by_capturer;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200601 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Capturer",
602 current_stats.frames_dropped_by_capturer);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100603 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.EncoderQueue "
604 << current_stats.frames_dropped_by_encoder_queue;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200605 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.EncoderQueue",
606 current_stats.frames_dropped_by_encoder_queue);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100607 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Encoder "
608 << current_stats.frames_dropped_by_encoder;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200609 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Encoder",
610 current_stats.frames_dropped_by_encoder);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100611 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Ratelimiter "
612 << current_stats.frames_dropped_by_rate_limiter;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200613 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Ratelimiter",
614 current_stats.frames_dropped_by_rate_limiter);
sprangb4a1ae52015-12-03 08:10:08 -0800615}
616
Pera48ddb72016-09-29 11:48:50 +0200617void SendStatisticsProxy::OnEncoderReconfigured(
618 const VideoEncoderConfig& config,
Åsa Perssonaa329e72017-12-15 15:54:44 +0100619 const std::vector<VideoStream>& streams,
Pera48ddb72016-09-29 11:48:50 +0200620 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800621 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200622 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
623
624 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700625 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200626 uma_container_.reset(new UmaSamplesContainer(
627 GetUmaPrefix(config.content_type), stats_, clock_));
628 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800629 }
Åsa Perssonaa329e72017-12-15 15:54:44 +0100630 uma_container_->encoded_frames_.clear();
631 uma_container_->num_streams_ = streams.size();
632 uma_container_->num_pixels_highest_stream_ =
633 streams.empty() ? 0 : (streams.back().width * streams.back().height);
Åsa Persson24b4eda2015-06-16 10:17:01 +0200634}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000635
Peter Boströme4499152016-02-05 11:13:28 +0100636void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
637 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000638 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200639 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100640 uma_container_->encode_time_counter_.Add(encode_time_ms);
641 encode_time_.Apply(1.0f, encode_time_ms);
642 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000643 stats_.encode_usage_percent = metrics.encode_usage_percent;
644}
645
Peter Boström7083e112015-09-22 16:28:51 +0200646void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700647 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200648 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000649 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800650 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800651 // Pause framerate (add min pause time since there may be frames/packets
652 // that are not yet sent).
653 const int64_t kMinMs = 500;
654 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
655 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
656 // Pause bitrate stats.
657 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
658 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
659 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
660 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
661 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
662 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700663 // Stop adaptation stats.
asapersson09f05612017-05-15 23:40:18 -0700664 uma_container_->cpu_adapt_timer_.Stop(now_ms);
665 uma_container_->quality_adapt_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800666 } else {
asapersson0944a802017-04-07 00:57:58 -0700667 // Start adaptation stats if scaling is enabled.
668 if (cpu_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700669 uma_container_->cpu_adapt_timer_.Start(now_ms);
asapersson0944a802017-04-07 00:57:58 -0700670 if (quality_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700671 uma_container_->quality_adapt_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800672 // Stop pause explicitly for stats that may be zero/not updated for some
673 // time.
674 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
675 uma_container_->padding_byte_counter_.ProcessAndStopPause();
676 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
677 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800678 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000679}
680
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000681VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200682 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000683 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000684 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800685 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
ilnik50864a82017-09-06 12:32:35 -0700686 stats_.content_type =
687 content_type_ == VideoEncoderConfig::ContentType::kRealtimeVideo
688 ? VideoContentType::UNSPECIFIED
689 : VideoContentType::SCREENSHARE;
Åsa Persson0122e842017-10-16 12:19:23 +0200690 stats_.encode_frame_rate = round(encoded_frame_rate_tracker_.ComputeRate());
691 stats_.media_bitrate_bps = media_byte_rate_tracker_.ComputeRate() * 8;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000692 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000693}
694
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000695void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200696 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000697 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
698 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000699 it != stats_.substreams.end(); ++it) {
700 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200701 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
702 it->second.width = 0;
703 it->second.height = 0;
704 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000705 }
706}
707
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000708VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
709 uint32_t ssrc) {
710 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
711 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000712 if (it != stats_.substreams.end())
713 return &it->second;
714
brandtrcd188f62016-11-15 08:21:52 -0800715 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
716 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800717 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
718 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800719 bool is_rtx =
720 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
721 ssrc) != rtp_config_.rtx.ssrcs.end();
722 if (!is_media && !is_flexfec && !is_rtx)
723 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000724
asapersson2e5cfcd2016-08-11 08:41:18 -0700725 // Insert new entry and return ptr.
726 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
727 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800728 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700729
730 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000731}
732
Peter Boström20f3f942015-05-15 11:33:39 +0200733void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
734 rtc::CritScope lock(&crit_);
735 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200736 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200737 return;
738
739 stats->total_bitrate_bps = 0;
740 stats->retransmit_bitrate_bps = 0;
741 stats->height = 0;
742 stats->width = 0;
743}
744
perkjf5b2e512016-07-05 08:34:04 -0700745void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200746 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800747 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
748 return; // Start on first non-zero bitrate, may initially be zero.
749
750 int64_t now = clock_->TimeInMilliseconds();
751 if (uma_container_->target_rate_updates_.last_ms != -1) {
752 bool was_paused = stats_.target_media_bitrate_bps == 0;
753 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
754 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
755
756 // Use last to not include update when stream is stopped and video disabled.
757 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
758 ++uma_container_->target_rate_updates_.pause_resume_events;
759
760 // Check if video is paused/resumed.
761 uma_container_->target_rate_updates_.last_paused_or_resumed =
762 (bitrate_bps == 0) != was_paused;
763 }
764 uma_container_->target_rate_updates_.last_ms = now;
765
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000766 stats_.target_media_bitrate_bps = bitrate_bps;
767}
768
asapersson8d75ac72017-09-15 06:41:15 -0700769void SendStatisticsProxy::UpdateEncoderFallbackStats(
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100770 const CodecSpecificInfo* codec_info,
771 int pixels) {
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100772 UpdateFallbackDisabledStats(codec_info, pixels);
773
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100774 if (!fallback_max_pixels_ || !uma_container_->fallback_info_.is_possible) {
asapersson8d75ac72017-09-15 06:41:15 -0700775 return;
776 }
777
778 if (!IsForcedFallbackPossible(codec_info)) {
779 uma_container_->fallback_info_.is_possible = false;
780 return;
781 }
782
783 FallbackEncoderInfo* fallback_info = &uma_container_->fallback_info_;
784
785 const int64_t now_ms = clock_->TimeInMilliseconds();
786 bool is_active = fallback_info->is_active;
787 if (codec_info->codec_name != stats_.encoder_implementation_name) {
788 // Implementation changed.
789 is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
790 if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
791 // First or not a VP8 SW change, update stats on next call.
792 return;
793 }
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100794 if (is_active && (pixels > *fallback_max_pixels_)) {
795 // Pixels should not be above |fallback_max_pixels_|. If above skip to
796 // avoid fallbacks due to failure.
797 fallback_info->is_possible = false;
798 return;
asapersson8d75ac72017-09-15 06:41:15 -0700799 }
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100800 stats_.has_entered_low_resolution = true;
asapersson8d75ac72017-09-15 06:41:15 -0700801 ++fallback_info->on_off_events;
802 }
803
804 if (fallback_info->last_update_ms) {
805 int64_t diff_ms = now_ms - *(fallback_info->last_update_ms);
806 // If the time diff since last update is greater than |max_frame_diff_ms|,
807 // video is considered paused/muted and the change is not included.
808 if (diff_ms < fallback_info->max_frame_diff_ms) {
809 uma_container_->fallback_active_counter_.Add(fallback_info->is_active,
810 diff_ms);
811 fallback_info->elapsed_ms += diff_ms;
812 }
813 }
814 fallback_info->is_active = is_active;
815 fallback_info->last_update_ms.emplace(now_ms);
816}
817
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100818void SendStatisticsProxy::UpdateFallbackDisabledStats(
819 const CodecSpecificInfo* codec_info,
820 int pixels) {
821 if (!fallback_max_pixels_disabled_ ||
822 !uma_container_->fallback_info_disabled_.is_possible ||
823 stats_.has_entered_low_resolution) {
824 return;
825 }
826
827 if (!IsForcedFallbackPossible(codec_info) ||
828 strcmp(codec_info->codec_name, kVp8SwCodecName) == 0) {
829 uma_container_->fallback_info_disabled_.is_possible = false;
830 return;
831 }
832
833 if (pixels <= *fallback_max_pixels_disabled_ ||
834 uma_container_->fallback_info_disabled_.min_pixel_limit_reached) {
835 stats_.has_entered_low_resolution = true;
836 }
837}
838
839void SendStatisticsProxy::OnMinPixelLimitReached() {
840 rtc::CritScope lock(&crit_);
841 uma_container_->fallback_info_disabled_.min_pixel_limit_reached = true;
842}
843
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000844void SendStatisticsProxy::OnSendEncodedImage(
845 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700846 const CodecSpecificInfo* codec_info) {
847 size_t simulcast_idx = 0;
848
perkj275afc52016-09-01 00:21:16 -0700849 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700850 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700851 if (codec_info) {
852 if (codec_info->codecType == kVideoCodecVP8) {
853 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
854 } else if (codec_info->codecType == kVideoCodecGeneric) {
855 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
856 }
perkj275afc52016-09-01 00:21:16 -0700857 if (codec_info->codec_name) {
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100858 UpdateEncoderFallbackStats(codec_info, encoded_image._encodedWidth *
859 encoded_image._encodedHeight);
perkj275afc52016-09-01 00:21:16 -0700860 stats_.encoder_implementation_name = codec_info->codec_name;
861 }
kjellander02b3d272016-04-20 05:05:54 -0700862 }
863
perkj26091b12016-09-01 01:17:40 -0700864 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100865 RTC_LOG(LS_ERROR) << "Encoded image outside simulcast range ("
866 << simulcast_idx << " >= " << rtp_config_.ssrcs.size()
867 << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000868 return;
869 }
perkj26091b12016-09-01 01:17:40 -0700870 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000871
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000872 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200873 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000874 return;
875
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000876 stats->width = encoded_image._encodedWidth;
877 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000878 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700879
sprangb4a1ae52015-12-03 08:10:08 -0800880 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
881 kVideoFrameKey);
asapersson4306fc72015-10-19 00:35:21 -0700882
sakal87da4042016-10-31 06:53:47 -0700883 if (encoded_image.qp_ != -1) {
884 if (!stats_.qp_sum)
885 stats_.qp_sum = rtc::Optional<uint64_t>(0);
886 *stats_.qp_sum += encoded_image.qp_;
887
888 if (codec_info) {
889 if (codec_info->codecType == kVideoCodecVP8) {
890 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
891 ? -1
892 : static_cast<int>(simulcast_idx);
893 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
894 } else if (codec_info->codecType == kVideoCodecVP9) {
895 int spatial_idx =
896 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
897 ? -1
898 : codec_info->codecSpecific.VP9.spatial_idx;
899 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700900 } else if (codec_info->codecType == kVideoCodecH264) {
901 int spatial_idx = -1;
902 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700903 }
asapersson5265fed2016-04-18 02:58:47 -0700904 }
asapersson118ef002016-03-31 00:00:19 -0700905 }
906
Åsa Persson0122e842017-10-16 12:19:23 +0200907 media_byte_rate_tracker_.AddSamples(encoded_image._length);
Åsa Perssonaa329e72017-12-15 15:54:44 +0100908
909 // Initialize to current since |is_limited_in_resolution| is only updated
910 // when an encoded frame is removed from the EncodedFrameMap.
911 bool is_limited_in_resolution = stats_.bw_limited_resolution;
912 if (uma_container_->InsertEncodedFrame(encoded_image, simulcast_idx,
913 &is_limited_in_resolution)) {
Åsa Persson0122e842017-10-16 12:19:23 +0200914 encoded_frame_rate_tracker_.AddSamples(1);
Åsa Perssonaa329e72017-12-15 15:54:44 +0100915 }
916
917 stats_.bw_limited_resolution =
918 is_limited_in_resolution || quality_downscales_ > 0;
919
920 if (quality_downscales_ != -1) {
921 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
922 if (quality_downscales_ > 0)
923 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
924 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000925}
926
Per69b332d2016-06-02 15:45:42 +0200927int SendStatisticsProxy::GetSendFrameRate() const {
928 rtc::CritScope lock(&crit_);
Åsa Persson0122e842017-10-16 12:19:23 +0200929 return round(encoded_frame_rate_tracker_.ComputeRate());
Per69b332d2016-06-02 15:45:42 +0200930}
931
asaperssond89920b2015-07-22 06:52:00 -0700932void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200933 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800934 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800935 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800936 uma_container_->input_width_counter_.Add(width);
937 uma_container_->input_height_counter_.Add(height);
asaperssonf4e44af2017-04-19 02:01:06 -0700938 if (cpu_downscales_ >= 0) {
939 uma_container_->cpu_limited_frame_counter_.Add(
940 stats_.cpu_limited_resolution);
941 }
Åsa Perssond29b54c2017-10-19 17:32:17 +0200942 if (encoded_frame_rate_tracker_.TotalSampleCount() == 0) {
943 // Set start time now instead of when first key frame is encoded to avoid a
944 // too high initial estimate.
945 encoded_frame_rate_tracker_.AddSamples(0);
946 }
perkj803d97f2016-11-01 11:45:46 -0700947}
948
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200949void SendStatisticsProxy::OnFrameDroppedBySource() {
950 rtc::CritScope lock(&crit_);
951 ++stats_.frames_dropped_by_capturer;
952}
953
954void SendStatisticsProxy::OnFrameDroppedInEncoderQueue() {
955 rtc::CritScope lock(&crit_);
956 ++stats_.frames_dropped_by_encoder_queue;
957}
958
959void SendStatisticsProxy::OnFrameDroppedByEncoder() {
960 rtc::CritScope lock(&crit_);
961 ++stats_.frames_dropped_by_encoder;
962}
963
964void SendStatisticsProxy::OnFrameDroppedByMediaOptimizations() {
965 rtc::CritScope lock(&crit_);
966 ++stats_.frames_dropped_by_rate_limiter;
967}
968
asapersson09f05612017-05-15 23:40:18 -0700969void SendStatisticsProxy::SetAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700970 const VideoStreamEncoder::AdaptCounts& cpu_counts,
971 const VideoStreamEncoder::AdaptCounts& quality_counts) {
perkj803d97f2016-11-01 11:45:46 -0700972 rtc::CritScope lock(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700973 SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
974 SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
975 UpdateAdaptationStats(cpu_counts, quality_counts);
asapersson36e9eb42017-03-31 05:29:12 -0700976}
977
asapersson09f05612017-05-15 23:40:18 -0700978void SendStatisticsProxy::OnCpuAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700979 const VideoStreamEncoder::AdaptCounts& cpu_counts,
980 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson36e9eb42017-03-31 05:29:12 -0700981 rtc::CritScope lock(&crit_);
perkj803d97f2016-11-01 11:45:46 -0700982 ++stats_.number_of_cpu_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700983 UpdateAdaptationStats(cpu_counts, quality_counts);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000984}
985
asapersson09f05612017-05-15 23:40:18 -0700986void SendStatisticsProxy::OnQualityAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700987 const VideoStreamEncoder::AdaptCounts& cpu_counts,
988 const VideoStreamEncoder::AdaptCounts& quality_counts) {
kthelgason876222f2016-11-29 01:44:11 -0800989 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700990 ++stats_.number_of_quality_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700991 UpdateAdaptationStats(cpu_counts, quality_counts);
992}
993
994void SendStatisticsProxy::UpdateAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700995 const VideoStreamEncoder::AdaptCounts& cpu_counts,
996 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson09f05612017-05-15 23:40:18 -0700997 cpu_downscales_ = cpu_counts.resolution;
998 quality_downscales_ = quality_counts.resolution;
999
1000 stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
1001 stats_.cpu_limited_framerate = cpu_counts.fps > 0;
1002 stats_.bw_limited_resolution = quality_counts.resolution > 0;
1003 stats_.bw_limited_framerate = quality_counts.fps > 0;
1004}
1005
mflodmancc3d4422017-08-03 08:27:51 -07001006void SendStatisticsProxy::SetAdaptTimer(
1007 const VideoStreamEncoder::AdaptCounts& counts,
1008 StatsTimer* timer) {
asapersson09f05612017-05-15 23:40:18 -07001009 if (counts.resolution >= 0 || counts.fps >= 0) {
1010 // Adaptation enabled.
1011 if (!stats_.suspended)
1012 timer->Start(clock_->TimeInMilliseconds());
1013 return;
1014 }
1015 timer->Stop(clock_->TimeInMilliseconds());
kthelgason876222f2016-11-29 01:44:11 -08001016}
1017
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00001018void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
1019 uint32_t ssrc,
1020 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001021 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001022 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001023 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00001024 return;
1025
1026 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -08001027 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
1028 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00001029}
1030
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001031void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
1032 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001033 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001034 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001035 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001036 return;
1037
1038 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -08001039 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001040}
1041
Peter Boströmd1d66ba2016-02-08 14:07:14 +01001042void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001043
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001044void SendStatisticsProxy::DataCountersUpdated(
1045 const StreamDataCounters& counters,
1046 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001047 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001048 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -08001049 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001050
asaperssona6a699a2016-11-25 03:52:46 -08001051 if (stats->is_flexfec) {
1052 // The same counters are reported for both the media ssrc and flexfec ssrc.
1053 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
1054 return;
1055 }
1056
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001057 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -07001058 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
1059 int64_t now_ms = clock_->TimeInMilliseconds();
1060 uma_container_->first_rtp_stats_time_ms_ = now_ms;
asapersson09f05612017-05-15 23:40:18 -07001061 uma_container_->cpu_adapt_timer_.Restart(now_ms);
1062 uma_container_->quality_adapt_timer_.Restart(now_ms);
asapersson6eca98b2017-04-04 23:40:50 -07001063 }
asapersson93e1e232017-02-06 05:18:35 -08001064
1065 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
1066 ssrc);
1067 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
1068 ssrc);
1069 uma_container_->retransmit_byte_counter_.Set(
1070 counters.retransmitted.TotalBytes(), ssrc);
1071 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
1072 if (stats->is_rtx) {
1073 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
1074 ssrc);
1075 } else {
1076 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
1077 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001078}
1079
sprangcd349d92016-07-13 09:11:28 -07001080void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
1081 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001082 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001083 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001084 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001085 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001086 return;
1087
sprangcd349d92016-07-13 09:11:28 -07001088 stats->total_bitrate_bps = total_bitrate_bps;
1089 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001090}
1091
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001092void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
1093 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001094 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001095 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001096 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001097 return;
1098
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001099 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001100}
1101
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001102void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
1103 int max_delay_ms,
1104 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001105 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001106 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001107 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001108 return;
1109 stats->avg_delay_ms = avg_delay_ms;
1110 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -08001111
sprangb4a1ae52015-12-03 08:10:08 -08001112 uma_container_->delay_counter_.Add(avg_delay_ms);
1113 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001114}
1115
asapersson6eca98b2017-04-04 23:40:50 -07001116void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
1117 if (start_ms == -1)
1118 start_ms = now_ms;
1119}
1120
1121void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
1122 if (start_ms != -1) {
1123 total_ms += now_ms - start_ms;
1124 start_ms = -1;
1125 }
1126}
1127
1128void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
1129 total_ms = 0;
1130 if (start_ms != -1)
1131 start_ms = now_ms;
1132}
1133
asaperssond89920b2015-07-22 06:52:00 -07001134void SendStatisticsProxy::SampleCounter::Add(int sample) {
1135 sum += sample;
1136 ++num_samples;
1137}
1138
asapersson66d4b372016-12-19 06:50:53 -08001139int SendStatisticsProxy::SampleCounter::Avg(
1140 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -07001141 if (num_samples < min_required_samples || num_samples == 0)
1142 return -1;
asapersson66d4b372016-12-19 06:50:53 -08001143 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -07001144}
1145
asaperssondec5ebf2015-10-05 02:36:17 -07001146void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
1147 if (sample)
1148 ++sum;
1149 ++num_samples;
1150}
1151
asapersson66d4b372016-12-19 06:50:53 -08001152void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
1153 if (sample)
1154 sum += count;
1155 num_samples += count;
1156}
asaperssondec5ebf2015-10-05 02:36:17 -07001157int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -08001158 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001159 return Fraction(min_required_samples, 100.0f);
1160}
1161
1162int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -08001163 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001164 return Fraction(min_required_samples, 1000.0f);
1165}
1166
1167int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -08001168 int64_t min_required_samples,
1169 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001170 if (num_samples < min_required_samples || num_samples == 0)
1171 return -1;
1172 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
1173}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001174} // namespace webrtc