blob: 71c9348e3a497af858038553677a4cb5bee560fc [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>
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
Mirko Bonadei71207422017-09-15 13:58:09 +020018#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/video_coding/include/video_codec_interface.h"
20#include "rtc_base/checks.h"
21#include "rtc_base/logging.h"
asapersson8d75ac72017-09-15 06:41:15 -070022#include "system_wrappers/include/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000024
25namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070026namespace {
asapersson1aa420b2015-12-07 03:12:22 -080027const float kEncodeTimeWeigthFactor = 0.5f;
Åsa Persson0122e842017-10-16 12:19:23 +020028const size_t kMaxEncodedFrameMapSize = 150;
29const int64_t kMaxEncodedFrameWindowMs = 800;
30const int64_t kBucketSizeMs = 100;
31const size_t kBucketCount = 10;
asapersson1aa420b2015-12-07 03:12:22 -080032
asapersson8d75ac72017-09-15 06:41:15 -070033const char kVp8ForcedFallbackEncoderFieldTrial[] =
Åsa Persson45bbc8a2017-11-13 10:16:47 +010034 "WebRTC-VP8-Forced-Fallback-Encoder-v2";
asapersson8d75ac72017-09-15 06:41:15 -070035const char kVp8SwCodecName[] = "libvpx";
36
asapersson2a0a2a42015-10-27 01:32:00 -070037// Used by histograms. Values of entries should not be changed.
38enum HistogramCodecType {
39 kVideoUnknown = 0,
40 kVideoVp8 = 1,
41 kVideoVp9 = 2,
42 kVideoH264 = 3,
43 kVideoMax = 64,
44};
45
asaperssonc2148a52016-02-04 00:33:21 -080046const char* kRealtimePrefix = "WebRTC.Video.";
47const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
48
sprangb4a1ae52015-12-03 08:10:08 -080049const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
50 switch (content_type) {
51 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080052 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080053 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080054 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080055 }
56 RTC_NOTREACHED();
57 return nullptr;
58}
59
asapersson2a0a2a42015-10-27 01:32:00 -070060HistogramCodecType PayloadNameToHistogramCodecType(
61 const std::string& payload_name) {
kthelgason1cdddc92017-08-24 03:52:48 -070062 VideoCodecType codecType = PayloadStringToCodecType(payload_name);
63 switch (codecType) {
deadbeefc964d0b2017-04-03 10:03:35 -070064 case kVideoCodecVP8:
65 return kVideoVp8;
66 case kVideoCodecVP9:
67 return kVideoVp9;
68 case kVideoCodecH264:
69 return kVideoH264;
70 default:
71 return kVideoUnknown;
72 }
asapersson2a0a2a42015-10-27 01:32:00 -070073}
74
75void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080076 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
77 PayloadNameToHistogramCodecType(payload_name),
78 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070079}
asapersson8d75ac72017-09-15 06:41:15 -070080
81bool IsForcedFallbackPossible(const CodecSpecificInfo* codec_info) {
82 return codec_info->codecType == kVideoCodecVP8 &&
83 codec_info->codecSpecific.VP8.simulcastIdx == 0 &&
84 (codec_info->codecSpecific.VP8.temporalIdx == 0 ||
85 codec_info->codecSpecific.VP8.temporalIdx == kNoTemporalIdx);
86}
87
Åsa Perssonc3ed6302017-11-16 14:04:52 +010088rtc::Optional<int> GetFallbackMaxPixels(const std::string& group) {
asapersson8d75ac72017-09-15 06:41:15 -070089 if (group.empty())
90 return rtc::Optional<int>();
91
asapersson8d75ac72017-09-15 06:41:15 -070092 int min_pixels;
Åsa Persson45bbc8a2017-11-13 10:16:47 +010093 int max_pixels;
94 int min_bps;
Åsa Perssonc3ed6302017-11-16 14:04:52 +010095 if (sscanf(group.c_str(), "-%d,%d,%d", &min_pixels, &max_pixels, &min_bps) !=
96 3) {
asapersson8d75ac72017-09-15 06:41:15 -070097 return rtc::Optional<int>();
98 }
99
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100100 if (min_pixels <= 0 || max_pixels <= 0 || max_pixels < min_pixels)
101 return rtc::Optional<int>();
102
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100103 return rtc::Optional<int>(max_pixels);
asapersson8d75ac72017-09-15 06:41:15 -0700104}
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100105
106rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialEnabled() {
107 std::string group =
108 webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
109 return (group.find("Enabled") == 0) ? GetFallbackMaxPixels(group.substr(7))
110 : rtc::Optional<int>();
111}
112
113rtc::Optional<int> GetFallbackMaxPixelsIfFieldTrialDisabled() {
114 std::string group =
115 webrtc::field_trial::FindFullName(kVp8ForcedFallbackEncoderFieldTrial);
116 return (group.find("Disabled") == 0) ? GetFallbackMaxPixels(group.substr(8))
117 : rtc::Optional<int>();
118}
asapersson2a0a2a42015-10-27 01:32:00 -0700119} // namespace
120
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000121
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000122const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
123
sprangb4a1ae52015-12-03 08:10:08 -0800124SendStatisticsProxy::SendStatisticsProxy(
125 Clock* clock,
126 const VideoSendStream::Config& config,
127 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -0700128 : clock_(clock),
perkj26091b12016-09-01 01:17:40 -0700129 payload_name_(config.encoder_settings.payload_name),
130 rtp_config_(config.rtp),
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100131 fallback_max_pixels_(GetFallbackMaxPixelsIfFieldTrialEnabled()),
132 fallback_max_pixels_disabled_(GetFallbackMaxPixelsIfFieldTrialDisabled()),
sprangb4a1ae52015-12-03 08:10:08 -0800133 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -0700134 start_ms_(clock->TimeInMilliseconds()),
asapersson1aa420b2015-12-07 03:12:22 -0800135 encode_time_(kEncodeTimeWeigthFactor),
asapersson0944a802017-04-07 00:57:58 -0700136 quality_downscales_(-1),
137 cpu_downscales_(-1),
Åsa Persson0122e842017-10-16 12:19:23 +0200138 media_byte_rate_tracker_(kBucketSizeMs, kBucketCount),
139 encoded_frame_rate_tracker_(kBucketSizeMs, kBucketCount),
sprang07fb9be2016-02-24 07:55:00 -0800140 uma_container_(
141 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000142}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000143
sprang07fb9be2016-02-24 07:55:00 -0800144SendStatisticsProxy::~SendStatisticsProxy() {
145 rtc::CritScope lock(&crit_);
perkj26091b12016-09-01 01:17:40 -0700146 uma_container_->UpdateHistograms(rtp_config_, stats_);
asapersson4374a092016-07-27 00:39:09 -0700147
148 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
asapersson1d02d3e2016-09-09 22:40:25 -0700149 RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
150 elapsed_sec);
asapersson4374a092016-07-27 00:39:09 -0700151
152 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
perkj26091b12016-09-01 01:17:40 -0700153 UpdateCodecTypeHistogram(payload_name_);
sprang07fb9be2016-02-24 07:55:00 -0800154}
sprangb4a1ae52015-12-03 08:10:08 -0800155
156SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800157 const char* prefix,
158 const VideoSendStream::Stats& stats,
159 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800160 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800161 clock_(clock),
Honghai Zhang82d78622016-05-06 11:29:15 -0700162 input_frame_rate_tracker_(100, 10u),
asapersson320e45a2016-11-29 01:40:35 -0800163 input_fps_counter_(clock, nullptr, true),
164 sent_fps_counter_(clock, nullptr, true),
asapersson93e1e232017-02-06 05:18:35 -0800165 total_byte_counter_(clock, nullptr, true),
166 media_byte_counter_(clock, nullptr, true),
167 rtx_byte_counter_(clock, nullptr, true),
168 padding_byte_counter_(clock, nullptr, true),
169 retransmit_byte_counter_(clock, nullptr, true),
170 fec_byte_counter_(clock, nullptr, true),
sprang07fb9be2016-02-24 07:55:00 -0800171 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100172 first_rtp_stats_time_ms_(-1),
asapersson93e1e232017-02-06 05:18:35 -0800173 start_stats_(stats) {
174 InitializeBitrateCounters(stats);
175}
sprangb4a1ae52015-12-03 08:10:08 -0800176
sprang07fb9be2016-02-24 07:55:00 -0800177SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200178
asapersson93e1e232017-02-06 05:18:35 -0800179void SendStatisticsProxy::UmaSamplesContainer::InitializeBitrateCounters(
180 const VideoSendStream::Stats& stats) {
181 for (const auto& it : stats.substreams) {
182 uint32_t ssrc = it.first;
183 total_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
184 ssrc);
185 padding_byte_counter_.SetLast(it.second.rtp_stats.transmitted.padding_bytes,
186 ssrc);
187 retransmit_byte_counter_.SetLast(
188 it.second.rtp_stats.retransmitted.TotalBytes(), ssrc);
189 fec_byte_counter_.SetLast(it.second.rtp_stats.fec.TotalBytes(), ssrc);
190 if (it.second.is_rtx) {
191 rtx_byte_counter_.SetLast(it.second.rtp_stats.transmitted.TotalBytes(),
192 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100193 } else {
asapersson93e1e232017-02-06 05:18:35 -0800194 media_byte_counter_.SetLast(it.second.rtp_stats.MediaPayloadBytes(),
195 ssrc);
Erik Språng22c2b482016-03-01 09:40:42 +0100196 }
197 }
198}
199
Åsa Persson0122e842017-10-16 12:19:23 +0200200void SendStatisticsProxy::UmaSamplesContainer::RemoveOld(int64_t now_ms) {
201 while (!encoded_frames_.empty()) {
202 auto it = encoded_frames_.begin();
203 if (now_ms - it->second.send_ms < kMaxEncodedFrameWindowMs)
204 break;
205
206 // Use max per timestamp.
207 sent_width_counter_.Add(it->second.max_width);
208 sent_height_counter_.Add(it->second.max_height);
209 encoded_frames_.erase(it);
210 }
211}
212
213bool SendStatisticsProxy::UmaSamplesContainer::InsertEncodedFrame(
214 const EncodedImage& encoded_frame) {
215 int64_t now_ms = clock_->TimeInMilliseconds();
216 RemoveOld(now_ms);
217 if (encoded_frames_.size() > kMaxEncodedFrameMapSize) {
218 encoded_frames_.clear();
219 }
220
221 auto it = encoded_frames_.find(encoded_frame._timeStamp);
222 if (it == encoded_frames_.end()) {
223 // First frame with this timestamp.
224 encoded_frames_.insert(std::make_pair(
225 encoded_frame._timeStamp, Frame(now_ms, encoded_frame._encodedWidth,
226 encoded_frame._encodedHeight)));
227 sent_fps_counter_.Add(1);
228 return true;
229 }
230
231 it->second.max_width =
232 std::max(it->second.max_width, encoded_frame._encodedWidth);
233 it->second.max_height =
234 std::max(it->second.max_height, encoded_frame._encodedHeight);
235 return false;
236}
237
sprang07fb9be2016-02-24 07:55:00 -0800238void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
perkj26091b12016-09-01 01:17:40 -0700239 const VideoSendStream::Config::Rtp& rtp_config,
sprang07fb9be2016-02-24 07:55:00 -0800240 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800241 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
242 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson320e45a2016-11-29 01:40:35 -0800243 const int kMinRequiredPeriodicSamples = 6;
perkj803d97f2016-11-01 11:45:46 -0700244 int in_width = input_width_counter_.Avg(kMinRequiredMetricsSamples);
245 int in_height = input_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700246 if (in_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700247 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputWidthInPixels",
248 in_width);
249 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "InputHeightInPixels",
250 in_height);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100251 RTC_LOG(LS_INFO) << uma_prefix_ << "InputWidthInPixels " << in_width;
252 RTC_LOG(LS_INFO) << uma_prefix_ << "InputHeightInPixels " << in_height;
asaperssond89920b2015-07-22 06:52:00 -0700253 }
asapersson320e45a2016-11-29 01:40:35 -0800254 AggregatedStats in_fps = input_fps_counter_.GetStats();
255 if (in_fps.num_samples >= kMinRequiredPeriodicSamples) {
256 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "InputFramesPerSecond",
257 in_fps.average);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100258 RTC_LOG(LS_INFO) << uma_prefix_ + "InputFramesPerSecond, "
259 << in_fps.ToString();
asapersson320e45a2016-11-29 01:40:35 -0800260 }
261
perkj803d97f2016-11-01 11:45:46 -0700262 int sent_width = sent_width_counter_.Avg(kMinRequiredMetricsSamples);
263 int sent_height = sent_height_counter_.Avg(kMinRequiredMetricsSamples);
asaperssond89920b2015-07-22 06:52:00 -0700264 if (sent_width != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700265 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentWidthInPixels",
266 sent_width);
267 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "SentHeightInPixels",
268 sent_height);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100269 RTC_LOG(LS_INFO) << uma_prefix_ << "SentWidthInPixels " << sent_width;
270 RTC_LOG(LS_INFO) << uma_prefix_ << "SentHeightInPixels " << sent_height;
asaperssond89920b2015-07-22 06:52:00 -0700271 }
asapersson320e45a2016-11-29 01:40:35 -0800272 AggregatedStats sent_fps = sent_fps_counter_.GetStats();
273 if (sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
274 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "SentFramesPerSecond",
275 sent_fps.average);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100276 RTC_LOG(LS_INFO) << uma_prefix_ + "SentFramesPerSecond, "
277 << sent_fps.ToString();
asapersson320e45a2016-11-29 01:40:35 -0800278 }
279
ilnikf4ded682017-08-30 02:30:20 -0700280 if (in_fps.num_samples > kMinRequiredPeriodicSamples &&
281 sent_fps.num_samples >= kMinRequiredPeriodicSamples) {
282 int in_fps_avg = in_fps.average;
283 if (in_fps_avg > 0) {
284 int sent_fps_avg = sent_fps.average;
285 int sent_to_in_fps_ratio_percent =
286 (100 * sent_fps_avg + in_fps_avg / 2) / in_fps_avg;
287 // If reported period is small, it may happen that sent_fps is larger than
288 // input_fps briefly on average. This should be treated as 100% sent to
289 // input ratio.
290 if (sent_to_in_fps_ratio_percent > 100)
291 sent_to_in_fps_ratio_percent = 100;
292 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
293 uma_prefix_ + "SentToInputFpsRatioPercent",
294 sent_to_in_fps_ratio_percent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100295 RTC_LOG(LS_INFO) << uma_prefix_ << "SentToInputFpsRatioPercent "
296 << sent_to_in_fps_ratio_percent;
ilnikf4ded682017-08-30 02:30:20 -0700297 }
298 }
299
perkj803d97f2016-11-01 11:45:46 -0700300 int encode_ms = encode_time_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800301 if (encode_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700302 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
303 encode_ms);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100304 RTC_LOG(LS_INFO) << uma_prefix_ << "EncodeTimeInMs " << encode_ms;
asaperssonc2148a52016-02-04 00:33:21 -0800305 }
perkj803d97f2016-11-01 11:45:46 -0700306 int key_frames_permille =
307 key_frame_counter_.Permille(kMinRequiredMetricsSamples);
asaperssondec5ebf2015-10-05 02:36:17 -0700308 if (key_frames_permille != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700309 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "KeyFramesSentInPermille",
310 key_frames_permille);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100311 RTC_LOG(LS_INFO) << uma_prefix_ << "KeyFramesSentInPermille "
312 << key_frames_permille;
asaperssondec5ebf2015-10-05 02:36:17 -0700313 }
asapersson4306fc72015-10-19 00:35:21 -0700314 int quality_limited =
perkj803d97f2016-11-01 11:45:46 -0700315 quality_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700316 if (quality_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700317 RTC_HISTOGRAMS_PERCENTAGE(kIndex,
318 uma_prefix_ + "QualityLimitedResolutionInPercent",
319 quality_limited);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100320 RTC_LOG(LS_INFO) << uma_prefix_ << "QualityLimitedResolutionInPercent "
321 << quality_limited;
asapersson4306fc72015-10-19 00:35:21 -0700322 }
perkj803d97f2016-11-01 11:45:46 -0700323 int downscales = quality_downscales_counter_.Avg(kMinRequiredMetricsSamples);
asapersson4306fc72015-10-19 00:35:21 -0700324 if (downscales != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700325 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800326 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
327 20);
asapersson4306fc72015-10-19 00:35:21 -0700328 }
perkj803d97f2016-11-01 11:45:46 -0700329 int cpu_limited =
330 cpu_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
331 if (cpu_limited != -1) {
332 RTC_HISTOGRAMS_PERCENTAGE(
333 kIndex, uma_prefix_ + "CpuLimitedResolutionInPercent", cpu_limited);
334 }
335 int bw_limited =
336 bw_limited_frame_counter_.Percent(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700337 if (bw_limited != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700338 RTC_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800339 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
340 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700341 }
perkj803d97f2016-11-01 11:45:46 -0700342 int num_disabled =
343 bw_resolutions_disabled_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonda535c42015-10-19 23:32:41 -0700344 if (num_disabled != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700345 RTC_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800346 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
347 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700348 }
perkj803d97f2016-11-01 11:45:46 -0700349 int delay_ms = delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800350 if (delay_ms != -1)
asapersson1d02d3e2016-09-09 22:40:25 -0700351 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayInMs",
352 delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800353
perkj803d97f2016-11-01 11:45:46 -0700354 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredMetricsSamples);
asaperssonf040b232015-11-04 00:59:03 -0800355 if (max_delay_ms != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700356 RTC_HISTOGRAMS_COUNTS_100000(kIndex, uma_prefix_ + "SendSideDelayMaxInMs",
357 max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800358 }
sprang07fb9be2016-02-24 07:55:00 -0800359
asapersson118ef002016-03-31 00:00:19 -0700360 for (const auto& it : qp_counters_) {
perkj803d97f2016-11-01 11:45:46 -0700361 int qp_vp8 = it.second.vp8.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700362 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700363 int spatial_idx = it.first;
364 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700365 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
366 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700367 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700368 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0",
369 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700370 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700371 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1",
372 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700373 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700374 RTC_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2",
375 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700376 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100377 RTC_LOG(LS_WARNING)
378 << "QP stats not recorded for VP8 spatial idx " << spatial_idx;
asapersson118ef002016-03-31 00:00:19 -0700379 }
380 }
perkj803d97f2016-11-01 11:45:46 -0700381 int qp_vp9 = it.second.vp9.Avg(kMinRequiredMetricsSamples);
asapersson5265fed2016-04-18 02:58:47 -0700382 if (qp_vp9 != -1) {
383 int spatial_idx = it.first;
384 if (spatial_idx == -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700385 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
386 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700387 } else if (spatial_idx == 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700388 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0",
389 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700390 } else if (spatial_idx == 1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700391 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1",
392 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700393 } else if (spatial_idx == 2) {
asapersson1d02d3e2016-09-09 22:40:25 -0700394 RTC_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2",
395 qp_vp9);
asapersson5265fed2016-04-18 02:58:47 -0700396 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100397 RTC_LOG(LS_WARNING)
398 << "QP stats not recorded for VP9 spatial layer " << spatial_idx;
asapersson5265fed2016-04-18 02:58:47 -0700399 }
400 }
asapersson827cab32016-11-02 09:08:47 -0700401 int qp_h264 = it.second.h264.Avg(kMinRequiredMetricsSamples);
402 if (qp_h264 != -1) {
403 int spatial_idx = it.first;
404 RTC_DCHECK_EQ(-1, spatial_idx);
405 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "Encoded.Qp.H264",
406 qp_h264);
407 }
asapersson118ef002016-03-31 00:00:19 -0700408 }
409
asapersson0944a802017-04-07 00:57:58 -0700410 if (first_rtp_stats_time_ms_ != -1) {
asapersson09f05612017-05-15 23:40:18 -0700411 quality_adapt_timer_.Stop(clock_->TimeInMilliseconds());
412 int64_t elapsed_sec = quality_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700413 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
414 int quality_changes = current_stats.number_of_quality_adapt_changes -
415 start_stats_.number_of_quality_adapt_changes;
416 RTC_HISTOGRAMS_COUNTS_100(kIndex,
417 uma_prefix_ + "AdaptChangesPerMinute.Quality",
418 quality_changes * 60 / elapsed_sec);
419 }
asapersson09f05612017-05-15 23:40:18 -0700420 cpu_adapt_timer_.Stop(clock_->TimeInMilliseconds());
421 elapsed_sec = cpu_adapt_timer_.total_ms / 1000;
asapersson0944a802017-04-07 00:57:58 -0700422 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
423 int cpu_changes = current_stats.number_of_cpu_adapt_changes -
424 start_stats_.number_of_cpu_adapt_changes;
425 RTC_HISTOGRAMS_COUNTS_100(kIndex,
426 uma_prefix_ + "AdaptChangesPerMinute.Cpu",
427 cpu_changes * 60 / elapsed_sec);
428 }
asapersson6eca98b2017-04-04 23:40:50 -0700429 }
430
sprange2d83d62016-02-19 09:03:26 -0800431 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800432 int64_t elapsed_sec =
433 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
434 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
435 int fraction_lost = report_block_stats_.FractionLostInPercent();
436 if (fraction_lost != -1) {
asapersson1d02d3e2016-09-09 22:40:25 -0700437 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800438 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100439 RTC_LOG(LS_INFO) << uma_prefix_ << "SentPacketsLostInPercent "
440 << fraction_lost;
sprang07fb9be2016-02-24 07:55:00 -0800441 }
442
443 // The RTCP packet type counters, delivered via the
444 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
445 // life of the send stream and are not reset when switching content type.
446 // For the purpose of these statistics though, we want new counts when
447 // switching since we switch histogram name. On every reset of the
448 // UmaSamplesContainer, we save the initial state of the counters, so that
449 // we can calculate the delta here and aggregate over all ssrcs.
450 RtcpPacketTypeCounter counters;
perkj26091b12016-09-01 01:17:40 -0700451 for (uint32_t ssrc : rtp_config.ssrcs) {
sprang07fb9be2016-02-24 07:55:00 -0800452 auto kv = current_stats.substreams.find(ssrc);
453 if (kv == current_stats.substreams.end())
454 continue;
455
456 RtcpPacketTypeCounter stream_counters =
457 kv->second.rtcp_packet_type_counts;
458 kv = start_stats_.substreams.find(ssrc);
459 if (kv != start_stats_.substreams.end())
460 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
461
462 counters.Add(stream_counters);
463 }
asapersson1d02d3e2016-09-09 22:40:25 -0700464 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
465 uma_prefix_ + "NackPacketsReceivedPerMinute",
466 counters.nack_packets * 60 / elapsed_sec);
467 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
468 uma_prefix_ + "FirPacketsReceivedPerMinute",
469 counters.fir_packets * 60 / elapsed_sec);
470 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
471 uma_prefix_ + "PliPacketsReceivedPerMinute",
472 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800473 if (counters.nack_requests > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -0700474 RTC_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800475 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
476 counters.UniqueNackRequestsInPercent());
477 }
sprange2d83d62016-02-19 09:03:26 -0800478 }
479 }
Erik Språng22c2b482016-03-01 09:40:42 +0100480
481 if (first_rtp_stats_time_ms_ != -1) {
482 int64_t elapsed_sec =
483 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
484 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
asapersson66d4b372016-12-19 06:50:53 -0800485 RTC_HISTOGRAMS_COUNTS_100(kIndex, uma_prefix_ + "NumberOfPauseEvents",
486 target_rate_updates_.pause_resume_events);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100487 RTC_LOG(LS_INFO) << uma_prefix_ << "NumberOfPauseEvents "
488 << target_rate_updates_.pause_resume_events;
asapersson66d4b372016-12-19 06:50:53 -0800489
490 int paused_time_percent =
491 paused_time_counter_.Percent(metrics::kMinRunTimeInSeconds * 1000);
492 if (paused_time_percent != -1) {
493 RTC_HISTOGRAMS_PERCENTAGE(kIndex, uma_prefix_ + "PausedTimeInPercent",
494 paused_time_percent);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100495 RTC_LOG(LS_INFO) << uma_prefix_ << "PausedTimeInPercent "
496 << paused_time_percent;
asapersson66d4b372016-12-19 06:50:53 -0800497 }
asapersson93e1e232017-02-06 05:18:35 -0800498 }
499 }
asapersson66d4b372016-12-19 06:50:53 -0800500
asapersson8d75ac72017-09-15 06:41:15 -0700501 if (fallback_info_.is_possible) {
502 // Double interval since there is some time before fallback may occur.
503 const int kMinRunTimeMs = 2 * metrics::kMinRunTimeInSeconds * 1000;
504 int64_t elapsed_ms = fallback_info_.elapsed_ms;
505 int fallback_time_percent = fallback_active_counter_.Percent(kMinRunTimeMs);
506 if (fallback_time_percent != -1 && elapsed_ms >= kMinRunTimeMs) {
507 RTC_HISTOGRAMS_PERCENTAGE(
508 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackTimeInPercent.Vp8",
509 fallback_time_percent);
510 RTC_HISTOGRAMS_COUNTS_100(
511 kIndex, uma_prefix_ + "Encoder.ForcedSwFallbackChangesPerMinute.Vp8",
512 fallback_info_.on_off_events * 60 / (elapsed_ms / 1000));
513 }
514 }
515
asapersson93e1e232017-02-06 05:18:35 -0800516 AggregatedStats total_bytes_per_sec = total_byte_counter_.GetStats();
517 if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
518 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "BitrateSentInKbps",
519 total_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100520 RTC_LOG(LS_INFO) << uma_prefix_ << "BitrateSentInBps, "
521 << total_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800522 }
523 AggregatedStats media_bytes_per_sec = media_byte_counter_.GetStats();
524 if (media_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
525 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
526 media_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100527 RTC_LOG(LS_INFO) << uma_prefix_ << "MediaBitrateSentInBps, "
528 << media_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800529 }
530 AggregatedStats padding_bytes_per_sec = padding_byte_counter_.GetStats();
531 if (padding_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
532 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
533 uma_prefix_ + "PaddingBitrateSentInKbps",
534 padding_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100535 RTC_LOG(LS_INFO) << uma_prefix_ << "PaddingBitrateSentInBps, "
536 << padding_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800537 }
538 AggregatedStats retransmit_bytes_per_sec =
539 retransmit_byte_counter_.GetStats();
540 if (retransmit_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
541 RTC_HISTOGRAMS_COUNTS_10000(kIndex,
542 uma_prefix_ + "RetransmittedBitrateSentInKbps",
543 retransmit_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100544 RTC_LOG(LS_INFO) << uma_prefix_ << "RetransmittedBitrateSentInBps, "
545 << retransmit_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800546 }
547 if (!rtp_config.rtx.ssrcs.empty()) {
548 AggregatedStats rtx_bytes_per_sec = rtx_byte_counter_.GetStats();
549 int rtx_bytes_per_sec_avg = -1;
550 if (rtx_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
551 rtx_bytes_per_sec_avg = rtx_bytes_per_sec.average;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100552 RTC_LOG(LS_INFO) << uma_prefix_ << "RtxBitrateSentInBps, "
553 << rtx_bytes_per_sec.ToStringWithMultiplier(8);
asapersson93e1e232017-02-06 05:18:35 -0800554 } else if (total_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
555 rtx_bytes_per_sec_avg = 0; // RTX enabled but no RTX data sent, record 0.
556 }
557 if (rtx_bytes_per_sec_avg != -1) {
558 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
559 rtx_bytes_per_sec_avg * 8 / 1000);
560 }
561 }
562 if (rtp_config.flexfec.payload_type != -1 ||
563 rtp_config.ulpfec.red_payload_type != -1) {
564 AggregatedStats fec_bytes_per_sec = fec_byte_counter_.GetStats();
565 if (fec_bytes_per_sec.num_samples > kMinRequiredPeriodicSamples) {
566 RTC_HISTOGRAMS_COUNTS_10000(kIndex, uma_prefix_ + "FecBitrateSentInKbps",
567 fec_bytes_per_sec.average * 8 / 1000);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100568 RTC_LOG(LS_INFO) << uma_prefix_ << "FecBitrateSentInBps, "
569 << fec_bytes_per_sec.ToStringWithMultiplier(8);
Erik Språng22c2b482016-03-01 09:40:42 +0100570 }
571 }
Mirko Bonadei675513b2017-11-09 11:09:25 +0100572 RTC_LOG(LS_INFO) << "Frames encoded " << current_stats.frames_encoded;
573 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Capturer "
574 << current_stats.frames_dropped_by_capturer;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200575 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Capturer",
576 current_stats.frames_dropped_by_capturer);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100577 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.EncoderQueue "
578 << current_stats.frames_dropped_by_encoder_queue;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200579 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.EncoderQueue",
580 current_stats.frames_dropped_by_encoder_queue);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100581 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Encoder "
582 << current_stats.frames_dropped_by_encoder;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200583 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Encoder",
584 current_stats.frames_dropped_by_encoder);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100585 RTC_LOG(LS_INFO) << uma_prefix_ << "DroppedFrames.Ratelimiter "
586 << current_stats.frames_dropped_by_rate_limiter;
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200587 RTC_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "DroppedFrames.Ratelimiter",
588 current_stats.frames_dropped_by_rate_limiter);
sprangb4a1ae52015-12-03 08:10:08 -0800589}
590
Pera48ddb72016-09-29 11:48:50 +0200591void SendStatisticsProxy::OnEncoderReconfigured(
592 const VideoEncoderConfig& config,
593 uint32_t preferred_bitrate_bps) {
sprangb4a1ae52015-12-03 08:10:08 -0800594 rtc::CritScope lock(&crit_);
Pera48ddb72016-09-29 11:48:50 +0200595 stats_.preferred_media_bitrate_bps = preferred_bitrate_bps;
596
597 if (content_type_ != config.content_type) {
perkj26091b12016-09-01 01:17:40 -0700598 uma_container_->UpdateHistograms(rtp_config_, stats_);
Pera48ddb72016-09-29 11:48:50 +0200599 uma_container_.reset(new UmaSamplesContainer(
600 GetUmaPrefix(config.content_type), stats_, clock_));
601 content_type_ = config.content_type;
asaperssonf040b232015-11-04 00:59:03 -0800602 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200603}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000604
Peter Boströme4499152016-02-05 11:13:28 +0100605void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
606 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000607 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200608 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100609 uma_container_->encode_time_counter_.Add(encode_time_ms);
610 encode_time_.Apply(1.0f, encode_time_ms);
611 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000612 stats_.encode_usage_percent = metrics.encode_usage_percent;
613}
614
Peter Boström7083e112015-09-22 16:28:51 +0200615void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
asapersson0944a802017-04-07 00:57:58 -0700616 int64_t now_ms = clock_->TimeInMilliseconds();
Peter Boströmf2f82832015-05-01 13:00:41 +0200617 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000618 stats_.suspended = is_suspended;
asapersson320e45a2016-11-29 01:40:35 -0800619 if (is_suspended) {
asapersson93e1e232017-02-06 05:18:35 -0800620 // Pause framerate (add min pause time since there may be frames/packets
621 // that are not yet sent).
622 const int64_t kMinMs = 500;
623 uma_container_->input_fps_counter_.ProcessAndPauseForDuration(kMinMs);
624 uma_container_->sent_fps_counter_.ProcessAndPauseForDuration(kMinMs);
625 // Pause bitrate stats.
626 uma_container_->total_byte_counter_.ProcessAndPauseForDuration(kMinMs);
627 uma_container_->media_byte_counter_.ProcessAndPauseForDuration(kMinMs);
628 uma_container_->rtx_byte_counter_.ProcessAndPauseForDuration(kMinMs);
629 uma_container_->padding_byte_counter_.ProcessAndPauseForDuration(kMinMs);
630 uma_container_->retransmit_byte_counter_.ProcessAndPauseForDuration(kMinMs);
631 uma_container_->fec_byte_counter_.ProcessAndPauseForDuration(kMinMs);
asapersson0944a802017-04-07 00:57:58 -0700632 // Stop adaptation stats.
asapersson09f05612017-05-15 23:40:18 -0700633 uma_container_->cpu_adapt_timer_.Stop(now_ms);
634 uma_container_->quality_adapt_timer_.Stop(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800635 } else {
asapersson0944a802017-04-07 00:57:58 -0700636 // Start adaptation stats if scaling is enabled.
637 if (cpu_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700638 uma_container_->cpu_adapt_timer_.Start(now_ms);
asapersson0944a802017-04-07 00:57:58 -0700639 if (quality_downscales_ >= 0)
asapersson09f05612017-05-15 23:40:18 -0700640 uma_container_->quality_adapt_timer_.Start(now_ms);
asapersson93e1e232017-02-06 05:18:35 -0800641 // Stop pause explicitly for stats that may be zero/not updated for some
642 // time.
643 uma_container_->rtx_byte_counter_.ProcessAndStopPause();
644 uma_container_->padding_byte_counter_.ProcessAndStopPause();
645 uma_container_->retransmit_byte_counter_.ProcessAndStopPause();
646 uma_container_->fec_byte_counter_.ProcessAndStopPause();
asapersson320e45a2016-11-29 01:40:35 -0800647 }
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000648}
649
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000650VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200651 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000652 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000653 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800654 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
ilnik50864a82017-09-06 12:32:35 -0700655 stats_.content_type =
656 content_type_ == VideoEncoderConfig::ContentType::kRealtimeVideo
657 ? VideoContentType::UNSPECIFIED
658 : VideoContentType::SCREENSHARE;
Åsa Persson0122e842017-10-16 12:19:23 +0200659 stats_.encode_frame_rate = round(encoded_frame_rate_tracker_.ComputeRate());
660 stats_.media_bitrate_bps = media_byte_rate_tracker_.ComputeRate() * 8;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000661 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000662}
663
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000664void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200665 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000666 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
667 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000668 it != stats_.substreams.end(); ++it) {
669 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200670 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
671 it->second.width = 0;
672 it->second.height = 0;
673 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000674 }
675}
676
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000677VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
678 uint32_t ssrc) {
679 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
680 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000681 if (it != stats_.substreams.end())
682 return &it->second;
683
brandtrcd188f62016-11-15 08:21:52 -0800684 bool is_media = std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(),
685 ssrc) != rtp_config_.ssrcs.end();
brandtr3d200bd2017-01-16 06:59:19 -0800686 bool is_flexfec = rtp_config_.flexfec.payload_type != -1 &&
687 ssrc == rtp_config_.flexfec.ssrc;
brandtrcd188f62016-11-15 08:21:52 -0800688 bool is_rtx =
689 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(),
690 ssrc) != rtp_config_.rtx.ssrcs.end();
691 if (!is_media && !is_flexfec && !is_rtx)
692 return nullptr;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000693
asapersson2e5cfcd2016-08-11 08:41:18 -0700694 // Insert new entry and return ptr.
695 VideoSendStream::StreamStats* entry = &stats_.substreams[ssrc];
696 entry->is_rtx = is_rtx;
asaperssona6a699a2016-11-25 03:52:46 -0800697 entry->is_flexfec = is_flexfec;
asapersson2e5cfcd2016-08-11 08:41:18 -0700698
699 return entry;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000700}
701
Peter Boström20f3f942015-05-15 11:33:39 +0200702void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
703 rtc::CritScope lock(&crit_);
704 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200705 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200706 return;
707
708 stats->total_bitrate_bps = 0;
709 stats->retransmit_bitrate_bps = 0;
710 stats->height = 0;
711 stats->width = 0;
712}
713
perkjf5b2e512016-07-05 08:34:04 -0700714void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200715 rtc::CritScope lock(&crit_);
asapersson66d4b372016-12-19 06:50:53 -0800716 if (uma_container_->target_rate_updates_.last_ms == -1 && bitrate_bps == 0)
717 return; // Start on first non-zero bitrate, may initially be zero.
718
719 int64_t now = clock_->TimeInMilliseconds();
720 if (uma_container_->target_rate_updates_.last_ms != -1) {
721 bool was_paused = stats_.target_media_bitrate_bps == 0;
722 int64_t diff_ms = now - uma_container_->target_rate_updates_.last_ms;
723 uma_container_->paused_time_counter_.Add(was_paused, diff_ms);
724
725 // Use last to not include update when stream is stopped and video disabled.
726 if (uma_container_->target_rate_updates_.last_paused_or_resumed)
727 ++uma_container_->target_rate_updates_.pause_resume_events;
728
729 // Check if video is paused/resumed.
730 uma_container_->target_rate_updates_.last_paused_or_resumed =
731 (bitrate_bps == 0) != was_paused;
732 }
733 uma_container_->target_rate_updates_.last_ms = now;
734
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000735 stats_.target_media_bitrate_bps = bitrate_bps;
736}
737
asapersson8d75ac72017-09-15 06:41:15 -0700738void SendStatisticsProxy::UpdateEncoderFallbackStats(
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100739 const CodecSpecificInfo* codec_info,
740 int pixels) {
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100741 UpdateFallbackDisabledStats(codec_info, pixels);
742
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100743 if (!fallback_max_pixels_ || !uma_container_->fallback_info_.is_possible) {
asapersson8d75ac72017-09-15 06:41:15 -0700744 return;
745 }
746
747 if (!IsForcedFallbackPossible(codec_info)) {
748 uma_container_->fallback_info_.is_possible = false;
749 return;
750 }
751
752 FallbackEncoderInfo* fallback_info = &uma_container_->fallback_info_;
753
754 const int64_t now_ms = clock_->TimeInMilliseconds();
755 bool is_active = fallback_info->is_active;
756 if (codec_info->codec_name != stats_.encoder_implementation_name) {
757 // Implementation changed.
758 is_active = strcmp(codec_info->codec_name, kVp8SwCodecName) == 0;
759 if (!is_active && stats_.encoder_implementation_name != kVp8SwCodecName) {
760 // First or not a VP8 SW change, update stats on next call.
761 return;
762 }
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100763 if (is_active && (pixels > *fallback_max_pixels_)) {
764 // Pixels should not be above |fallback_max_pixels_|. If above skip to
765 // avoid fallbacks due to failure.
766 fallback_info->is_possible = false;
767 return;
asapersson8d75ac72017-09-15 06:41:15 -0700768 }
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100769 stats_.has_entered_low_resolution = true;
asapersson8d75ac72017-09-15 06:41:15 -0700770 ++fallback_info->on_off_events;
771 }
772
773 if (fallback_info->last_update_ms) {
774 int64_t diff_ms = now_ms - *(fallback_info->last_update_ms);
775 // If the time diff since last update is greater than |max_frame_diff_ms|,
776 // video is considered paused/muted and the change is not included.
777 if (diff_ms < fallback_info->max_frame_diff_ms) {
778 uma_container_->fallback_active_counter_.Add(fallback_info->is_active,
779 diff_ms);
780 fallback_info->elapsed_ms += diff_ms;
781 }
782 }
783 fallback_info->is_active = is_active;
784 fallback_info->last_update_ms.emplace(now_ms);
785}
786
Åsa Perssonc3ed6302017-11-16 14:04:52 +0100787void SendStatisticsProxy::UpdateFallbackDisabledStats(
788 const CodecSpecificInfo* codec_info,
789 int pixels) {
790 if (!fallback_max_pixels_disabled_ ||
791 !uma_container_->fallback_info_disabled_.is_possible ||
792 stats_.has_entered_low_resolution) {
793 return;
794 }
795
796 if (!IsForcedFallbackPossible(codec_info) ||
797 strcmp(codec_info->codec_name, kVp8SwCodecName) == 0) {
798 uma_container_->fallback_info_disabled_.is_possible = false;
799 return;
800 }
801
802 if (pixels <= *fallback_max_pixels_disabled_ ||
803 uma_container_->fallback_info_disabled_.min_pixel_limit_reached) {
804 stats_.has_entered_low_resolution = true;
805 }
806}
807
808void SendStatisticsProxy::OnMinPixelLimitReached() {
809 rtc::CritScope lock(&crit_);
810 uma_container_->fallback_info_disabled_.min_pixel_limit_reached = true;
811}
812
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000813void SendStatisticsProxy::OnSendEncodedImage(
814 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700815 const CodecSpecificInfo* codec_info) {
816 size_t simulcast_idx = 0;
817
perkj275afc52016-09-01 00:21:16 -0700818 rtc::CritScope lock(&crit_);
sakal43536c32016-10-24 01:46:43 -0700819 ++stats_.frames_encoded;
kjellander02b3d272016-04-20 05:05:54 -0700820 if (codec_info) {
821 if (codec_info->codecType == kVideoCodecVP8) {
822 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
823 } else if (codec_info->codecType == kVideoCodecGeneric) {
824 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
825 }
perkj275afc52016-09-01 00:21:16 -0700826 if (codec_info->codec_name) {
Åsa Persson45bbc8a2017-11-13 10:16:47 +0100827 UpdateEncoderFallbackStats(codec_info, encoded_image._encodedWidth *
828 encoded_image._encodedHeight);
perkj275afc52016-09-01 00:21:16 -0700829 stats_.encoder_implementation_name = codec_info->codec_name;
830 }
kjellander02b3d272016-04-20 05:05:54 -0700831 }
832
perkj26091b12016-09-01 01:17:40 -0700833 if (simulcast_idx >= rtp_config_.ssrcs.size()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100834 RTC_LOG(LS_ERROR) << "Encoded image outside simulcast range ("
835 << simulcast_idx << " >= " << rtp_config_.ssrcs.size()
836 << ").";
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000837 return;
838 }
perkj26091b12016-09-01 01:17:40 -0700839 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx];
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000840
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000841 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200842 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000843 return;
844
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000845 stats->width = encoded_image._encodedWidth;
846 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000847 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700848
sprangb4a1ae52015-12-03 08:10:08 -0800849 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
850 kVideoFrameKey);
asapersson17821db2015-12-14 02:08:12 -0800851 stats_.bw_limited_resolution =
kthelgason0cd27ba2016-12-19 06:32:16 -0800852 encoded_image.adapt_reason_.bw_resolutions_disabled > 0 ||
853 quality_downscales_ > 0;
asapersson17821db2015-12-14 02:08:12 -0800854
kthelgason0cd27ba2016-12-19 06:32:16 -0800855 if (quality_downscales_ != -1) {
856 uma_container_->quality_limited_frame_counter_.Add(quality_downscales_ > 0);
857 if (quality_downscales_ > 0)
858 uma_container_->quality_downscales_counter_.Add(quality_downscales_);
asapersson4306fc72015-10-19 00:35:21 -0700859 }
asaperssonda535c42015-10-19 23:32:41 -0700860 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
861 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800862 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700863 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800864 uma_container_->bw_resolutions_disabled_counter_.Add(
865 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700866 }
867 }
asapersson4306fc72015-10-19 00:35:21 -0700868
sakal87da4042016-10-31 06:53:47 -0700869 if (encoded_image.qp_ != -1) {
870 if (!stats_.qp_sum)
871 stats_.qp_sum = rtc::Optional<uint64_t>(0);
872 *stats_.qp_sum += encoded_image.qp_;
873
874 if (codec_info) {
875 if (codec_info->codecType == kVideoCodecVP8) {
876 int spatial_idx = (rtp_config_.ssrcs.size() == 1)
877 ? -1
878 : static_cast<int>(simulcast_idx);
879 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
880 } else if (codec_info->codecType == kVideoCodecVP9) {
881 int spatial_idx =
882 (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
883 ? -1
884 : codec_info->codecSpecific.VP9.spatial_idx;
885 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
asapersson827cab32016-11-02 09:08:47 -0700886 } else if (codec_info->codecType == kVideoCodecH264) {
887 int spatial_idx = -1;
888 uma_container_->qp_counters_[spatial_idx].h264.Add(encoded_image.qp_);
sakal87da4042016-10-31 06:53:47 -0700889 }
asapersson5265fed2016-04-18 02:58:47 -0700890 }
asapersson118ef002016-03-31 00:00:19 -0700891 }
892
Åsa Persson0122e842017-10-16 12:19:23 +0200893 media_byte_rate_tracker_.AddSamples(encoded_image._length);
894 if (uma_container_->InsertEncodedFrame(encoded_image))
895 encoded_frame_rate_tracker_.AddSamples(1);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000896}
897
Per69b332d2016-06-02 15:45:42 +0200898int SendStatisticsProxy::GetSendFrameRate() const {
899 rtc::CritScope lock(&crit_);
Åsa Persson0122e842017-10-16 12:19:23 +0200900 return round(encoded_frame_rate_tracker_.ComputeRate());
Per69b332d2016-06-02 15:45:42 +0200901}
902
asaperssond89920b2015-07-22 06:52:00 -0700903void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200904 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800905 uma_container_->input_frame_rate_tracker_.AddSamples(1);
asapersson320e45a2016-11-29 01:40:35 -0800906 uma_container_->input_fps_counter_.Add(1);
sprangb4a1ae52015-12-03 08:10:08 -0800907 uma_container_->input_width_counter_.Add(width);
908 uma_container_->input_height_counter_.Add(height);
asaperssonf4e44af2017-04-19 02:01:06 -0700909 if (cpu_downscales_ >= 0) {
910 uma_container_->cpu_limited_frame_counter_.Add(
911 stats_.cpu_limited_resolution);
912 }
Åsa Perssond29b54c2017-10-19 17:32:17 +0200913 if (encoded_frame_rate_tracker_.TotalSampleCount() == 0) {
914 // Set start time now instead of when first key frame is encoded to avoid a
915 // too high initial estimate.
916 encoded_frame_rate_tracker_.AddSamples(0);
917 }
perkj803d97f2016-11-01 11:45:46 -0700918}
919
Ilya Nikolaevskiyd79314f2017-10-23 10:45:37 +0200920void SendStatisticsProxy::OnFrameDroppedBySource() {
921 rtc::CritScope lock(&crit_);
922 ++stats_.frames_dropped_by_capturer;
923}
924
925void SendStatisticsProxy::OnFrameDroppedInEncoderQueue() {
926 rtc::CritScope lock(&crit_);
927 ++stats_.frames_dropped_by_encoder_queue;
928}
929
930void SendStatisticsProxy::OnFrameDroppedByEncoder() {
931 rtc::CritScope lock(&crit_);
932 ++stats_.frames_dropped_by_encoder;
933}
934
935void SendStatisticsProxy::OnFrameDroppedByMediaOptimizations() {
936 rtc::CritScope lock(&crit_);
937 ++stats_.frames_dropped_by_rate_limiter;
938}
939
asapersson09f05612017-05-15 23:40:18 -0700940void SendStatisticsProxy::SetAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700941 const VideoStreamEncoder::AdaptCounts& cpu_counts,
942 const VideoStreamEncoder::AdaptCounts& quality_counts) {
perkj803d97f2016-11-01 11:45:46 -0700943 rtc::CritScope lock(&crit_);
asapersson09f05612017-05-15 23:40:18 -0700944 SetAdaptTimer(cpu_counts, &uma_container_->cpu_adapt_timer_);
945 SetAdaptTimer(quality_counts, &uma_container_->quality_adapt_timer_);
946 UpdateAdaptationStats(cpu_counts, quality_counts);
asapersson36e9eb42017-03-31 05:29:12 -0700947}
948
asapersson09f05612017-05-15 23:40:18 -0700949void SendStatisticsProxy::OnCpuAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700950 const VideoStreamEncoder::AdaptCounts& cpu_counts,
951 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson36e9eb42017-03-31 05:29:12 -0700952 rtc::CritScope lock(&crit_);
perkj803d97f2016-11-01 11:45:46 -0700953 ++stats_.number_of_cpu_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700954 UpdateAdaptationStats(cpu_counts, quality_counts);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000955}
956
asapersson09f05612017-05-15 23:40:18 -0700957void SendStatisticsProxy::OnQualityAdaptationChanged(
mflodmancc3d4422017-08-03 08:27:51 -0700958 const VideoStreamEncoder::AdaptCounts& cpu_counts,
959 const VideoStreamEncoder::AdaptCounts& quality_counts) {
kthelgason876222f2016-11-29 01:44:11 -0800960 rtc::CritScope lock(&crit_);
asaperssonfab67072017-04-04 05:51:49 -0700961 ++stats_.number_of_quality_adapt_changes;
asapersson09f05612017-05-15 23:40:18 -0700962 UpdateAdaptationStats(cpu_counts, quality_counts);
963}
964
965void SendStatisticsProxy::UpdateAdaptationStats(
mflodmancc3d4422017-08-03 08:27:51 -0700966 const VideoStreamEncoder::AdaptCounts& cpu_counts,
967 const VideoStreamEncoder::AdaptCounts& quality_counts) {
asapersson09f05612017-05-15 23:40:18 -0700968 cpu_downscales_ = cpu_counts.resolution;
969 quality_downscales_ = quality_counts.resolution;
970
971 stats_.cpu_limited_resolution = cpu_counts.resolution > 0;
972 stats_.cpu_limited_framerate = cpu_counts.fps > 0;
973 stats_.bw_limited_resolution = quality_counts.resolution > 0;
974 stats_.bw_limited_framerate = quality_counts.fps > 0;
975}
976
mflodmancc3d4422017-08-03 08:27:51 -0700977void SendStatisticsProxy::SetAdaptTimer(
978 const VideoStreamEncoder::AdaptCounts& counts,
979 StatsTimer* timer) {
asapersson09f05612017-05-15 23:40:18 -0700980 if (counts.resolution >= 0 || counts.fps >= 0) {
981 // Adaptation enabled.
982 if (!stats_.suspended)
983 timer->Start(clock_->TimeInMilliseconds());
984 return;
985 }
986 timer->Stop(clock_->TimeInMilliseconds());
kthelgason876222f2016-11-29 01:44:11 -0800987}
988
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000989void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
990 uint32_t ssrc,
991 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200992 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000993 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200994 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000995 return;
996
997 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800998 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
999 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00001000}
1001
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001002void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
1003 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001004 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001005 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001006 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001007 return;
1008
1009 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -08001010 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001011}
1012
Peter Boströmd1d66ba2016-02-08 14:07:14 +01001013void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001014
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001015void SendStatisticsProxy::DataCountersUpdated(
1016 const StreamDataCounters& counters,
1017 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001018 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001019 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
asapersson93e1e232017-02-06 05:18:35 -08001020 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001021
asaperssona6a699a2016-11-25 03:52:46 -08001022 if (stats->is_flexfec) {
1023 // The same counters are reported for both the media ssrc and flexfec ssrc.
1024 // Bitrate stats are summed for all SSRCs. Use fec stats from media update.
1025 return;
1026 }
1027
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001028 stats->rtp_stats = counters;
asapersson6eca98b2017-04-04 23:40:50 -07001029 if (uma_container_->first_rtp_stats_time_ms_ == -1) {
1030 int64_t now_ms = clock_->TimeInMilliseconds();
1031 uma_container_->first_rtp_stats_time_ms_ = now_ms;
asapersson09f05612017-05-15 23:40:18 -07001032 uma_container_->cpu_adapt_timer_.Restart(now_ms);
1033 uma_container_->quality_adapt_timer_.Restart(now_ms);
asapersson6eca98b2017-04-04 23:40:50 -07001034 }
asapersson93e1e232017-02-06 05:18:35 -08001035
1036 uma_container_->total_byte_counter_.Set(counters.transmitted.TotalBytes(),
1037 ssrc);
1038 uma_container_->padding_byte_counter_.Set(counters.transmitted.padding_bytes,
1039 ssrc);
1040 uma_container_->retransmit_byte_counter_.Set(
1041 counters.retransmitted.TotalBytes(), ssrc);
1042 uma_container_->fec_byte_counter_.Set(counters.fec.TotalBytes(), ssrc);
1043 if (stats->is_rtx) {
1044 uma_container_->rtx_byte_counter_.Set(counters.transmitted.TotalBytes(),
1045 ssrc);
1046 } else {
1047 uma_container_->media_byte_counter_.Set(counters.MediaPayloadBytes(), ssrc);
1048 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001049}
1050
sprangcd349d92016-07-13 09:11:28 -07001051void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
1052 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001053 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001054 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001055 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001056 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001057 return;
1058
sprangcd349d92016-07-13 09:11:28 -07001059 stats->total_bitrate_bps = total_bitrate_bps;
1060 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001061}
1062
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001063void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
1064 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001065 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001066 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001067 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001068 return;
1069
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001070 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001071}
1072
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001073void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
1074 int max_delay_ms,
1075 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +02001076 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001077 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +02001078 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001079 return;
1080 stats->avg_delay_ms = avg_delay_ms;
1081 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -08001082
sprangb4a1ae52015-12-03 08:10:08 -08001083 uma_container_->delay_counter_.Add(avg_delay_ms);
1084 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +00001085}
1086
asapersson6eca98b2017-04-04 23:40:50 -07001087void SendStatisticsProxy::StatsTimer::Start(int64_t now_ms) {
1088 if (start_ms == -1)
1089 start_ms = now_ms;
1090}
1091
1092void SendStatisticsProxy::StatsTimer::Stop(int64_t now_ms) {
1093 if (start_ms != -1) {
1094 total_ms += now_ms - start_ms;
1095 start_ms = -1;
1096 }
1097}
1098
1099void SendStatisticsProxy::StatsTimer::Restart(int64_t now_ms) {
1100 total_ms = 0;
1101 if (start_ms != -1)
1102 start_ms = now_ms;
1103}
1104
asaperssond89920b2015-07-22 06:52:00 -07001105void SendStatisticsProxy::SampleCounter::Add(int sample) {
1106 sum += sample;
1107 ++num_samples;
1108}
1109
asapersson66d4b372016-12-19 06:50:53 -08001110int SendStatisticsProxy::SampleCounter::Avg(
1111 int64_t min_required_samples) const {
asaperssond89920b2015-07-22 06:52:00 -07001112 if (num_samples < min_required_samples || num_samples == 0)
1113 return -1;
asapersson66d4b372016-12-19 06:50:53 -08001114 return static_cast<int>((sum + (num_samples / 2)) / num_samples);
asaperssond89920b2015-07-22 06:52:00 -07001115}
1116
asaperssondec5ebf2015-10-05 02:36:17 -07001117void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
1118 if (sample)
1119 ++sum;
1120 ++num_samples;
1121}
1122
asapersson66d4b372016-12-19 06:50:53 -08001123void SendStatisticsProxy::BoolSampleCounter::Add(bool sample, int64_t count) {
1124 if (sample)
1125 sum += count;
1126 num_samples += count;
1127}
asaperssondec5ebf2015-10-05 02:36:17 -07001128int SendStatisticsProxy::BoolSampleCounter::Percent(
asapersson66d4b372016-12-19 06:50:53 -08001129 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001130 return Fraction(min_required_samples, 100.0f);
1131}
1132
1133int SendStatisticsProxy::BoolSampleCounter::Permille(
asapersson66d4b372016-12-19 06:50:53 -08001134 int64_t min_required_samples) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001135 return Fraction(min_required_samples, 1000.0f);
1136}
1137
1138int SendStatisticsProxy::BoolSampleCounter::Fraction(
asapersson66d4b372016-12-19 06:50:53 -08001139 int64_t min_required_samples,
1140 float multiplier) const {
asaperssondec5ebf2015-10-05 02:36:17 -07001141 if (num_samples < min_required_samples || num_samples == 0)
1142 return -1;
1143 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
1144}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001145} // namespace webrtc