blob: 3d82a3b0468d121bf8fe6b2416851b2239e91a81 [file] [log] [blame]
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/video/send_statistics_proxy.h"
12
asaperssond89920b2015-07-22 06:52:00 -070013#include <algorithm>
Tim Psiakiad13d2f2015-11-10 16:34:50 -080014#include <cmath>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000015#include <map>
asapersson58d992e2016-03-29 02:15:06 -070016#include <vector>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000017
pbos@webrtc.org49096de2015-02-24 22:37:52 +000018#include "webrtc/base/checks.h"
Peter Boström415d2cd2015-10-26 11:35:17 +010019#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010020#include "webrtc/system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000021
22namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070023namespace {
asapersson1aa420b2015-12-07 03:12:22 -080024const float kEncodeTimeWeigthFactor = 0.5f;
25
asapersson2a0a2a42015-10-27 01:32:00 -070026// Used by histograms. Values of entries should not be changed.
27enum HistogramCodecType {
28 kVideoUnknown = 0,
29 kVideoVp8 = 1,
30 kVideoVp9 = 2,
31 kVideoH264 = 3,
32 kVideoMax = 64,
33};
34
asaperssonc2148a52016-02-04 00:33:21 -080035const char* kRealtimePrefix = "WebRTC.Video.";
36const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
37
sprangb4a1ae52015-12-03 08:10:08 -080038const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
39 switch (content_type) {
40 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080041 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080042 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080043 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080044 }
45 RTC_NOTREACHED();
46 return nullptr;
47}
48
asapersson2a0a2a42015-10-27 01:32:00 -070049HistogramCodecType PayloadNameToHistogramCodecType(
50 const std::string& payload_name) {
51 if (payload_name == "VP8") {
52 return kVideoVp8;
53 } else if (payload_name == "VP9") {
54 return kVideoVp9;
55 } else if (payload_name == "H264") {
56 return kVideoH264;
57 } else {
58 return kVideoUnknown;
59 }
60}
61
62void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080063 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
64 PayloadNameToHistogramCodecType(payload_name),
65 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070066}
67} // namespace
68
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000069
pbos@webrtc.org273a4142014-12-01 15:23:21 +000070const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
71
sprangb4a1ae52015-12-03 08:10:08 -080072SendStatisticsProxy::SendStatisticsProxy(
73 Clock* clock,
74 const VideoSendStream::Config& config,
75 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070076 : clock_(clock),
77 config_(config),
sprangb4a1ae52015-12-03 08:10:08 -080078 content_type_(content_type),
asaperssond89920b2015-07-22 06:52:00 -070079 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080080 encode_time_(kEncodeTimeWeigthFactor),
sprang07fb9be2016-02-24 07:55:00 -080081 uma_container_(
82 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
asapersson2a0a2a42015-10-27 01:32:00 -070083 UpdateCodecTypeHistogram(config_.encoder_settings.payload_name);
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000084}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000085
sprang07fb9be2016-02-24 07:55:00 -080086SendStatisticsProxy::~SendStatisticsProxy() {
87 rtc::CritScope lock(&crit_);
88 uma_container_->UpdateHistograms(config_, stats_);
89}
sprangb4a1ae52015-12-03 08:10:08 -080090
91SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -080092 const char* prefix,
93 const VideoSendStream::Stats& stats,
94 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -080095 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -080096 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -080097 max_sent_width_per_timestamp_(0),
98 max_sent_height_per_timestamp_(0),
99 input_frame_rate_tracker_(100u, 10u),
sprange2d83d62016-02-19 09:03:26 -0800100 sent_frame_rate_tracker_(100u, 10u),
sprang07fb9be2016-02-24 07:55:00 -0800101 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100102 first_rtp_stats_time_ms_(-1),
sprang07fb9be2016-02-24 07:55:00 -0800103 start_stats_(stats) {}
sprangb4a1ae52015-12-03 08:10:08 -0800104
sprang07fb9be2016-02-24 07:55:00 -0800105SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200106
Erik Språng22c2b482016-03-01 09:40:42 +0100107void AccumulateRtpStats(const VideoSendStream::Stats& stats,
108 const VideoSendStream::Config& config,
109 StreamDataCounters* total_rtp_stats,
110 StreamDataCounters* rtx_stats) {
111 for (auto it : stats.substreams) {
112 const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs;
113 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) !=
114 rtx_ssrcs.end()) {
115 rtx_stats->Add(it.second.rtp_stats);
116 } else {
117 total_rtp_stats->Add(it.second.rtp_stats);
118 }
119 }
120}
121
sprang07fb9be2016-02-24 07:55:00 -0800122void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
123 const VideoSendStream::Config& config,
124 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800125 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
126 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson6718e972015-07-24 00:20:58 -0700127 const int kMinRequiredSamples = 200;
asaperssond89920b2015-07-22 06:52:00 -0700128 int in_width = input_width_counter_.Avg(kMinRequiredSamples);
129 int in_height = input_height_counter_.Avg(kMinRequiredSamples);
asapersson6f14be82015-11-16 00:40:49 -0800130 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate());
asaperssond89920b2015-07-22 06:52:00 -0700131 if (in_width != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700132 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
133 kIndex, uma_prefix_ + "InputWidthInPixels", in_width);
134 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
135 kIndex, uma_prefix_ + "InputHeightInPixels", in_height);
136 RTC_LOGGED_HISTOGRAMS_COUNTS_100(
137 kIndex, uma_prefix_ + "InputFramesPerSecond", in_fps);
asaperssond89920b2015-07-22 06:52:00 -0700138 }
139 int sent_width = sent_width_counter_.Avg(kMinRequiredSamples);
140 int sent_height = sent_height_counter_.Avg(kMinRequiredSamples);
asapersson6f14be82015-11-16 00:40:49 -0800141 int sent_fps = round(sent_frame_rate_tracker_.ComputeTotalRate());
asaperssond89920b2015-07-22 06:52:00 -0700142 if (sent_width != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700143 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
144 kIndex, uma_prefix_ + "SentWidthInPixels", sent_width);
145 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
146 kIndex, uma_prefix_ + "SentHeightInPixels", sent_height);
147 RTC_LOGGED_HISTOGRAMS_COUNTS_100(
148 kIndex, uma_prefix_ + "SentFramesPerSecond", sent_fps);
asaperssond89920b2015-07-22 06:52:00 -0700149 }
asapersson6718e972015-07-24 00:20:58 -0700150 int encode_ms = encode_time_counter_.Avg(kMinRequiredSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800151 if (encode_ms != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700152 RTC_LOGGED_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
153 encode_ms);
asaperssonc2148a52016-02-04 00:33:21 -0800154 }
asaperssondec5ebf2015-10-05 02:36:17 -0700155 int key_frames_permille = key_frame_counter_.Permille(kMinRequiredSamples);
156 if (key_frames_permille != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700157 RTC_LOGGED_HISTOGRAMS_COUNTS_1000(
158 kIndex, uma_prefix_ + "KeyFramesSentInPermille", key_frames_permille);
asaperssondec5ebf2015-10-05 02:36:17 -0700159 }
asapersson4306fc72015-10-19 00:35:21 -0700160 int quality_limited =
161 quality_limited_frame_counter_.Percent(kMinRequiredSamples);
162 if (quality_limited != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700163 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
164 kIndex, uma_prefix_ + "QualityLimitedResolutionInPercent",
165 quality_limited);
asapersson4306fc72015-10-19 00:35:21 -0700166 }
167 int downscales = quality_downscales_counter_.Avg(kMinRequiredSamples);
168 if (downscales != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700169 RTC_LOGGED_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800170 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
171 20);
asapersson4306fc72015-10-19 00:35:21 -0700172 }
asaperssonda535c42015-10-19 23:32:41 -0700173 int bw_limited = bw_limited_frame_counter_.Percent(kMinRequiredSamples);
174 if (bw_limited != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700175 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800176 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
177 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700178 }
179 int num_disabled = bw_resolutions_disabled_counter_.Avg(kMinRequiredSamples);
180 if (num_disabled != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700181 RTC_LOGGED_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800182 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
183 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700184 }
asaperssonf040b232015-11-04 00:59:03 -0800185 int delay_ms = delay_counter_.Avg(kMinRequiredSamples);
186 if (delay_ms != -1)
asapersson58d992e2016-03-29 02:15:06 -0700187 RTC_LOGGED_HISTOGRAMS_COUNTS_100000(
188 kIndex, uma_prefix_ + "SendSideDelayInMs", delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800189
190 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredSamples);
191 if (max_delay_ms != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700192 RTC_LOGGED_HISTOGRAMS_COUNTS_100000(
193 kIndex, uma_prefix_ + "SendSideDelayMaxInMs", max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800194 }
sprang07fb9be2016-02-24 07:55:00 -0800195
asapersson118ef002016-03-31 00:00:19 -0700196 for (const auto& it : qp_counters_) {
197 int qp = it.second.vp8.Avg(kMinRequiredSamples);
198 if (qp != -1) {
199 int spatial_idx = it.first;
200 if (spatial_idx == -1) {
201 RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
202 qp);
203 } else if (spatial_idx == 0) {
204 RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex,
205 uma_prefix_ + "Encoded.Qp.Vp8.S0", qp);
206 } else if (spatial_idx == 1) {
207 RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex,
208 uma_prefix_ + "Encoded.Qp.Vp8.S1", qp);
209 } else if (spatial_idx == 2) {
210 RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex,
211 uma_prefix_ + "Encoded.Qp.Vp8.S2", qp);
212 } else {
213 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
214 << spatial_idx;
215 }
216 }
217 }
218
sprange2d83d62016-02-19 09:03:26 -0800219 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800220 int64_t elapsed_sec =
221 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
222 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
223 int fraction_lost = report_block_stats_.FractionLostInPercent();
224 if (fraction_lost != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700225 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800226 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
227 }
228
229 // The RTCP packet type counters, delivered via the
230 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
231 // life of the send stream and are not reset when switching content type.
232 // For the purpose of these statistics though, we want new counts when
233 // switching since we switch histogram name. On every reset of the
234 // UmaSamplesContainer, we save the initial state of the counters, so that
235 // we can calculate the delta here and aggregate over all ssrcs.
236 RtcpPacketTypeCounter counters;
237 for (uint32_t ssrc : config.rtp.ssrcs) {
238 auto kv = current_stats.substreams.find(ssrc);
239 if (kv == current_stats.substreams.end())
240 continue;
241
242 RtcpPacketTypeCounter stream_counters =
243 kv->second.rtcp_packet_type_counts;
244 kv = start_stats_.substreams.find(ssrc);
245 if (kv != start_stats_.substreams.end())
246 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
247
248 counters.Add(stream_counters);
249 }
asapersson58d992e2016-03-29 02:15:06 -0700250 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
251 kIndex, uma_prefix_ + "NackPacketsReceivedPerMinute",
252 counters.nack_packets * 60 / elapsed_sec);
253 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
254 kIndex, uma_prefix_ + "FirPacketsReceivedPerMinute",
255 counters.fir_packets * 60 / elapsed_sec);
256 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
257 kIndex, uma_prefix_ + "PliPacketsReceivedPerMinute",
258 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800259 if (counters.nack_requests > 0) {
asapersson58d992e2016-03-29 02:15:06 -0700260 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800261 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
262 counters.UniqueNackRequestsInPercent());
263 }
sprange2d83d62016-02-19 09:03:26 -0800264 }
265 }
Erik Språng22c2b482016-03-01 09:40:42 +0100266
267 if (first_rtp_stats_time_ms_ != -1) {
268 int64_t elapsed_sec =
269 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
270 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
271 StreamDataCounters rtp;
272 StreamDataCounters rtx;
273 AccumulateRtpStats(current_stats, config, &rtp, &rtx);
274 StreamDataCounters start_rtp;
275 StreamDataCounters start_rtx;
276 AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx);
277 rtp.Subtract(start_rtp);
278 rtx.Subtract(start_rtx);
279 StreamDataCounters rtp_rtx = rtp;
280 rtp_rtx.Add(rtx);
281
asapersson58d992e2016-03-29 02:15:06 -0700282 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100283 kIndex, uma_prefix_ + "BitrateSentInKbps",
284 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
285 1000));
asapersson58d992e2016-03-29 02:15:06 -0700286 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100287 kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
288 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
asapersson58d992e2016-03-29 02:15:06 -0700289 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100290 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps",
291 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
292 1000));
asapersson58d992e2016-03-29 02:15:06 -0700293 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100294 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps",
295 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
296 elapsed_sec / 1000));
297 if (!config.rtp.rtx.ssrcs.empty()) {
asapersson58d992e2016-03-29 02:15:06 -0700298 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100299 kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
300 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
301 1000));
302 }
303 if (config.rtp.fec.red_payload_type != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700304 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
305 kIndex, uma_prefix_ + "FecBitrateSentInKbps",
306 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec /
307 1000));
Erik Språng22c2b482016-03-01 09:40:42 +0100308 }
309 }
310 }
sprangb4a1ae52015-12-03 08:10:08 -0800311}
312
313void SendStatisticsProxy::SetContentType(
314 VideoEncoderConfig::ContentType content_type) {
315 rtc::CritScope lock(&crit_);
316 if (content_type_ != content_type) {
sprang07fb9be2016-02-24 07:55:00 -0800317 uma_container_->UpdateHistograms(config_, stats_);
318 uma_container_.reset(
319 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_));
sprangb4a1ae52015-12-03 08:10:08 -0800320 content_type_ = content_type;
asaperssonf040b232015-11-04 00:59:03 -0800321 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200322}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000323
Peter Boströmb7d9a972015-12-18 16:01:11 +0100324void SendStatisticsProxy::OnEncoderImplementationName(
325 const char* implementation_name) {
326 rtc::CritScope lock(&crit_);
327 stats_.encoder_implementation_name = implementation_name;
328}
329
Peter Boström7083e112015-09-22 16:28:51 +0200330void SendStatisticsProxy::OnOutgoingRate(uint32_t framerate, uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200331 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000332 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000333 stats_.media_bitrate_bps = bitrate;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000334}
335
Peter Boströme4499152016-02-05 11:13:28 +0100336void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
337 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000338 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200339 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100340 uma_container_->encode_time_counter_.Add(encode_time_ms);
341 encode_time_.Apply(1.0f, encode_time_ms);
342 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000343 stats_.encode_usage_percent = metrics.encode_usage_percent;
344}
345
Peter Boström7083e112015-09-22 16:28:51 +0200346void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200347 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000348 stats_.suspended = is_suspended;
349}
350
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000351VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200352 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000353 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000354 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800355 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000356 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000357}
358
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000359void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200360 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000361 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
362 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000363 it != stats_.substreams.end(); ++it) {
364 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200365 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
366 it->second.width = 0;
367 it->second.height = 0;
368 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000369 }
370}
371
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000372VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
373 uint32_t ssrc) {
374 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
375 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000376 if (it != stats_.substreams.end())
377 return &it->second;
378
379 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) ==
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000380 config_.rtp.ssrcs.end() &&
381 std::find(config_.rtp.rtx.ssrcs.begin(),
382 config_.rtp.rtx.ssrcs.end(),
383 ssrc) == config_.rtp.rtx.ssrcs.end()) {
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000384 return nullptr;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000385 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000386
387 return &stats_.substreams[ssrc]; // Insert new entry and return ptr.
388}
389
Peter Boström20f3f942015-05-15 11:33:39 +0200390void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
391 rtc::CritScope lock(&crit_);
392 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
393 if (stats == nullptr)
394 return;
395
396 stats->total_bitrate_bps = 0;
397 stats->retransmit_bitrate_bps = 0;
398 stats->height = 0;
399 stats->width = 0;
400}
401
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000402void SendStatisticsProxy::OnSetRates(uint32_t bitrate_bps, int framerate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200403 rtc::CritScope lock(&crit_);
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000404 stats_.target_media_bitrate_bps = bitrate_bps;
405}
406
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000407void SendStatisticsProxy::OnSendEncodedImage(
408 const EncodedImage& encoded_image,
409 const RTPVideoHeader* rtp_video_header) {
410 size_t simulcast_idx =
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000411 rtp_video_header != nullptr ? rtp_video_header->simulcastIdx : 0;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000412 if (simulcast_idx >= config_.rtp.ssrcs.size()) {
413 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
414 << " >= " << config_.rtp.ssrcs.size() << ").";
415 return;
416 }
417 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx];
418
Peter Boströmf2f82832015-05-01 13:00:41 +0200419 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000420 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000421 if (stats == nullptr)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000422 return;
423
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000424 stats->width = encoded_image._encodedWidth;
425 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000426 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700427
sprangb4a1ae52015-12-03 08:10:08 -0800428 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
429 kVideoFrameKey);
asaperssondec5ebf2015-10-05 02:36:17 -0700430
asapersson17821db2015-12-14 02:08:12 -0800431 stats_.bw_limited_resolution =
432 encoded_image.adapt_reason_.quality_resolution_downscales > 0 ||
433 encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
434
asapersson4306fc72015-10-19 00:35:21 -0700435 if (encoded_image.adapt_reason_.quality_resolution_downscales != -1) {
436 bool downscaled =
437 encoded_image.adapt_reason_.quality_resolution_downscales > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800438 uma_container_->quality_limited_frame_counter_.Add(downscaled);
asapersson4306fc72015-10-19 00:35:21 -0700439 if (downscaled) {
sprangb4a1ae52015-12-03 08:10:08 -0800440 uma_container_->quality_downscales_counter_.Add(
asapersson4306fc72015-10-19 00:35:21 -0700441 encoded_image.adapt_reason_.quality_resolution_downscales);
442 }
443 }
asaperssonda535c42015-10-19 23:32:41 -0700444 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
445 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800446 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700447 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800448 uma_container_->bw_resolutions_disabled_counter_.Add(
449 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700450 }
451 }
asapersson4306fc72015-10-19 00:35:21 -0700452
asapersson118ef002016-03-31 00:00:19 -0700453 if (encoded_image.qp_ != -1 && rtp_video_header != nullptr &&
454 rtp_video_header->codec == kRtpVideoVp8) {
455 int spatial_idx =
456 (config_.rtp.ssrcs.size() == 1) ? -1 : static_cast<int>(simulcast_idx);
457 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
458 }
459
asaperssond89920b2015-07-22 06:52:00 -0700460 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
461 // different threads and there is no guarantee that one frame of all layers
462 // are encoded before the next start.
463 if (last_sent_frame_timestamp_ > 0 &&
464 encoded_image._timeStamp != last_sent_frame_timestamp_) {
sprangb4a1ae52015-12-03 08:10:08 -0800465 uma_container_->sent_frame_rate_tracker_.AddSamples(1);
466 uma_container_->sent_width_counter_.Add(
467 uma_container_->max_sent_width_per_timestamp_);
468 uma_container_->sent_height_counter_.Add(
469 uma_container_->max_sent_height_per_timestamp_);
470 uma_container_->max_sent_width_per_timestamp_ = 0;
471 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200472 }
asaperssond89920b2015-07-22 06:52:00 -0700473 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800474 uma_container_->max_sent_width_per_timestamp_ =
475 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700476 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800477 uma_container_->max_sent_height_per_timestamp_ =
478 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700479 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000480}
481
asaperssond89920b2015-07-22 06:52:00 -0700482void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200483 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800484 uma_container_->input_frame_rate_tracker_.AddSamples(1);
485 uma_container_->input_width_counter_.Add(width);
486 uma_container_->input_height_counter_.Add(height);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000487}
488
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000489void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
490 uint32_t ssrc,
491 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200492 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000493 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000494 if (stats == nullptr)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000495 return;
496
497 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800498 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
499 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000500}
501
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000502void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
503 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200504 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000505 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000506 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000507 return;
508
509 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800510 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000511}
512
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100513void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000514
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000515void SendStatisticsProxy::DataCountersUpdated(
516 const StreamDataCounters& counters,
517 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200518 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000519 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
henrikg91d6ede2015-09-17 00:24:34 -0700520 RTC_DCHECK(stats != nullptr)
521 << "DataCountersUpdated reported for unknown ssrc: " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000522
523 stats->rtp_stats = counters;
Erik Språng22c2b482016-03-01 09:40:42 +0100524 if (uma_container_->first_rtp_stats_time_ms_ == -1)
525 uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000526}
527
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000528void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
529 const BitrateStatistics& retransmit_stats,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000530 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200531 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000532 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000533 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000534 return;
535
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000536 stats->total_bitrate_bps = total_stats.bitrate_bps;
537 stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000538}
539
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000540void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
541 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200542 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000543 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000544 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000545 return;
546
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000547 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000548}
549
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000550void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
551 int max_delay_ms,
552 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200553 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000554 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000555 if (stats == nullptr)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000556 return;
557 stats->avg_delay_ms = avg_delay_ms;
558 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800559
sprangb4a1ae52015-12-03 08:10:08 -0800560 uma_container_->delay_counter_.Add(avg_delay_ms);
561 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000562}
563
asaperssond89920b2015-07-22 06:52:00 -0700564void SendStatisticsProxy::SampleCounter::Add(int sample) {
565 sum += sample;
566 ++num_samples;
567}
568
569int SendStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
570 if (num_samples < min_required_samples || num_samples == 0)
571 return -1;
asaperssonda535c42015-10-19 23:32:41 -0700572 return (sum + (num_samples / 2)) / num_samples;
asaperssond89920b2015-07-22 06:52:00 -0700573}
574
asaperssondec5ebf2015-10-05 02:36:17 -0700575void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
576 if (sample)
577 ++sum;
578 ++num_samples;
579}
580
581int SendStatisticsProxy::BoolSampleCounter::Percent(
582 int min_required_samples) const {
583 return Fraction(min_required_samples, 100.0f);
584}
585
586int SendStatisticsProxy::BoolSampleCounter::Permille(
587 int min_required_samples) const {
588 return Fraction(min_required_samples, 1000.0f);
589}
590
591int SendStatisticsProxy::BoolSampleCounter::Fraction(
592 int min_required_samples, float multiplier) const {
593 if (num_samples < min_required_samples || num_samples == 0)
594 return -1;
595 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
596}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000597} // namespace webrtc