blob: 00edd065ced1afc3cd19db5bffed604c89f6a02f [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>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000014#include <map>
15
pbos@webrtc.org49096de2015-02-24 22:37:52 +000016#include "webrtc/base/checks.h"
17
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000018#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
pbos@webrtc.org273a4142014-12-01 15:23:21 +000019#include "webrtc/system_wrappers/interface/logging.h"
Åsa Persson24b4eda2015-06-16 10:17:01 +020020#include "webrtc/system_wrappers/interface/metrics.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000021
22namespace webrtc {
23
pbos@webrtc.org273a4142014-12-01 15:23:21 +000024const int SendStatisticsProxy::kStatsTimeoutMs = 5000;
25
26SendStatisticsProxy::SendStatisticsProxy(Clock* clock,
27 const VideoSendStream::Config& config)
asaperssond89920b2015-07-22 06:52:00 -070028 : clock_(clock),
29 config_(config),
Tim Psiaki63046262015-09-14 10:38:08 -070030 input_frame_rate_tracker_(100u, 10u),
31 sent_frame_rate_tracker_(100u, 10u),
asaperssond89920b2015-07-22 06:52:00 -070032 last_sent_frame_timestamp_(0),
33 max_sent_width_per_timestamp_(0),
34 max_sent_height_per_timestamp_(0) {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +000035}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000036
Åsa Persson24b4eda2015-06-16 10:17:01 +020037SendStatisticsProxy::~SendStatisticsProxy() {
38 UpdateHistograms();
39}
40
41void SendStatisticsProxy::UpdateHistograms() {
42 int input_fps =
Tim Psiaki63046262015-09-14 10:38:08 -070043 static_cast<int>(input_frame_rate_tracker_.ComputeTotalRate());
Åsa Persson24b4eda2015-06-16 10:17:01 +020044 if (input_fps > 0)
45 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.InputFramesPerSecond", input_fps);
asaperssond89920b2015-07-22 06:52:00 -070046 int sent_fps =
Tim Psiaki63046262015-09-14 10:38:08 -070047 static_cast<int>(sent_frame_rate_tracker_.ComputeTotalRate());
Åsa Persson24b4eda2015-06-16 10:17:01 +020048 if (sent_fps > 0)
49 RTC_HISTOGRAM_COUNTS_100("WebRTC.Video.SentFramesPerSecond", sent_fps);
asaperssond89920b2015-07-22 06:52:00 -070050
asapersson6718e972015-07-24 00:20:58 -070051 const int kMinRequiredSamples = 200;
asaperssond89920b2015-07-22 06:52:00 -070052 int in_width = input_width_counter_.Avg(kMinRequiredSamples);
53 int in_height = input_height_counter_.Avg(kMinRequiredSamples);
54 if (in_width != -1) {
55 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputWidthInPixels", in_width);
56 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.InputHeightInPixels", in_height);
57 }
58 int sent_width = sent_width_counter_.Avg(kMinRequiredSamples);
59 int sent_height = sent_height_counter_.Avg(kMinRequiredSamples);
60 if (sent_width != -1) {
61 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentWidthInPixels", sent_width);
62 RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.SentHeightInPixels", sent_height);
63 }
asapersson6718e972015-07-24 00:20:58 -070064 int encode_ms = encode_time_counter_.Avg(kMinRequiredSamples);
65 if (encode_ms != -1)
66 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.EncodeTimeInMs", encode_ms);
asaperssondec5ebf2015-10-05 02:36:17 -070067
68 int key_frames_permille = key_frame_counter_.Permille(kMinRequiredSamples);
69 if (key_frames_permille != -1) {
70 RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.KeyFramesSentInPermille",
71 key_frames_permille);
72 }
asapersson4306fc72015-10-19 00:35:21 -070073 int quality_limited =
74 quality_limited_frame_counter_.Percent(kMinRequiredSamples);
75 if (quality_limited != -1) {
76 RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.QualityLimitedResolutionInPercent",
77 quality_limited);
78 }
79 int downscales = quality_downscales_counter_.Avg(kMinRequiredSamples);
80 if (downscales != -1) {
81 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.QualityLimitedResolutionDownscales",
82 downscales, 20);
83 }
Åsa Persson24b4eda2015-06-16 10:17:01 +020084}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000085
Peter Boström7083e112015-09-22 16:28:51 +020086void SendStatisticsProxy::OnOutgoingRate(uint32_t framerate, uint32_t bitrate) {
Peter Boströmf2f82832015-05-01 13:00:41 +020087 rtc::CritScope lock(&crit_);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000088 stats_.encode_frame_rate = framerate;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +000089 stats_.media_bitrate_bps = bitrate;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000090}
91
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000092void SendStatisticsProxy::CpuOveruseMetricsUpdated(
93 const CpuOveruseMetrics& metrics) {
Peter Boströmf2f82832015-05-01 13:00:41 +020094 rtc::CritScope lock(&crit_);
asapersson6718e972015-07-24 00:20:58 -070095 // TODO(asapersson): Change to use OnEncodedFrame() for avg_encode_time_ms.
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +000096 stats_.avg_encode_time_ms = metrics.avg_encode_time_ms;
97 stats_.encode_usage_percent = metrics.encode_usage_percent;
98}
99
Peter Boström7083e112015-09-22 16:28:51 +0200100void SendStatisticsProxy::OnSuspendChange(bool is_suspended) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200101 rtc::CritScope lock(&crit_);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000102 stats_.suspended = is_suspended;
103}
104
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000105VideoSendStream::Stats SendStatisticsProxy::GetStats() {
Peter Boströmf2f82832015-05-01 13:00:41 +0200106 rtc::CritScope lock(&crit_);
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000107 PurgeOldStats();
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000108 stats_.input_frame_rate =
Tim Psiaki63046262015-09-14 10:38:08 -0700109 static_cast<int>(input_frame_rate_tracker_.ComputeRate());
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000110 return stats_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000111}
112
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000113void SendStatisticsProxy::PurgeOldStats() {
Peter Boström20f3f942015-05-15 11:33:39 +0200114 int64_t old_stats_ms = clock_->TimeInMilliseconds() - kStatsTimeoutMs;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000115 for (std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
116 stats_.substreams.begin();
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000117 it != stats_.substreams.end(); ++it) {
118 uint32_t ssrc = it->first;
Peter Boström20f3f942015-05-15 11:33:39 +0200119 if (update_times_[ssrc].resolution_update_ms <= old_stats_ms) {
120 it->second.width = 0;
121 it->second.height = 0;
122 }
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000123 }
124}
125
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000126VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry(
127 uint32_t ssrc) {
128 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
129 stats_.substreams.find(ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000130 if (it != stats_.substreams.end())
131 return &it->second;
132
133 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) ==
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000134 config_.rtp.ssrcs.end() &&
135 std::find(config_.rtp.rtx.ssrcs.begin(),
136 config_.rtp.rtx.ssrcs.end(),
137 ssrc) == config_.rtp.rtx.ssrcs.end()) {
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000138 return nullptr;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000139 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000140
141 return &stats_.substreams[ssrc]; // Insert new entry and return ptr.
142}
143
Peter Boström20f3f942015-05-15 11:33:39 +0200144void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) {
145 rtc::CritScope lock(&crit_);
146 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
147 if (stats == nullptr)
148 return;
149
150 stats->total_bitrate_bps = 0;
151 stats->retransmit_bitrate_bps = 0;
152 stats->height = 0;
153 stats->width = 0;
154}
155
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000156void SendStatisticsProxy::OnSetRates(uint32_t bitrate_bps, int framerate) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200157 rtc::CritScope lock(&crit_);
pbos@webrtc.org891d4832015-02-26 13:15:22 +0000158 stats_.target_media_bitrate_bps = bitrate_bps;
159}
160
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000161void SendStatisticsProxy::OnSendEncodedImage(
162 const EncodedImage& encoded_image,
163 const RTPVideoHeader* rtp_video_header) {
164 size_t simulcast_idx =
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000165 rtp_video_header != nullptr ? rtp_video_header->simulcastIdx : 0;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000166 if (simulcast_idx >= config_.rtp.ssrcs.size()) {
167 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx
168 << " >= " << config_.rtp.ssrcs.size() << ").";
169 return;
170 }
171 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx];
172
Peter Boströmf2f82832015-05-01 13:00:41 +0200173 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000174 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000175 if (stats == nullptr)
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000176 return;
177
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000178 stats->width = encoded_image._encodedWidth;
179 stats->height = encoded_image._encodedHeight;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000180 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds();
asaperssond89920b2015-07-22 06:52:00 -0700181
Peter Boström5d0379d2015-10-06 14:04:51 +0200182 key_frame_counter_.Add(encoded_image._frameType == kKeyFrame);
asaperssondec5ebf2015-10-05 02:36:17 -0700183
asapersson4306fc72015-10-19 00:35:21 -0700184 if (encoded_image.adapt_reason_.quality_resolution_downscales != -1) {
185 bool downscaled =
186 encoded_image.adapt_reason_.quality_resolution_downscales > 0;
187 quality_limited_frame_counter_.Add(downscaled);
188 if (downscaled) {
189 quality_downscales_counter_.Add(
190 encoded_image.adapt_reason_.quality_resolution_downscales);
191 }
192 }
193
asaperssond89920b2015-07-22 06:52:00 -0700194 // TODO(asapersson): This is incorrect if simulcast layers are encoded on
195 // different threads and there is no guarantee that one frame of all layers
196 // are encoded before the next start.
197 if (last_sent_frame_timestamp_ > 0 &&
198 encoded_image._timeStamp != last_sent_frame_timestamp_) {
Tim Psiaki63046262015-09-14 10:38:08 -0700199 sent_frame_rate_tracker_.AddSamples(1);
asaperssond89920b2015-07-22 06:52:00 -0700200 sent_width_counter_.Add(max_sent_width_per_timestamp_);
201 sent_height_counter_.Add(max_sent_height_per_timestamp_);
202 max_sent_width_per_timestamp_ = 0;
203 max_sent_height_per_timestamp_ = 0;
Åsa Persson24b4eda2015-06-16 10:17:01 +0200204 }
asaperssond89920b2015-07-22 06:52:00 -0700205 last_sent_frame_timestamp_ = encoded_image._timeStamp;
206 max_sent_width_per_timestamp_ =
207 std::max(max_sent_width_per_timestamp_,
208 static_cast<int>(encoded_image._encodedWidth));
209 max_sent_height_per_timestamp_ =
210 std::max(max_sent_height_per_timestamp_,
211 static_cast<int>(encoded_image._encodedHeight));
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000212}
213
asaperssond89920b2015-07-22 06:52:00 -0700214void SendStatisticsProxy::OnIncomingFrame(int width, int height) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200215 rtc::CritScope lock(&crit_);
Tim Psiaki63046262015-09-14 10:38:08 -0700216 input_frame_rate_tracker_.AddSamples(1);
asaperssond89920b2015-07-22 06:52:00 -0700217 input_width_counter_.Add(width);
218 input_height_counter_.Add(height);
perkj@webrtc.orgaf612d52015-03-18 09:51:05 +0000219}
220
asapersson6718e972015-07-24 00:20:58 -0700221void SendStatisticsProxy::OnEncodedFrame(int encode_time_ms) {
222 rtc::CritScope lock(&crit_);
223 encode_time_counter_.Add(encode_time_ms);
224}
225
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000226void SendStatisticsProxy::RtcpPacketTypesCounterUpdated(
227 uint32_t ssrc,
228 const RtcpPacketTypeCounter& packet_counter) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200229 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000230 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000231 if (stats == nullptr)
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000232 return;
233
234 stats->rtcp_packet_type_counts = packet_counter;
235}
236
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000237void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
238 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200239 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000240 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000241 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000242 return;
243
244 stats->rtcp_stats = statistics;
245}
246
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000247void SendStatisticsProxy::CNameChanged(const char* cname, uint32_t ssrc) {
248}
249
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000250void SendStatisticsProxy::DataCountersUpdated(
251 const StreamDataCounters& counters,
252 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200253 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000254 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
henrikg91d6ede2015-09-17 00:24:34 -0700255 RTC_DCHECK(stats != nullptr)
256 << "DataCountersUpdated reported for unknown ssrc: " << ssrc;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000257
258 stats->rtp_stats = counters;
259}
260
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000261void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
262 const BitrateStatistics& retransmit_stats,
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000263 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200264 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000265 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000266 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000267 return;
268
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000269 stats->total_bitrate_bps = total_stats.bitrate_bps;
270 stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000271}
272
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000273void SendStatisticsProxy::FrameCountUpdated(const FrameCounts& frame_counts,
274 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200275 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000276 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000277 if (stats == nullptr)
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000278 return;
279
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000280 stats->frame_counts = frame_counts;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000281}
282
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000283void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
284 int max_delay_ms,
285 uint32_t ssrc) {
Peter Boströmf2f82832015-05-01 13:00:41 +0200286 rtc::CritScope lock(&crit_);
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000287 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc);
pbos@webrtc.org2b4ce3a2015-03-23 13:12:24 +0000288 if (stats == nullptr)
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000289 return;
290 stats->avg_delay_ms = avg_delay_ms;
291 stats->max_delay_ms = max_delay_ms;
292}
293
asaperssond89920b2015-07-22 06:52:00 -0700294void SendStatisticsProxy::SampleCounter::Add(int sample) {
295 sum += sample;
296 ++num_samples;
297}
298
299int SendStatisticsProxy::SampleCounter::Avg(int min_required_samples) const {
300 if (num_samples < min_required_samples || num_samples == 0)
301 return -1;
302 return sum / num_samples;
303}
304
asaperssondec5ebf2015-10-05 02:36:17 -0700305void SendStatisticsProxy::BoolSampleCounter::Add(bool sample) {
306 if (sample)
307 ++sum;
308 ++num_samples;
309}
310
311int SendStatisticsProxy::BoolSampleCounter::Percent(
312 int min_required_samples) const {
313 return Fraction(min_required_samples, 100.0f);
314}
315
316int SendStatisticsProxy::BoolSampleCounter::Permille(
317 int min_required_samples) const {
318 return Fraction(min_required_samples, 1000.0f);
319}
320
321int SendStatisticsProxy::BoolSampleCounter::Fraction(
322 int min_required_samples, float multiplier) const {
323 if (num_samples < min_required_samples || num_samples == 0)
324 return -1;
325 return static_cast<int>((sum * multiplier / num_samples) + 0.5f);
326}
327
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000328} // namespace webrtc