blob: dfa7185f36e6f289ed995f9490ef1d12d7a0d761 [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"
kjellander02b3d272016-04-20 05:05:54 -070020#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000022
23namespace webrtc {
asapersson2a0a2a42015-10-27 01:32:00 -070024namespace {
asapersson1aa420b2015-12-07 03:12:22 -080025const float kEncodeTimeWeigthFactor = 0.5f;
26
asapersson2a0a2a42015-10-27 01:32:00 -070027// Used by histograms. Values of entries should not be changed.
28enum HistogramCodecType {
29 kVideoUnknown = 0,
30 kVideoVp8 = 1,
31 kVideoVp9 = 2,
32 kVideoH264 = 3,
33 kVideoMax = 64,
34};
35
asaperssonc2148a52016-02-04 00:33:21 -080036const char* kRealtimePrefix = "WebRTC.Video.";
37const char* kScreenPrefix = "WebRTC.Video.Screenshare.";
38
sprangb4a1ae52015-12-03 08:10:08 -080039const char* GetUmaPrefix(VideoEncoderConfig::ContentType content_type) {
40 switch (content_type) {
41 case VideoEncoderConfig::ContentType::kRealtimeVideo:
asaperssonc2148a52016-02-04 00:33:21 -080042 return kRealtimePrefix;
sprangb4a1ae52015-12-03 08:10:08 -080043 case VideoEncoderConfig::ContentType::kScreen:
asaperssonc2148a52016-02-04 00:33:21 -080044 return kScreenPrefix;
sprangb4a1ae52015-12-03 08:10:08 -080045 }
46 RTC_NOTREACHED();
47 return nullptr;
48}
49
asapersson2a0a2a42015-10-27 01:32:00 -070050HistogramCodecType PayloadNameToHistogramCodecType(
51 const std::string& payload_name) {
52 if (payload_name == "VP8") {
53 return kVideoVp8;
54 } else if (payload_name == "VP9") {
55 return kVideoVp9;
56 } else if (payload_name == "H264") {
57 return kVideoH264;
58 } else {
59 return kVideoUnknown;
60 }
61}
62
63void UpdateCodecTypeHistogram(const std::string& payload_name) {
asapersson28ba9272016-01-25 05:58:23 -080064 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.Encoder.CodecType",
65 PayloadNameToHistogramCodecType(payload_name),
66 kVideoMax);
asapersson2a0a2a42015-10-27 01:32:00 -070067}
68} // namespace
69
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000070
pbos@webrtc.org273a4142014-12-01 15:23:21 +000071const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
72
sprangb4a1ae52015-12-03 08:10:08 -080073SendStatisticsProxy::SendStatisticsProxy(
74 Clock* clock,
75 const VideoSendStream::Config& config,
76 VideoEncoderConfig::ContentType content_type)
asaperssond89920b2015-07-22 06:52:00 -070077 : clock_(clock),
78 config_(config),
sprangb4a1ae52015-12-03 08:10:08 -080079 content_type_(content_type),
asapersson4374a092016-07-27 00:39:09 -070080 start_ms_(clock->TimeInMilliseconds()),
asaperssond89920b2015-07-22 06:52:00 -070081 last_sent_frame_timestamp_(0),
asapersson1aa420b2015-12-07 03:12:22 -080082 encode_time_(kEncodeTimeWeigthFactor),
sprang07fb9be2016-02-24 07:55:00 -080083 uma_container_(
84 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000085}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000086
sprang07fb9be2016-02-24 07:55:00 -080087SendStatisticsProxy::~SendStatisticsProxy() {
88 rtc::CritScope lock(&crit_);
89 uma_container_->UpdateHistograms(config_, stats_);
asapersson4374a092016-07-27 00:39:09 -070090
91 int64_t elapsed_sec = (clock_->TimeInMilliseconds() - start_ms_) / 1000;
92 RTC_LOGGED_HISTOGRAM_COUNTS_100000("WebRTC.Video.SendStreamLifetimeInSeconds",
93 elapsed_sec);
94
95 if (elapsed_sec >= metrics::kMinRunTimeInSeconds)
96 UpdateCodecTypeHistogram(config_.encoder_settings.payload_name);
sprang07fb9be2016-02-24 07:55:00 -080097}
sprangb4a1ae52015-12-03 08:10:08 -080098
99SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer(
sprang07fb9be2016-02-24 07:55:00 -0800100 const char* prefix,
101 const VideoSendStream::Stats& stats,
102 Clock* const clock)
sprangb4a1ae52015-12-03 08:10:08 -0800103 : uma_prefix_(prefix),
sprang07fb9be2016-02-24 07:55:00 -0800104 clock_(clock),
sprangb4a1ae52015-12-03 08:10:08 -0800105 max_sent_width_per_timestamp_(0),
106 max_sent_height_per_timestamp_(0),
Honghai Zhang82d78622016-05-06 11:29:15 -0700107 input_frame_rate_tracker_(100, 10u),
108 sent_frame_rate_tracker_(100, 10u),
sprang07fb9be2016-02-24 07:55:00 -0800109 first_rtcp_stats_time_ms_(-1),
Erik Språng22c2b482016-03-01 09:40:42 +0100110 first_rtp_stats_time_ms_(-1),
sprang07fb9be2016-02-24 07:55:00 -0800111 start_stats_(stats) {}
sprangb4a1ae52015-12-03 08:10:08 -0800112
sprang07fb9be2016-02-24 07:55:00 -0800113SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {}
Åsa Persson24b4eda2015-06-16 10:17:01 +0200114
Erik Språng22c2b482016-03-01 09:40:42 +0100115void AccumulateRtpStats(const VideoSendStream::Stats& stats,
116 const VideoSendStream::Config& config,
117 StreamDataCounters* total_rtp_stats,
118 StreamDataCounters* rtx_stats) {
119 for (auto it : stats.substreams) {
120 const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs;
121 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) !=
122 rtx_ssrcs.end()) {
123 rtx_stats->Add(it.second.rtp_stats);
124 } else {
125 total_rtp_stats->Add(it.second.rtp_stats);
126 }
127 }
128}
129
sprang07fb9be2016-02-24 07:55:00 -0800130void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms(
131 const VideoSendStream::Config& config,
132 const VideoSendStream::Stats& current_stats) {
asaperssonc2148a52016-02-04 00:33:21 -0800133 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix);
134 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0;
asapersson6718e972015-07-24 00:20:58 -0700135 const int kMinRequiredSamples = 200;
asaperssond89920b2015-07-22 06:52:00 -0700136 int in_width = input_width_counter_.Avg(kMinRequiredSamples);
137 int in_height = input_height_counter_.Avg(kMinRequiredSamples);
asapersson6f14be82015-11-16 00:40:49 -0800138 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate());
asaperssond89920b2015-07-22 06:52:00 -0700139 if (in_width != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700140 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
141 kIndex, uma_prefix_ + "InputWidthInPixels", in_width);
142 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
143 kIndex, uma_prefix_ + "InputHeightInPixels", in_height);
144 RTC_LOGGED_HISTOGRAMS_COUNTS_100(
145 kIndex, uma_prefix_ + "InputFramesPerSecond", in_fps);
asaperssond89920b2015-07-22 06:52:00 -0700146 }
147 int sent_width = sent_width_counter_.Avg(kMinRequiredSamples);
148 int sent_height = sent_height_counter_.Avg(kMinRequiredSamples);
asapersson6f14be82015-11-16 00:40:49 -0800149 int sent_fps = round(sent_frame_rate_tracker_.ComputeTotalRate());
asaperssond89920b2015-07-22 06:52:00 -0700150 if (sent_width != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700151 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
152 kIndex, uma_prefix_ + "SentWidthInPixels", sent_width);
153 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
154 kIndex, uma_prefix_ + "SentHeightInPixels", sent_height);
155 RTC_LOGGED_HISTOGRAMS_COUNTS_100(
156 kIndex, uma_prefix_ + "SentFramesPerSecond", sent_fps);
asaperssond89920b2015-07-22 06:52:00 -0700157 }
asapersson6718e972015-07-24 00:20:58 -0700158 int encode_ms = encode_time_counter_.Avg(kMinRequiredSamples);
asaperssonc2148a52016-02-04 00:33:21 -0800159 if (encode_ms != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700160 RTC_LOGGED_HISTOGRAMS_COUNTS_1000(kIndex, uma_prefix_ + "EncodeTimeInMs",
161 encode_ms);
asaperssonc2148a52016-02-04 00:33:21 -0800162 }
asaperssondec5ebf2015-10-05 02:36:17 -0700163 int key_frames_permille = key_frame_counter_.Permille(kMinRequiredSamples);
164 if (key_frames_permille != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700165 RTC_LOGGED_HISTOGRAMS_COUNTS_1000(
166 kIndex, uma_prefix_ + "KeyFramesSentInPermille", key_frames_permille);
asaperssondec5ebf2015-10-05 02:36:17 -0700167 }
asapersson4306fc72015-10-19 00:35:21 -0700168 int quality_limited =
169 quality_limited_frame_counter_.Percent(kMinRequiredSamples);
170 if (quality_limited != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700171 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
172 kIndex, uma_prefix_ + "QualityLimitedResolutionInPercent",
173 quality_limited);
asapersson4306fc72015-10-19 00:35:21 -0700174 }
175 int downscales = quality_downscales_counter_.Avg(kMinRequiredSamples);
176 if (downscales != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700177 RTC_LOGGED_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800178 kIndex, uma_prefix_ + "QualityLimitedResolutionDownscales", downscales,
179 20);
asapersson4306fc72015-10-19 00:35:21 -0700180 }
asaperssonda535c42015-10-19 23:32:41 -0700181 int bw_limited = bw_limited_frame_counter_.Percent(kMinRequiredSamples);
182 if (bw_limited != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700183 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
asaperssonc2148a52016-02-04 00:33:21 -0800184 kIndex, uma_prefix_ + "BandwidthLimitedResolutionInPercent",
185 bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700186 }
187 int num_disabled = bw_resolutions_disabled_counter_.Avg(kMinRequiredSamples);
188 if (num_disabled != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700189 RTC_LOGGED_HISTOGRAMS_ENUMERATION(
asaperssonc2148a52016-02-04 00:33:21 -0800190 kIndex, uma_prefix_ + "BandwidthLimitedResolutionsDisabled",
191 num_disabled, 10);
asaperssonda535c42015-10-19 23:32:41 -0700192 }
asaperssonf040b232015-11-04 00:59:03 -0800193 int delay_ms = delay_counter_.Avg(kMinRequiredSamples);
194 if (delay_ms != -1)
asapersson58d992e2016-03-29 02:15:06 -0700195 RTC_LOGGED_HISTOGRAMS_COUNTS_100000(
196 kIndex, uma_prefix_ + "SendSideDelayInMs", delay_ms);
asaperssonf040b232015-11-04 00:59:03 -0800197
198 int max_delay_ms = max_delay_counter_.Avg(kMinRequiredSamples);
199 if (max_delay_ms != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700200 RTC_LOGGED_HISTOGRAMS_COUNTS_100000(
201 kIndex, uma_prefix_ + "SendSideDelayMaxInMs", max_delay_ms);
sprangb4a1ae52015-12-03 08:10:08 -0800202 }
sprang07fb9be2016-02-24 07:55:00 -0800203
asapersson118ef002016-03-31 00:00:19 -0700204 for (const auto& it : qp_counters_) {
asapersson5265fed2016-04-18 02:58:47 -0700205 int qp_vp8 = it.second.vp8.Avg(kMinRequiredSamples);
206 if (qp_vp8 != -1) {
asapersson118ef002016-03-31 00:00:19 -0700207 int spatial_idx = it.first;
208 if (spatial_idx == -1) {
209 RTC_LOGGED_HISTOGRAMS_COUNTS_200(kIndex, uma_prefix_ + "Encoded.Qp.Vp8",
asapersson5265fed2016-04-18 02:58:47 -0700210 qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700211 } else if (spatial_idx == 0) {
asapersson5265fed2016-04-18 02:58:47 -0700212 RTC_LOGGED_HISTOGRAMS_COUNTS_200(
213 kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S0", qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700214 } else if (spatial_idx == 1) {
asapersson5265fed2016-04-18 02:58:47 -0700215 RTC_LOGGED_HISTOGRAMS_COUNTS_200(
216 kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S1", qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700217 } else if (spatial_idx == 2) {
asapersson5265fed2016-04-18 02:58:47 -0700218 RTC_LOGGED_HISTOGRAMS_COUNTS_200(
219 kIndex, uma_prefix_ + "Encoded.Qp.Vp8.S2", qp_vp8);
asapersson118ef002016-03-31 00:00:19 -0700220 } else {
221 LOG(LS_WARNING) << "QP stats not recorded for VP8 spatial idx "
222 << spatial_idx;
223 }
224 }
asapersson5265fed2016-04-18 02:58:47 -0700225 int qp_vp9 = it.second.vp9.Avg(kMinRequiredSamples);
226 if (qp_vp9 != -1) {
227 int spatial_idx = it.first;
228 if (spatial_idx == -1) {
229 RTC_LOGGED_HISTOGRAMS_COUNTS_500(kIndex, uma_prefix_ + "Encoded.Qp.Vp9",
230 qp_vp9);
231 } else if (spatial_idx == 0) {
232 RTC_LOGGED_HISTOGRAMS_COUNTS_500(
233 kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S0", qp_vp9);
234 } else if (spatial_idx == 1) {
235 RTC_LOGGED_HISTOGRAMS_COUNTS_500(
236 kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S1", qp_vp9);
237 } else if (spatial_idx == 2) {
238 RTC_LOGGED_HISTOGRAMS_COUNTS_500(
239 kIndex, uma_prefix_ + "Encoded.Qp.Vp9.S2", qp_vp9);
240 } else {
241 LOG(LS_WARNING) << "QP stats not recorded for VP9 spatial layer "
242 << spatial_idx;
243 }
244 }
asapersson118ef002016-03-31 00:00:19 -0700245 }
246
sprange2d83d62016-02-19 09:03:26 -0800247 if (first_rtcp_stats_time_ms_ != -1) {
sprang07fb9be2016-02-24 07:55:00 -0800248 int64_t elapsed_sec =
249 (clock_->TimeInMilliseconds() - first_rtcp_stats_time_ms_) / 1000;
250 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
251 int fraction_lost = report_block_stats_.FractionLostInPercent();
252 if (fraction_lost != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700253 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800254 kIndex, uma_prefix_ + "SentPacketsLostInPercent", fraction_lost);
255 }
256
257 // The RTCP packet type counters, delivered via the
258 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire
259 // life of the send stream and are not reset when switching content type.
260 // For the purpose of these statistics though, we want new counts when
261 // switching since we switch histogram name. On every reset of the
262 // UmaSamplesContainer, we save the initial state of the counters, so that
263 // we can calculate the delta here and aggregate over all ssrcs.
264 RtcpPacketTypeCounter counters;
265 for (uint32_t ssrc : config.rtp.ssrcs) {
266 auto kv = current_stats.substreams.find(ssrc);
267 if (kv == current_stats.substreams.end())
268 continue;
269
270 RtcpPacketTypeCounter stream_counters =
271 kv->second.rtcp_packet_type_counts;
272 kv = start_stats_.substreams.find(ssrc);
273 if (kv != start_stats_.substreams.end())
274 stream_counters.Subtract(kv->second.rtcp_packet_type_counts);
275
276 counters.Add(stream_counters);
277 }
asapersson58d992e2016-03-29 02:15:06 -0700278 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
279 kIndex, uma_prefix_ + "NackPacketsReceivedPerMinute",
280 counters.nack_packets * 60 / elapsed_sec);
281 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
282 kIndex, uma_prefix_ + "FirPacketsReceivedPerMinute",
283 counters.fir_packets * 60 / elapsed_sec);
284 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
285 kIndex, uma_prefix_ + "PliPacketsReceivedPerMinute",
286 counters.pli_packets * 60 / elapsed_sec);
sprang07fb9be2016-02-24 07:55:00 -0800287 if (counters.nack_requests > 0) {
asapersson58d992e2016-03-29 02:15:06 -0700288 RTC_LOGGED_HISTOGRAMS_PERCENTAGE(
sprang07fb9be2016-02-24 07:55:00 -0800289 kIndex, uma_prefix_ + "UniqueNackRequestsReceivedInPercent",
290 counters.UniqueNackRequestsInPercent());
291 }
sprange2d83d62016-02-19 09:03:26 -0800292 }
293 }
Erik Språng22c2b482016-03-01 09:40:42 +0100294
295 if (first_rtp_stats_time_ms_ != -1) {
296 int64_t elapsed_sec =
297 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000;
298 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) {
299 StreamDataCounters rtp;
300 StreamDataCounters rtx;
301 AccumulateRtpStats(current_stats, config, &rtp, &rtx);
302 StreamDataCounters start_rtp;
303 StreamDataCounters start_rtx;
304 AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx);
305 rtp.Subtract(start_rtp);
306 rtx.Subtract(start_rtx);
307 StreamDataCounters rtp_rtx = rtp;
308 rtp_rtx.Add(rtx);
309
asapersson58d992e2016-03-29 02:15:06 -0700310 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100311 kIndex, uma_prefix_ + "BitrateSentInKbps",
312 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
313 1000));
asapersson58d992e2016-03-29 02:15:06 -0700314 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100315 kIndex, uma_prefix_ + "MediaBitrateSentInKbps",
316 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000));
asapersson58d992e2016-03-29 02:15:06 -0700317 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100318 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps",
319 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec /
320 1000));
asapersson58d992e2016-03-29 02:15:06 -0700321 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100322 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps",
323 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 /
324 elapsed_sec / 1000));
325 if (!config.rtp.rtx.ssrcs.empty()) {
asapersson58d992e2016-03-29 02:15:06 -0700326 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
Erik Språng22c2b482016-03-01 09:40:42 +0100327 kIndex, uma_prefix_ + "RtxBitrateSentInKbps",
328 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec /
329 1000));
330 }
331 if (config.rtp.fec.red_payload_type != -1) {
asapersson58d992e2016-03-29 02:15:06 -0700332 RTC_LOGGED_HISTOGRAMS_COUNTS_10000(
333 kIndex, uma_prefix_ + "FecBitrateSentInKbps",
334 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec /
335 1000));
Erik Språng22c2b482016-03-01 09:40:42 +0100336 }
337 }
338 }
sprangb4a1ae52015-12-03 08:10:08 -0800339}
340
341void SendStatisticsProxy::SetContentType(
342 VideoEncoderConfig::ContentType content_type) {
343 rtc::CritScope lock(&crit_);
344 if (content_type_ != content_type) {
sprang07fb9be2016-02-24 07:55:00 -0800345 uma_container_->UpdateHistograms(config_, stats_);
346 uma_container_.reset(
347 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_));
sprangb4a1ae52015-12-03 08:10:08 -0800348 content_type_ = content_type;
asaperssonf040b232015-11-04 00:59:03 -0800349 }
Åsa Persson24b4eda2015-06-16 10:17:01 +0200350}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000351
perkj376b1922016-05-02 11:35:24 -0700352void SendStatisticsProxy::OnEncoderStatsUpdate(
353 uint32_t framerate,
354 uint32_t bitrate,
355 const std::string& encoder_name) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200356 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000357 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000358 stats_.media_bitrate_bps = bitrate;
perkj376b1922016-05-02 11:35:24 -0700359 stats_.encoder_implementation_name = encoder_name;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000360}
361
Peter Boströme4499152016-02-05 11:13:28 +0100362void SendStatisticsProxy::OnEncodedFrameTimeMeasured(
363 int encode_time_ms,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000364 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200365 rtc::CritScope lock(&crit_);
Peter Boströme4499152016-02-05 11:13:28 +0100366 uma_container_->encode_time_counter_.Add(encode_time_ms);
367 encode_time_.Apply(1.0f, encode_time_ms);
368 stats_.avg_encode_time_ms = round(encode_time_.filtered());
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000369 stats_.encode_usage_percent = metrics.encode_usage_percent;
370}
371
Peter Boström7083e112015-09-22 16:28:51 +0200372void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200373 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000374 stats_.suspended = is_suspended;
375}
376
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000377VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200378 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000379 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000380 stats_.input_frame_rate =
sprangb4a1ae52015-12-03 08:10:08 -0800381 round(uma_container_->input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000382 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000383}
384
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000385void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200386 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000387 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
388 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000389 it != stats_.substreams.end(); ++it) {
390 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200391 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
392 it->second.width = 0;
393 it->second.height = 0;
394 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000395 }
396}
397
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000398VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
399 uint32_t ssrc) {
400 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
401 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000402 if (it != stats_.substreams.end())
403 return &it->second;
404
405 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) ==
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000406 config_.rtp.ssrcs.end() &&
407 std::find(config_.rtp.rtx.ssrcs.begin(),
408 config_.rtp.rtx.ssrcs.end(),
409 ssrc) == config_.rtp.rtx.ssrcs.end()) {
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000410 return nullptr;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000411 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000412
413 return &stats_.substreams[ssrc]; // Insert new entry and return ptr.
414}
415
Peter Boström20f3f942015-05-15 11:33:39 +0200416void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
417 rtc::CritScope lock(&crit_);
418 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200419 if (!stats)
Peter Boström20f3f942015-05-15 11:33:39 +0200420 return;
421
422 stats->total_bitrate_bps = 0;
423 stats->retransmit_bitrate_bps = 0;
424 stats->height = 0;
425 stats->width = 0;
426}
427
perkjf5b2e512016-07-05 08:34:04 -0700428void SendStatisticsProxy::OnSetEncoderTargetRate(uint32_t bitrate_bps) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200429 rtc::CritScope lock(&crit_);
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000430 stats_.target_media_bitrate_bps = bitrate_bps;
431}
432
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000433void SendStatisticsProxy::OnSendEncodedImage(
434 const EncodedImage& encoded_image,
kjellander02b3d272016-04-20 05:05:54 -0700435 const CodecSpecificInfo* codec_info) {
436 size_t simulcast_idx = 0;
437
438 if (codec_info) {
439 if (codec_info->codecType == kVideoCodecVP8) {
440 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx;
441 } else if (codec_info->codecType == kVideoCodecGeneric) {
442 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx;
443 }
444 }
445
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000446 if (simulcast_idx >= config_.rtp.ssrcs.size()) {
447 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
448 << " >= " << config_.rtp.ssrcs.size() << ").";
449 return;
450 }
451 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx];
452
Peter Boströmf2f82832015-05-01 13:00:41 +0200453 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000454 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200455 if (!stats)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000456 return;
457
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000458 stats->width = encoded_image._encodedWidth;
459 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000460 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700461
sprangb4a1ae52015-12-03 08:10:08 -0800462 uma_container_->key_frame_counter_.Add(encoded_image._frameType ==
463 kVideoFrameKey);
asaperssondec5ebf2015-10-05 02:36:17 -0700464
asapersson17821db2015-12-14 02:08:12 -0800465 stats_.bw_limited_resolution =
466 encoded_image.adapt_reason_.quality_resolution_downscales > 0 ||
467 encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
468
asapersson4306fc72015-10-19 00:35:21 -0700469 if (encoded_image.adapt_reason_.quality_resolution_downscales != -1) {
470 bool downscaled =
471 encoded_image.adapt_reason_.quality_resolution_downscales > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800472 uma_container_->quality_limited_frame_counter_.Add(downscaled);
asapersson4306fc72015-10-19 00:35:21 -0700473 if (downscaled) {
sprangb4a1ae52015-12-03 08:10:08 -0800474 uma_container_->quality_downscales_counter_.Add(
asapersson4306fc72015-10-19 00:35:21 -0700475 encoded_image.adapt_reason_.quality_resolution_downscales);
476 }
477 }
asaperssonda535c42015-10-19 23:32:41 -0700478 if (encoded_image.adapt_reason_.bw_resolutions_disabled != -1) {
479 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0;
sprangb4a1ae52015-12-03 08:10:08 -0800480 uma_container_->bw_limited_frame_counter_.Add(bw_limited);
asaperssonda535c42015-10-19 23:32:41 -0700481 if (bw_limited) {
sprangb4a1ae52015-12-03 08:10:08 -0800482 uma_container_->bw_resolutions_disabled_counter_.Add(
483 encoded_image.adapt_reason_.bw_resolutions_disabled);
asaperssonda535c42015-10-19 23:32:41 -0700484 }
485 }
asapersson4306fc72015-10-19 00:35:21 -0700486
kjellander02b3d272016-04-20 05:05:54 -0700487 if (encoded_image.qp_ != -1 && codec_info) {
488 if (codec_info->codecType == kVideoCodecVP8) {
asapersson5265fed2016-04-18 02:58:47 -0700489 int spatial_idx = (config_.rtp.ssrcs.size() == 1)
490 ? -1
491 : static_cast<int>(simulcast_idx);
492 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_);
kjellander02b3d272016-04-20 05:05:54 -0700493 } else if (codec_info->codecType == kVideoCodecVP9) {
494 int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1)
495 ? -1
496 : codec_info->codecSpecific.VP9.spatial_idx;
asapersson5265fed2016-04-18 02:58:47 -0700497 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_);
498 }
asapersson118ef002016-03-31 00:00:19 -0700499 }
500
asaperssond89920b2015-07-22 06:52:00 -0700501 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
502 // different threads and there is no guarantee that one frame of all layers
503 // are encoded before the next start.
504 if (last_sent_frame_timestamp_ > 0 &&
505 encoded_image._timeStamp != last_sent_frame_timestamp_) {
sprangb4a1ae52015-12-03 08:10:08 -0800506 uma_container_->sent_frame_rate_tracker_.AddSamples(1);
507 uma_container_->sent_width_counter_.Add(
508 uma_container_->max_sent_width_per_timestamp_);
509 uma_container_->sent_height_counter_.Add(
510 uma_container_->max_sent_height_per_timestamp_);
511 uma_container_->max_sent_width_per_timestamp_ = 0;
512 uma_container_->max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200513 }
asaperssond89920b2015-07-22 06:52:00 -0700514 last_sent_frame_timestamp_ = encoded_image._timeStamp;
sprangb4a1ae52015-12-03 08:10:08 -0800515 uma_container_->max_sent_width_per_timestamp_ =
516 std::max(uma_container_->max_sent_width_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700517 static_cast<int>(encoded_image._encodedWidth));
sprangb4a1ae52015-12-03 08:10:08 -0800518 uma_container_->max_sent_height_per_timestamp_ =
519 std::max(uma_container_->max_sent_height_per_timestamp_,
asaperssond89920b2015-07-22 06:52:00 -0700520 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000521}
522
Per69b332d2016-06-02 15:45:42 +0200523int SendStatisticsProxy::GetSendFrameRate() const {
524 rtc::CritScope lock(&crit_);
525 return stats_.encode_frame_rate;
526}
527
asaperssond89920b2015-07-22 06:52:00 -0700528void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200529 rtc::CritScope lock(&crit_);
sprangb4a1ae52015-12-03 08:10:08 -0800530 uma_container_->input_frame_rate_tracker_.AddSamples(1);
531 uma_container_->input_width_counter_.Add(width);
532 uma_container_->input_height_counter_.Add(height);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000533}
534
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000535void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
536 uint32_t ssrc,
537 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200538 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000539 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200540 if (!stats)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000541 return;
542
543 stats->rtcp_packet_type_counts = packet_counter;
sprang07fb9be2016-02-24 07:55:00 -0800544 if (uma_container_->first_rtcp_stats_time_ms_ == -1)
545 uma_container_->first_rtcp_stats_time_ms_ = clock_->TimeInMilliseconds();
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000546}
547
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000548void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
549 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200550 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000551 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200552 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000553 return;
554
555 stats->rtcp_stats = statistics;
sprange2d83d62016-02-19 09:03:26 -0800556 uma_container_->report_block_stats_.Store(statistics, 0, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000557}
558
Peter Boströmd1d66ba2016-02-08 14:07:14 +0100559void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000560
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000561void SendStatisticsProxy::DataCountersUpdated(
562 const StreamDataCounters& counters,
563 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200564 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000565 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200566 RTC_DCHECK(stats) << "DataCountersUpdated reported for unknown ssrc: "
567 << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000568
569 stats->rtp_stats = counters;
Erik Språng22c2b482016-03-01 09:40:42 +0100570 if (uma_container_->first_rtp_stats_time_ms_ == -1)
571 uma_container_->first_rtp_stats_time_ms_ = clock_->TimeInMilliseconds();
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000572}
573
sprangcd349d92016-07-13 09:11:28 -0700574void SendStatisticsProxy::Notify(uint32_t total_bitrate_bps,
575 uint32_t retransmit_bitrate_bps,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000576 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200577 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000578 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200579 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000580 return;
581
sprangcd349d92016-07-13 09:11:28 -0700582 stats->total_bitrate_bps = total_bitrate_bps;
583 stats->retransmit_bitrate_bps = retransmit_bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000584}
585
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000586void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
587 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200588 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000589 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200590 if (!stats)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000591 return;
592
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000593 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000594}
595
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000596void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
597 int max_delay_ms,
598 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200599 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000600 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
Peter Boström74f6e9e2016-04-04 17:56:10 +0200601 if (!stats)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000602 return;
603 stats->avg_delay_ms = avg_delay_ms;
604 stats->max_delay_ms = max_delay_ms;
asaperssonf040b232015-11-04 00:59:03 -0800605
sprangb4a1ae52015-12-03 08:10:08 -0800606 uma_container_->delay_counter_.Add(avg_delay_ms);
607 uma_container_->max_delay_counter_.Add(max_delay_ms);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000608}
609
asaperssond89920b2015-07-22 06:52:00 -0700610void SendStatisticsProxy::SampleCounter::Add(int sample) {
611 sum += sample;
612 ++num_samples;
613}
614
615int SendStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
616 if (num_samples < min_required_samples || num_samples == 0)
617 return -1;
asaperssonda535c42015-10-19 23:32:41 -0700618 return (sum + (num_samples / 2)) / num_samples;
asaperssond89920b2015-07-22 06:52:00 -0700619}
620
asaperssondec5ebf2015-10-05 02:36:17 -0700621void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
622 if (sample)
623 ++sum;
624 ++num_samples;
625}
626
627int SendStatisticsProxy::BoolSampleCounter::Percent(
628 int min_required_samples) const {
629 return Fraction(min_required_samples, 100.0f);
630}
631
632int SendStatisticsProxy::BoolSampleCounter::Permille(
633 int min_required_samples) const {
634 return Fraction(min_required_samples, 1000.0f);
635}
636
637int SendStatisticsProxy::BoolSampleCounter::Fraction(
638 int min_required_samples, float multiplier) const {
639 if (num_samples < min_required_samples || num_samples == 0)
640 return -1;
641 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
642}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000643} // namespace webrtc