blob: 928bc8b701b5855d03d896c446f73fe8f77cc856 [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
Steve Antonbd631a02019-03-28 10:51:27 -070013#include <algorithm>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000014#include <map>
kwiberg27f982b2016-03-01 11:52:33 -080015#include <memory>
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000016#include <string>
17#include <vector>
18
Steve Antonbd631a02019-03-28 10:51:27 -070019#include "absl/algorithm/container.h"
Henrik Boström23aff9b2019-05-20 15:15:38 +020020#include "api/units/timestamp.h"
21#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "system_wrappers/include/metrics.h"
asapersson8d75ac72017-09-15 06:41:15 -070023#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "test/gtest.h"
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000025
26namespace webrtc {
asapersson5265fed2016-04-18 02:58:47 -070027namespace {
28const uint32_t kFirstSsrc = 17;
29const uint32_t kSecondSsrc = 42;
30const uint32_t kFirstRtxSsrc = 18;
31const uint32_t kSecondRtxSsrc = 43;
asaperssona6a699a2016-11-25 03:52:46 -080032const uint32_t kFlexFecSsrc = 55;
asapersson320e45a2016-11-29 01:40:35 -080033const int kFpsPeriodicIntervalMs = 2000;
34const int kWidth = 640;
35const int kHeight = 480;
asapersson5265fed2016-04-18 02:58:47 -070036const int kQpIdx0 = 21;
37const int kQpIdx1 = 39;
Åsa Perssonaa329e72017-12-15 15:54:44 +010038const int kRtpClockRateHz = 90000;
kthelgason0cd27ba2016-12-19 06:32:16 -080039const CodecSpecificInfo kDefaultCodecInfo = []() {
40 CodecSpecificInfo codec_info;
41 codec_info.codecType = kVideoCodecVP8;
kthelgason0cd27ba2016-12-19 06:32:16 -080042 return codec_info;
43}();
asapersson5265fed2016-04-18 02:58:47 -070044} // namespace
sprang07fb9be2016-02-24 07:55:00 -080045
stefan@webrtc.org168f23f2014-07-11 13:44:02 +000046class SendStatisticsProxyTest : public ::testing::Test {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000047 public:
asapersson8d75ac72017-09-15 06:41:15 -070048 SendStatisticsProxyTest() : SendStatisticsProxyTest("") {}
49 explicit SendStatisticsProxyTest(const std::string& field_trials)
50 : override_field_trials_(field_trials),
51 fake_clock_(1234),
52 config_(GetTestConfig()),
53 avg_delay_ms_(0),
solenberg4fbae2b2015-08-28 04:07:10 -070054 max_delay_ms_(0) {}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000055 virtual ~SendStatisticsProxyTest() {}
56
57 protected:
58 virtual void SetUp() {
asapersson01d70a32016-05-20 06:29:46 -070059 metrics::Reset();
sprangb4a1ae52015-12-03 08:10:08 -080060 statistics_proxy_.reset(new SendStatisticsProxy(
61 &fake_clock_, GetTestConfig(),
62 VideoEncoderConfig::ContentType::kRealtimeVideo));
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000063 expected_ = VideoSendStream::Stats();
asapersson2e5cfcd2016-08-11 08:41:18 -070064 for (const auto& ssrc : config_.rtp.ssrcs)
65 expected_.substreams[ssrc].is_rtx = false;
66 for (const auto& ssrc : config_.rtp.rtx.ssrcs)
67 expected_.substreams[ssrc].is_rtx = true;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000068 }
69
70 VideoSendStream::Config GetTestConfig() {
solenberg4fbae2b2015-08-28 04:07:10 -070071 VideoSendStream::Config config(nullptr);
sprang07fb9be2016-02-24 07:55:00 -080072 config.rtp.ssrcs.push_back(kFirstSsrc);
73 config.rtp.ssrcs.push_back(kSecondSsrc);
74 config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
75 config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
brandtrb5f2c3f2016-10-04 23:28:39 -070076 config.rtp.ulpfec.red_payload_type = 17;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +000077 return config;
78 }
79
asaperssona6a699a2016-11-25 03:52:46 -080080 VideoSendStream::Config GetTestConfigWithFlexFec() {
81 VideoSendStream::Config config(nullptr);
82 config.rtp.ssrcs.push_back(kFirstSsrc);
83 config.rtp.ssrcs.push_back(kSecondSsrc);
84 config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
85 config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
brandtr3d200bd2017-01-16 06:59:19 -080086 config.rtp.flexfec.payload_type = 50;
87 config.rtp.flexfec.ssrc = kFlexFecSsrc;
asaperssona6a699a2016-11-25 03:52:46 -080088 return config;
89 }
90
91 VideoSendStream::StreamStats GetStreamStats(uint32_t ssrc) {
92 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
93 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
94 stats.substreams.find(ssrc);
95 EXPECT_NE(it, stats.substreams.end());
96 return it->second;
97 }
98
asapersson66d4b372016-12-19 06:50:53 -080099 void UpdateDataCounters(uint32_t ssrc) {
100 StreamDataCountersCallback* proxy =
101 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
102 StreamDataCounters counters;
103 proxy->DataCountersUpdated(counters, ssrc);
104 }
105
sprang@webrtc.org09315702014-02-07 12:06:29 +0000106 void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
sprang@webrtc.org09315702014-02-07 12:06:29 +0000107 EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
108 EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000109 EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000110 EXPECT_EQ(one.suspended, other.suspended);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000111
112 EXPECT_EQ(one.substreams.size(), other.substreams.size());
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000113 for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
sprang@webrtc.org09315702014-02-07 12:06:29 +0000114 one.substreams.begin();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000115 it != one.substreams.end(); ++it) {
116 std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
117 corresponding_it = other.substreams.find(it->first);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000118 ASSERT_TRUE(corresponding_it != other.substreams.end());
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000119 const VideoSendStream::StreamStats& a = it->second;
120 const VideoSendStream::StreamStats& b = corresponding_it->second;
sprang@webrtc.org09315702014-02-07 12:06:29 +0000121
asapersson2e5cfcd2016-08-11 08:41:18 -0700122 EXPECT_EQ(a.is_rtx, b.is_rtx);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000123 EXPECT_EQ(a.frame_counts.key_frames, b.frame_counts.key_frames);
124 EXPECT_EQ(a.frame_counts.delta_frames, b.frame_counts.delta_frames);
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000125 EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000126 EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
127 EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000128
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000129 EXPECT_EQ(a.rtp_stats.transmitted.payload_bytes,
130 b.rtp_stats.transmitted.payload_bytes);
131 EXPECT_EQ(a.rtp_stats.transmitted.header_bytes,
132 b.rtp_stats.transmitted.header_bytes);
133 EXPECT_EQ(a.rtp_stats.transmitted.padding_bytes,
134 b.rtp_stats.transmitted.padding_bytes);
135 EXPECT_EQ(a.rtp_stats.transmitted.packets,
136 b.rtp_stats.transmitted.packets);
137 EXPECT_EQ(a.rtp_stats.retransmitted.packets,
138 b.rtp_stats.retransmitted.packets);
139 EXPECT_EQ(a.rtp_stats.fec.packets, b.rtp_stats.fec.packets);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000140
141 EXPECT_EQ(a.rtcp_stats.fraction_lost, b.rtcp_stats.fraction_lost);
srte186d9c32017-08-04 05:03:53 -0700142 EXPECT_EQ(a.rtcp_stats.packets_lost, b.rtcp_stats.packets_lost);
143 EXPECT_EQ(a.rtcp_stats.extended_highest_sequence_number,
144 b.rtcp_stats.extended_highest_sequence_number);
sprang@webrtc.org09315702014-02-07 12:06:29 +0000145 EXPECT_EQ(a.rtcp_stats.jitter, b.rtcp_stats.jitter);
146 }
147 }
148
asapersson8d75ac72017-09-15 06:41:15 -0700149 test::ScopedFieldTrials override_field_trials_;
pbos@webrtc.org273a4142014-12-01 15:23:21 +0000150 SimulatedClock fake_clock_;
kwiberg27f982b2016-03-01 11:52:33 -0800151 std::unique_ptr<SendStatisticsProxy> statistics_proxy_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000152 VideoSendStream::Config config_;
153 int avg_delay_ms_;
154 int max_delay_ms_;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000155 VideoSendStream::Stats expected_;
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000156 typedef std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
157 StreamIterator;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000158};
159
160TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
161 RtcpStatisticsCallback* callback = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700162 for (const auto& ssrc : config_.rtp.ssrcs) {
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000163 VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000164
165 // Add statistics with some arbitrary, but unique, numbers.
166 uint32_t offset = ssrc * sizeof(RtcpStatistics);
srte186d9c32017-08-04 05:03:53 -0700167 ssrc_stats.rtcp_stats.packets_lost = offset;
168 ssrc_stats.rtcp_stats.extended_highest_sequence_number = offset + 1;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000169 ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
170 ssrc_stats.rtcp_stats.jitter = offset + 3;
171 callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
172 }
asapersson35151f32016-05-02 23:44:01 -0700173 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000174 VideoSendStream::StreamStats& ssrc_stats = expected_.substreams[ssrc];
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000175
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000176 // Add statistics with some arbitrary, but unique, numbers.
177 uint32_t offset = ssrc * sizeof(RtcpStatistics);
srte186d9c32017-08-04 05:03:53 -0700178 ssrc_stats.rtcp_stats.packets_lost = offset;
179 ssrc_stats.rtcp_stats.extended_highest_sequence_number = offset + 1;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000180 ssrc_stats.rtcp_stats.fraction_lost = offset + 2;
181 ssrc_stats.rtcp_stats.jitter = offset + 3;
182 callback->StatisticsUpdated(ssrc_stats.rtcp_stats, ssrc);
183 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000184 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000185 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000186}
187
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000188TEST_F(SendStatisticsProxyTest, Suspended) {
189 // Verify that the value is false by default.
190 EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
191
192 // Verify that we can set it to true.
Peter Boström7083e112015-09-22 16:28:51 +0200193 statistics_proxy_->OnSuspendChange(true);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000194 EXPECT_TRUE(statistics_proxy_->GetStats().suspended);
195
196 // Verify that we can set it back to false again.
Peter Boström7083e112015-09-22 16:28:51 +0200197 statistics_proxy_->OnSuspendChange(false);
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000198 EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
199}
200
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000201TEST_F(SendStatisticsProxyTest, FrameCounts) {
202 FrameCountObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700203 for (const auto& ssrc : config_.rtp.ssrcs) {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000204 // Add statistics with some arbitrary, but unique, numbers.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000205 VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
206 uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000207 FrameCounts frame_counts;
208 frame_counts.key_frames = offset;
209 frame_counts.delta_frames = offset + 1;
210 stats.frame_counts = frame_counts;
211 observer->FrameCountUpdated(frame_counts, ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000212 }
asapersson35151f32016-05-02 23:44:01 -0700213 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000214 // Add statistics with some arbitrary, but unique, numbers.
pbos@webrtc.org09c77b92015-02-25 10:42:16 +0000215 VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
216 uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000217 FrameCounts frame_counts;
218 frame_counts.key_frames = offset;
219 frame_counts.delta_frames = offset + 1;
220 stats.frame_counts = frame_counts;
221 observer->FrameCountUpdated(frame_counts, ssrc);
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000222 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000223
224 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000225 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000226}
227
228TEST_F(SendStatisticsProxyTest, DataCounters) {
229 StreamDataCountersCallback* callback = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700230 for (const auto& ssrc : config_.rtp.ssrcs) {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000231 StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
232 // Add statistics with some arbitrary, but unique, numbers.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000233 size_t offset = ssrc * sizeof(StreamDataCounters);
234 uint32_t offset_uint32 = static_cast<uint32_t>(offset);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000235 counters.transmitted.payload_bytes = offset;
236 counters.transmitted.header_bytes = offset + 1;
237 counters.fec.packets = offset_uint32 + 2;
238 counters.transmitted.padding_bytes = offset + 3;
239 counters.retransmitted.packets = offset_uint32 + 4;
240 counters.transmitted.packets = offset_uint32 + 5;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000241 callback->DataCountersUpdated(counters, ssrc);
242 }
asapersson35151f32016-05-02 23:44:01 -0700243 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000244 StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
245 // Add statistics with some arbitrary, but unique, numbers.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000246 size_t offset = ssrc * sizeof(StreamDataCounters);
247 uint32_t offset_uint32 = static_cast<uint32_t>(offset);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000248 counters.transmitted.payload_bytes = offset;
249 counters.transmitted.header_bytes = offset + 1;
250 counters.fec.packets = offset_uint32 + 2;
251 counters.transmitted.padding_bytes = offset + 3;
252 counters.retransmitted.packets = offset_uint32 + 4;
253 counters.transmitted.packets = offset_uint32 + 5;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000254 callback->DataCountersUpdated(counters, ssrc);
255 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000256
257 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000258 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000259}
260
261TEST_F(SendStatisticsProxyTest, Bitrate) {
262 BitrateStatisticsObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700263 for (const auto& ssrc : config_.rtp.ssrcs) {
sprangcd349d92016-07-13 09:11:28 -0700264 uint32_t total;
265 uint32_t retransmit;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000266 // Use ssrc as bitrate_bps to get a unique value for each stream.
sprangcd349d92016-07-13 09:11:28 -0700267 total = ssrc;
268 retransmit = ssrc + 1;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000269 observer->Notify(total, retransmit, ssrc);
sprangcd349d92016-07-13 09:11:28 -0700270 expected_.substreams[ssrc].total_bitrate_bps = total;
271 expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000272 }
asapersson35151f32016-05-02 23:44:01 -0700273 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
sprangcd349d92016-07-13 09:11:28 -0700274 uint32_t total;
275 uint32_t retransmit;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000276 // Use ssrc as bitrate_bps to get a unique value for each stream.
sprangcd349d92016-07-13 09:11:28 -0700277 total = ssrc;
278 retransmit = ssrc + 1;
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000279 observer->Notify(total, retransmit, ssrc);
sprangcd349d92016-07-13 09:11:28 -0700280 expected_.substreams[ssrc].total_bitrate_bps = total;
281 expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000282 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000283
284 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprang@webrtc.org09315702014-02-07 12:06:29 +0000285 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000286}
287
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000288TEST_F(SendStatisticsProxyTest, SendSideDelay) {
289 SendSideDelayObserver* observer = statistics_proxy_.get();
asapersson35151f32016-05-02 23:44:01 -0700290 for (const auto& ssrc : config_.rtp.ssrcs) {
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000291 // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
292 // stream.
293 int avg_delay_ms = ssrc;
294 int max_delay_ms = ssrc + 1;
Henrik Boström9fe18342019-05-16 18:38:20 +0200295 uint64_t total_packet_send_delay_ms = ssrc + 2;
296 observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms,
297 total_packet_send_delay_ms, ssrc);
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000298 expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
299 expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
Henrik Boström9fe18342019-05-16 18:38:20 +0200300 expected_.substreams[ssrc].total_packet_send_delay_ms =
301 total_packet_send_delay_ms;
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000302 }
asapersson35151f32016-05-02 23:44:01 -0700303 for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000304 // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
305 // stream.
306 int avg_delay_ms = ssrc;
307 int max_delay_ms = ssrc + 1;
Henrik Boström9fe18342019-05-16 18:38:20 +0200308 uint64_t total_packet_send_delay_ms = ssrc + 2;
309 observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms,
310 total_packet_send_delay_ms, ssrc);
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000311 expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
312 expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
Henrik Boström9fe18342019-05-16 18:38:20 +0200313 expected_.substreams[ssrc].total_packet_send_delay_ms =
314 total_packet_send_delay_ms;
stefan@webrtc.org58e2d262014-08-14 15:10:49 +0000315 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000316 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000317 ExpectEqual(expected_, stats);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000318}
319
Peter Boströme4499152016-02-05 11:13:28 +0100320TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) {
asapersson1aa420b2015-12-07 03:12:22 -0800321 const int kEncodeTimeMs = 11;
Niels Möller213618e2018-07-24 09:29:58 +0200322 int encode_usage_percent = 80;
323 statistics_proxy_->OnEncodedFrameTimeMeasured(kEncodeTimeMs,
324 encode_usage_percent);
asapersson1aa420b2015-12-07 03:12:22 -0800325
326 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
327 EXPECT_EQ(kEncodeTimeMs, stats.avg_encode_time_ms);
Niels Möller213618e2018-07-24 09:29:58 +0200328 EXPECT_EQ(encode_usage_percent, stats.encode_usage_percent);
asapersson1aa420b2015-12-07 03:12:22 -0800329}
330
Henrik Boström5684af52019-04-02 15:05:21 +0200331TEST_F(SendStatisticsProxyTest, TotalEncodeTimeIncreasesPerFrameMeasured) {
332 const int kEncodeUsagePercent = 0; // Don't care for this test.
333 EXPECT_EQ(0u, statistics_proxy_->GetStats().total_encode_time_ms);
334 statistics_proxy_->OnEncodedFrameTimeMeasured(10, kEncodeUsagePercent);
335 EXPECT_EQ(10u, statistics_proxy_->GetStats().total_encode_time_ms);
336 statistics_proxy_->OnEncodedFrameTimeMeasured(20, kEncodeUsagePercent);
337 EXPECT_EQ(30u, statistics_proxy_->GetStats().total_encode_time_ms);
338}
339
sakal43536c32016-10-24 01:46:43 -0700340TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) {
341 EncodedImage encoded_image;
342 CodecSpecificInfo codec_info;
343 EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_encoded);
344 for (uint32_t i = 1; i <= 3; ++i) {
345 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
346 EXPECT_EQ(i, statistics_proxy_->GetStats().frames_encoded);
347 }
348}
349
sakal87da4042016-10-31 06:53:47 -0700350TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesQpSum) {
351 EncodedImage encoded_image;
352 CodecSpecificInfo codec_info;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200353 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
sakal87da4042016-10-31 06:53:47 -0700354 encoded_image.qp_ = 3;
355 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100356 EXPECT_EQ(3u, statistics_proxy_->GetStats().qp_sum);
sakal87da4042016-10-31 06:53:47 -0700357 encoded_image.qp_ = 127;
358 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Oskar Sundbom8e07c132018-01-08 16:45:42 +0100359 EXPECT_EQ(130u, statistics_proxy_->GetStats().qp_sum);
sakal87da4042016-10-31 06:53:47 -0700360}
361
362TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
363 EncodedImage encoded_image;
364 CodecSpecificInfo codec_info;
365 encoded_image.qp_ = -1;
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200366 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
sakal87da4042016-10-31 06:53:47 -0700367 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200368 EXPECT_EQ(absl::nullopt, statistics_proxy_->GetStats().qp_sum);
sakal87da4042016-10-31 06:53:47 -0700369}
370
Henrik Boström23aff9b2019-05-20 15:15:38 +0200371TEST_F(SendStatisticsProxyTest, TotalEncodedBytesTargetFirstFrame) {
372 const uint32_t kTargetBytesPerSecond = 100000;
373 statistics_proxy_->OnSetEncoderTargetRate(kTargetBytesPerSecond * 8);
374 EXPECT_EQ(0u, statistics_proxy_->GetStats().total_encoded_bytes_target);
375
376 EncodedImage encoded_image;
377 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
378 // On the first frame we don't know the frame rate yet, calculation yields
379 // zero. Our estimate assumes at least 1 FPS, so we expect the frame size to
380 // increment by a full |kTargetBytesPerSecond|.
381 EXPECT_EQ(kTargetBytesPerSecond,
382 statistics_proxy_->GetStats().total_encoded_bytes_target);
383}
384
385TEST_F(SendStatisticsProxyTest,
386 TotalEncodedBytesTargetIncrementsBasedOnFrameRate) {
387 const uint32_t kTargetBytesPerSecond = 100000;
388 const int kInterframeDelayMs = 100;
389
390 // SendStatisticsProxy uses a RateTracker internally. SendStatisticsProxy uses
391 // |fake_clock_| for testing, but the RateTracker relies on a global clock.
392 // This test relies on rtc::ScopedFakeClock to synchronize these two clocks.
393 // TODO(https://crbug.com/webrtc/10640): When the RateTracker uses a Clock
394 // this test can stop relying on rtc::ScopedFakeClock.
395 rtc::ScopedFakeClock fake_global_clock;
396 fake_global_clock.SetTime(Timestamp::ms(fake_clock_.TimeInMilliseconds()));
397
398 statistics_proxy_->OnSetEncoderTargetRate(kTargetBytesPerSecond * 8);
399 EncodedImage encoded_image;
400
401 // First frame
402 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
403 uint64_t first_total_encoded_bytes_target =
404 statistics_proxy_->GetStats().total_encoded_bytes_target;
405 // Second frame
406 fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
407 fake_global_clock.SetTime(Timestamp::ms(fake_clock_.TimeInMilliseconds()));
408 encoded_image.SetTimestamp(encoded_image.Timestamp() +
409 90 * kInterframeDelayMs);
410 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
411
412 auto stats = statistics_proxy_->GetStats();
413 // By the time the second frame arrives, one frame has previously arrived
414 // during a |kInterframeDelayMs| interval. The estimated encode frame rate at
415 // the second frame's arrival should be 10 FPS.
416 uint64_t delta_encoded_bytes_target =
417 stats.total_encoded_bytes_target - first_total_encoded_bytes_target;
418 EXPECT_EQ(kTargetBytesPerSecond / 10, delta_encoded_bytes_target);
419}
420
asapersson09f05612017-05-15 23:40:18 -0700421TEST_F(SendStatisticsProxyTest, GetCpuAdaptationStats) {
Niels Möller213618e2018-07-24 09:29:58 +0200422 SendStatisticsProxy::AdaptationSteps cpu_counts;
423 SendStatisticsProxy::AdaptationSteps quality_counts;
asapersson09f05612017-05-15 23:40:18 -0700424 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
asapersson36e9eb42017-03-31 05:29:12 -0700425 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200426 cpu_counts.num_framerate_reductions = 1;
427 cpu_counts.num_resolution_reductions = 0;
428 statistics_proxy_->OnAdaptationChanged(
429 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
430 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700431 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
asapersson36e9eb42017-03-31 05:29:12 -0700432 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200433 cpu_counts.num_framerate_reductions = 0;
434 cpu_counts.num_resolution_reductions = 1;
435 statistics_proxy_->OnAdaptationChanged(
436 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
437 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700438 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
asapersson6eca98b2017-04-04 23:40:50 -0700439 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200440 cpu_counts.num_framerate_reductions = 1;
441 cpu_counts.num_resolution_reductions = absl::nullopt;
442 statistics_proxy_->OnAdaptationChanged(
443 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
444 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700445 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -0700446 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200447 cpu_counts.num_framerate_reductions = absl::nullopt;
448 cpu_counts.num_resolution_reductions = absl::nullopt;
449 statistics_proxy_->OnAdaptationChanged(
450 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
451 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700452 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
453 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
454}
455
456TEST_F(SendStatisticsProxyTest, GetQualityAdaptationStats) {
Niels Möller213618e2018-07-24 09:29:58 +0200457 SendStatisticsProxy::AdaptationSteps cpu_counts;
458 SendStatisticsProxy::AdaptationSteps quality_counts;
asapersson09f05612017-05-15 23:40:18 -0700459 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
460 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200461 quality_counts.num_framerate_reductions = 1;
462 quality_counts.num_resolution_reductions = 0;
463 statistics_proxy_->OnAdaptationChanged(
464 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
465 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700466 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
467 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200468 quality_counts.num_framerate_reductions = 0;
469 quality_counts.num_resolution_reductions = 1;
470 statistics_proxy_->OnAdaptationChanged(
471 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
472 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700473 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
474 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200475 quality_counts.num_framerate_reductions = 1;
476 quality_counts.num_resolution_reductions = absl::nullopt;
477 statistics_proxy_->OnAdaptationChanged(
478 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
479 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700480 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
481 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
Niels Möller213618e2018-07-24 09:29:58 +0200482 quality_counts.num_framerate_reductions = absl::nullopt;
483 quality_counts.num_resolution_reductions = absl::nullopt;
484 statistics_proxy_->OnAdaptationChanged(
485 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
486 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700487 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
488 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
489}
490
491TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuAdaptChanges) {
Niels Möller213618e2018-07-24 09:29:58 +0200492 SendStatisticsProxy::AdaptationSteps cpu_counts;
493 SendStatisticsProxy::AdaptationSteps quality_counts;
asaperssonfab67072017-04-04 05:51:49 -0700494 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
495
Niels Möller213618e2018-07-24 09:29:58 +0200496 cpu_counts.num_resolution_reductions = 1;
497 statistics_proxy_->OnAdaptationChanged(
498 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
499 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700500 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -0700501 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
502 EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
503
Niels Möller213618e2018-07-24 09:29:58 +0200504 cpu_counts.num_resolution_reductions = 2;
505 statistics_proxy_->OnAdaptationChanged(
506 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
507 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700508 EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
509 EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -0700510 EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
asapersson09f05612017-05-15 23:40:18 -0700511 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700512}
513
asapersson09f05612017-05-15 23:40:18 -0700514TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityAdaptChanges) {
Niels Möller213618e2018-07-24 09:29:58 +0200515 SendStatisticsProxy::AdaptationSteps cpu_counts;
516 SendStatisticsProxy::AdaptationSteps quality_counts;
asaperssonfab67072017-04-04 05:51:49 -0700517 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
518
Niels Möller213618e2018-07-24 09:29:58 +0200519 quality_counts.num_framerate_reductions = 1;
520 statistics_proxy_->OnAdaptationChanged(
521 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
522 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700523 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
524 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
asaperssonfab67072017-04-04 05:51:49 -0700525 EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
526
Niels Möller213618e2018-07-24 09:29:58 +0200527 quality_counts.num_framerate_reductions = 0;
528 statistics_proxy_->OnAdaptationChanged(
529 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
530 quality_counts);
asapersson09f05612017-05-15 23:40:18 -0700531 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
asaperssonfab67072017-04-04 05:51:49 -0700532 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
asapersson09f05612017-05-15 23:40:18 -0700533 EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
534 EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
asaperssonfab67072017-04-04 05:51:49 -0700535}
536
asapersson09f05612017-05-15 23:40:18 -0700537TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_AdaptationNotEnabled) {
asapersson0944a802017-04-07 00:57:58 -0700538 // First RTP packet sent.
539 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700540 // Min runtime has passed.
541 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
542 statistics_proxy_.reset();
543 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
544 EXPECT_EQ(0,
545 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
546}
547
548TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) {
asapersson0944a802017-04-07 00:57:58 -0700549 // First RTP packet sent.
550 UpdateDataCounters(kFirstSsrc);
asapersson09f05612017-05-15 23:40:18 -0700551 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200552 SendStatisticsProxy::AdaptationSteps cpu_counts;
553 SendStatisticsProxy::AdaptationSteps quality_counts;
554 statistics_proxy_->OnAdaptationChanged(
555 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
556 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700557 // Min runtime has not passed.
558 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
559 statistics_proxy_.reset();
560 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
561 EXPECT_EQ(0,
562 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
563}
564
asapersson09f05612017-05-15 23:40:18 -0700565TEST_F(SendStatisticsProxyTest, ZeroAdaptChangesReported) {
asapersson0944a802017-04-07 00:57:58 -0700566 // First RTP packet sent.
567 UpdateDataCounters(kFirstSsrc);
asapersson09f05612017-05-15 23:40:18 -0700568 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200569 SendStatisticsProxy::AdaptationSteps cpu_counts;
570 SendStatisticsProxy::AdaptationSteps quality_counts;
571 statistics_proxy_->OnAdaptationChanged(
572 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
573 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700574 // Min runtime has passed.
575 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
576 statistics_proxy_.reset();
577 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
578 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 0));
asapersson6eca98b2017-04-04 23:40:50 -0700579 EXPECT_EQ(1,
580 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
581 EXPECT_EQ(
582 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
583}
584
585TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) {
asapersson0944a802017-04-07 00:57:58 -0700586 // First RTP packet sent.
587 UpdateDataCounters(kFirstSsrc);
asapersson09f05612017-05-15 23:40:18 -0700588 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200589 SendStatisticsProxy::AdaptationSteps cpu_counts;
590 SendStatisticsProxy::AdaptationSteps quality_counts;
591 statistics_proxy_->OnAdaptationChanged(
592 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
593 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700594 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
Niels Möller213618e2018-07-24 09:29:58 +0200595 statistics_proxy_->OnAdaptationChanged(
596 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
597 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700598 fake_clock_.AdvanceTimeMilliseconds(10000);
599 statistics_proxy_.reset();
600 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
601 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
602}
603
Åsa Persson875841d2018-01-08 08:49:53 +0100604TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChange) {
605 // First RTP packet sent.
606 UpdateDataCounters(kFirstSsrc);
607 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200608 SendStatisticsProxy::AdaptationSteps cpu_counts;
609 SendStatisticsProxy::AdaptationSteps quality_counts;
610 statistics_proxy_->OnAdaptationChanged(
611 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
612 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100613 // Adapt changes: 1 (1 initial) = 0, elapsed time: 10 sec => 0 per minute.
Niels Möller213618e2018-07-24 09:29:58 +0200614 statistics_proxy_->OnAdaptationChanged(
615 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
616 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100617 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
618 fake_clock_.AdvanceTimeMilliseconds(10000);
619 statistics_proxy_.reset();
620 EXPECT_EQ(1,
621 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
622 EXPECT_EQ(
623 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
624}
625
626TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChanges) {
627 // First RTP packet sent.
628 UpdateDataCounters(kFirstSsrc);
629 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200630 SendStatisticsProxy::AdaptationSteps cpu_counts;
631 SendStatisticsProxy::AdaptationSteps quality_counts;
632 statistics_proxy_->OnAdaptationChanged(
633 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
634 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100635 // Adapt changes: 3 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
Niels Möller213618e2018-07-24 09:29:58 +0200636 quality_counts.num_resolution_reductions = 1;
637 statistics_proxy_->OnAdaptationChanged(
638 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
639 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100640 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
Niels Möller213618e2018-07-24 09:29:58 +0200641 quality_counts.num_resolution_reductions = 2;
642 statistics_proxy_->OnAdaptationChanged(
643 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
644 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100645 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
Niels Möller213618e2018-07-24 09:29:58 +0200646 quality_counts.num_resolution_reductions = 3;
647 statistics_proxy_->OnAdaptationChanged(
648 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
649 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100650 fake_clock_.AdvanceTimeMilliseconds(10000);
651 statistics_proxy_.reset();
652 EXPECT_EQ(1,
653 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
654 EXPECT_EQ(
655 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
656}
657
658TEST_F(SendStatisticsProxyTest, InitialQualityAdaptChangesNotExcludedOnError) {
659 // First RTP packet sent.
660 UpdateDataCounters(kFirstSsrc);
661 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200662 SendStatisticsProxy::AdaptationSteps cpu_counts;
663 SendStatisticsProxy::AdaptationSteps quality_counts;
664 statistics_proxy_->OnAdaptationChanged(
665 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
666 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100667 // Adapt changes: 1 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
Niels Möller213618e2018-07-24 09:29:58 +0200668 statistics_proxy_->OnAdaptationChanged(
669 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
670 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100671 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
672 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
673 fake_clock_.AdvanceTimeMilliseconds(10000);
674 statistics_proxy_.reset();
675 EXPECT_EQ(1,
676 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
677 EXPECT_EQ(
678 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
679}
680
681TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownAndUpChanges) {
682 // First RTP packet sent.
683 UpdateDataCounters(kFirstSsrc);
684 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200685 SendStatisticsProxy::AdaptationSteps cpu_counts;
686 SendStatisticsProxy::AdaptationSteps quality_counts;
687 statistics_proxy_->OnAdaptationChanged(
688 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
689 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100690 // Adapt changes: 8 (4 initial) = 4, elapsed time: 10 sec => 24 per minute.
Niels Möller213618e2018-07-24 09:29:58 +0200691 quality_counts.num_resolution_reductions = 1;
692 statistics_proxy_->OnAdaptationChanged(
693 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
694 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100695 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
Niels Möller213618e2018-07-24 09:29:58 +0200696 quality_counts.num_resolution_reductions = 2;
697 statistics_proxy_->OnAdaptationChanged(
698 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
699 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100700 statistics_proxy_->OnInitialQualityResolutionAdaptDown();
Niels Möller213618e2018-07-24 09:29:58 +0200701 quality_counts.num_resolution_reductions = 3;
702 statistics_proxy_->OnAdaptationChanged(
703 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
704 quality_counts);
705 quality_counts.num_framerate_reductions = 1;
706 statistics_proxy_->OnAdaptationChanged(
707 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
708 quality_counts);
709 quality_counts.num_framerate_reductions = 0;
710 statistics_proxy_->OnAdaptationChanged(
711 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
712 quality_counts);
713 quality_counts.num_resolution_reductions = 2; // Initial resolution up.
714 statistics_proxy_->OnAdaptationChanged(
715 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
716 quality_counts);
717 quality_counts.num_resolution_reductions = 1; // Initial resolution up.
718 statistics_proxy_->OnAdaptationChanged(
719 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
720 quality_counts);
721 quality_counts.num_resolution_reductions = 0;
722 statistics_proxy_->OnAdaptationChanged(
723 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
724 quality_counts);
Åsa Persson875841d2018-01-08 08:49:53 +0100725
726 fake_clock_.AdvanceTimeMilliseconds(10000);
727 statistics_proxy_.reset();
728 EXPECT_EQ(1,
729 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
730 EXPECT_EQ(
731 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 24));
732}
733
asapersson6eca98b2017-04-04 23:40:50 -0700734TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
asapersson0944a802017-04-07 00:57:58 -0700735 // First RTP packet sent.
736 UpdateDataCounters(kFirstSsrc);
737
asapersson09f05612017-05-15 23:40:18 -0700738 // Disable quality adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200739 SendStatisticsProxy::AdaptationSteps cpu_counts;
740 SendStatisticsProxy::AdaptationSteps quality_counts;
741 quality_counts.num_framerate_reductions = absl::nullopt;
742 quality_counts.num_resolution_reductions = absl::nullopt;
743 statistics_proxy_->OnAdaptationChanged(
744 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
745 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700746 fake_clock_.AdvanceTimeMilliseconds(10000);
747
asapersson09f05612017-05-15 23:40:18 -0700748 // Enable quality adaptation.
asapersson0944a802017-04-07 00:57:58 -0700749 // Adapt changes: 2, elapsed time: 20 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200750 quality_counts.num_framerate_reductions = 0;
751 statistics_proxy_->OnAdaptationChanged(
752 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
753 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700754 fake_clock_.AdvanceTimeMilliseconds(5000);
Niels Möller213618e2018-07-24 09:29:58 +0200755 statistics_proxy_->OnAdaptationChanged(
756 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
757 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700758 fake_clock_.AdvanceTimeMilliseconds(9000);
Niels Möller213618e2018-07-24 09:29:58 +0200759 statistics_proxy_->OnAdaptationChanged(
760 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
761 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700762 fake_clock_.AdvanceTimeMilliseconds(6000);
Niels Möller213618e2018-07-24 09:29:58 +0200763 statistics_proxy_->OnAdaptationChanged(
764 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
765 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700766
asapersson09f05612017-05-15 23:40:18 -0700767 // Disable quality adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200768 quality_counts.num_framerate_reductions = absl::nullopt;
769 statistics_proxy_->OnAdaptationChanged(
770 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
771 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700772 fake_clock_.AdvanceTimeMilliseconds(30000);
773
asapersson09f05612017-05-15 23:40:18 -0700774 // Enable quality adaptation.
asapersson0944a802017-04-07 00:57:58 -0700775 // Adapt changes: 1, elapsed time: 10 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200776 quality_counts.num_resolution_reductions = 0;
777 statistics_proxy_->OnAdaptationChanged(
778 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
779 quality_counts);
780 statistics_proxy_->OnAdaptationChanged(
781 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
782 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700783 fake_clock_.AdvanceTimeMilliseconds(10000);
784
asapersson09f05612017-05-15 23:40:18 -0700785 // Disable quality adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200786 quality_counts.num_resolution_reductions = absl::nullopt;
787 statistics_proxy_->OnAdaptationChanged(
788 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
789 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700790 fake_clock_.AdvanceTimeMilliseconds(5000);
Niels Möller213618e2018-07-24 09:29:58 +0200791 statistics_proxy_->OnAdaptationChanged(
792 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
793 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700794 fake_clock_.AdvanceTimeMilliseconds(20000);
795
asapersson0944a802017-04-07 00:57:58 -0700796 // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700797 statistics_proxy_.reset();
798 EXPECT_EQ(1,
799 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
800 EXPECT_EQ(
801 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
802}
803
asapersson0944a802017-04-07 00:57:58 -0700804TEST_F(SendStatisticsProxyTest,
805 AdaptChangesNotReported_ScalingNotEnabledVideoResumed) {
806 // First RTP packet sent.
807 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700808
asapersson0944a802017-04-07 00:57:58 -0700809 // Suspend and resume video.
810 statistics_proxy_->OnSuspendChange(true);
811 fake_clock_.AdvanceTimeMilliseconds(5000);
812 statistics_proxy_->OnSuspendChange(false);
813
814 // Min runtime has passed but scaling not enabled.
815 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
816 statistics_proxy_.reset();
817 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
818 EXPECT_EQ(0,
819 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
820}
821
822TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) {
823 // First RTP packet sent.
824 UpdateDataCounters(kFirstSsrc);
825
asapersson09f05612017-05-15 23:40:18 -0700826 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200827 SendStatisticsProxy::AdaptationSteps cpu_counts;
828 SendStatisticsProxy::AdaptationSteps quality_counts;
asapersson0944a802017-04-07 00:57:58 -0700829 // Adapt changes: 2, elapsed time: 20 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200830 statistics_proxy_->OnAdaptationChanged(
831 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
832 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700833 fake_clock_.AdvanceTimeMilliseconds(20000);
Niels Möller213618e2018-07-24 09:29:58 +0200834 statistics_proxy_->OnAdaptationChanged(
835 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
836 quality_counts);
837 statistics_proxy_->OnAdaptationChanged(
838 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
839 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700840
841 // Suspend and resume video.
842 statistics_proxy_->OnSuspendChange(true);
843 fake_clock_.AdvanceTimeMilliseconds(30000);
844 statistics_proxy_->OnSuspendChange(false);
845
846 // Adapt changes: 1, elapsed time: 10 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200847 statistics_proxy_->OnAdaptationChanged(
848 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
849 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700850 fake_clock_.AdvanceTimeMilliseconds(10000);
851
852 // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
853 statistics_proxy_.reset();
854 EXPECT_EQ(1,
855 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
856 EXPECT_EQ(
857 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
858}
859
860TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) {
861 // First RTP packet sent.
862 UpdateDataCounters(kFirstSsrc);
863
864 // Video not suspended.
865 statistics_proxy_->OnSuspendChange(false);
866 fake_clock_.AdvanceTimeMilliseconds(30000);
867
asapersson09f05612017-05-15 23:40:18 -0700868 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200869 SendStatisticsProxy::AdaptationSteps cpu_counts;
870 SendStatisticsProxy::AdaptationSteps quality_counts;
asapersson0944a802017-04-07 00:57:58 -0700871 // Adapt changes: 1, elapsed time: 20 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200872 statistics_proxy_->OnAdaptationChanged(
873 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
874 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700875 fake_clock_.AdvanceTimeMilliseconds(10000);
Niels Möller213618e2018-07-24 09:29:58 +0200876 statistics_proxy_->OnAdaptationChanged(
877 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
878 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700879
880 // Video not suspended, stats time already started.
881 statistics_proxy_->OnSuspendChange(false);
882 fake_clock_.AdvanceTimeMilliseconds(10000);
883
asapersson09f05612017-05-15 23:40:18 -0700884 // Disable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200885 cpu_counts.num_framerate_reductions = absl::nullopt;
886 cpu_counts.num_resolution_reductions = absl::nullopt;
887 statistics_proxy_->OnAdaptationChanged(
888 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
889 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700890 fake_clock_.AdvanceTimeMilliseconds(30000);
891
892 // Suspend and resume video, stats time not started when scaling not enabled.
893 statistics_proxy_->OnSuspendChange(true);
894 fake_clock_.AdvanceTimeMilliseconds(30000);
895 statistics_proxy_->OnSuspendChange(false);
896 fake_clock_.AdvanceTimeMilliseconds(30000);
897
asapersson09f05612017-05-15 23:40:18 -0700898 // Enable adaptation.
asapersson0944a802017-04-07 00:57:58 -0700899 // Adapt changes: 1, elapsed time: 10 sec.
Niels Möller213618e2018-07-24 09:29:58 +0200900 cpu_counts.num_framerate_reductions = 0;
901 cpu_counts.num_resolution_reductions = 0;
902 statistics_proxy_->OnAdaptationChanged(
903 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
904 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700905 fake_clock_.AdvanceTimeMilliseconds(10000);
Niels Möller213618e2018-07-24 09:29:58 +0200906 statistics_proxy_->OnAdaptationChanged(
907 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
908 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700909
910 // Adapt changes: 2, elapsed time: 30 sec => 4 per minute.
911 statistics_proxy_.reset();
912 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
913 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 4));
914}
915
916TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) {
917 // First RTP packet sent.
918 UpdateDataCounters(kFirstSsrc);
919
920 // Video suspended.
921 statistics_proxy_->OnSuspendChange(true);
922
asapersson09f05612017-05-15 23:40:18 -0700923 // Enable adaptation, stats time not started when suspended.
Niels Möller213618e2018-07-24 09:29:58 +0200924 SendStatisticsProxy::AdaptationSteps cpu_counts;
925 SendStatisticsProxy::AdaptationSteps quality_counts;
926 statistics_proxy_->OnAdaptationChanged(
927 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
928 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700929 fake_clock_.AdvanceTimeMilliseconds(10000);
930
931 // Resume video, stats time started.
932 // Adapt changes: 1, elapsed time: 10 sec.
933 statistics_proxy_->OnSuspendChange(false);
934 fake_clock_.AdvanceTimeMilliseconds(10000);
Niels Möller213618e2018-07-24 09:29:58 +0200935 statistics_proxy_->OnAdaptationChanged(
936 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
937 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700938
939 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
940 statistics_proxy_.reset();
941 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
942 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
943}
944
945TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) {
asapersson09f05612017-05-15 23:40:18 -0700946 // Send first packet, adaptation enabled.
asapersson6eca98b2017-04-04 23:40:50 -0700947 // Elapsed time before first packet is sent should be excluded.
Niels Möller213618e2018-07-24 09:29:58 +0200948 SendStatisticsProxy::AdaptationSteps cpu_counts;
949 SendStatisticsProxy::AdaptationSteps quality_counts;
950 statistics_proxy_->OnAdaptationChanged(
951 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
952 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700953 fake_clock_.AdvanceTimeMilliseconds(10000);
asapersson0944a802017-04-07 00:57:58 -0700954 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700955
asapersson0944a802017-04-07 00:57:58 -0700956 // Adapt changes: 1, elapsed time: 10 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700957 fake_clock_.AdvanceTimeMilliseconds(10000);
Niels Möller213618e2018-07-24 09:29:58 +0200958 statistics_proxy_->OnAdaptationChanged(
959 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
960 quality_counts);
asapersson0944a802017-04-07 00:57:58 -0700961 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700962
asapersson0944a802017-04-07 00:57:58 -0700963 // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
asapersson6eca98b2017-04-04 23:40:50 -0700964 statistics_proxy_.reset();
965 EXPECT_EQ(1,
966 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
967 EXPECT_EQ(
968 1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
969}
970
971TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
asapersson09f05612017-05-15 23:40:18 -0700972 // Enable and disable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200973 SendStatisticsProxy::AdaptationSteps cpu_counts;
974 SendStatisticsProxy::AdaptationSteps quality_counts;
975 statistics_proxy_->OnAdaptationChanged(
976 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
977 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700978 fake_clock_.AdvanceTimeMilliseconds(60000);
Niels Möller213618e2018-07-24 09:29:58 +0200979 cpu_counts.num_framerate_reductions = absl::nullopt;
980 cpu_counts.num_resolution_reductions = absl::nullopt;
981 statistics_proxy_->OnAdaptationChanged(
982 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
983 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700984
985 // Send first packet, scaling disabled.
986 // Elapsed time before first packet is sent should be excluded.
asapersson0944a802017-04-07 00:57:58 -0700987 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700988 fake_clock_.AdvanceTimeMilliseconds(60000);
989
asapersson09f05612017-05-15 23:40:18 -0700990 // Enable adaptation.
Niels Möller213618e2018-07-24 09:29:58 +0200991 cpu_counts.num_resolution_reductions = 0;
992 statistics_proxy_->OnAdaptationChanged(
993 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
994 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -0700995 fake_clock_.AdvanceTimeMilliseconds(10000);
asapersson0944a802017-04-07 00:57:58 -0700996 UpdateDataCounters(kFirstSsrc);
asapersson6eca98b2017-04-04 23:40:50 -0700997
asapersson0944a802017-04-07 00:57:58 -0700998 // Adapt changes: 1, elapsed time: 20 sec.
asapersson6eca98b2017-04-04 23:40:50 -0700999 fake_clock_.AdvanceTimeMilliseconds(10000);
Niels Möller213618e2018-07-24 09:29:58 +02001000 statistics_proxy_->OnAdaptationChanged(
1001 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1002 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001003
asapersson0944a802017-04-07 00:57:58 -07001004 // Adapt changes: 1, elapsed time: 20 sec => 3 per minute.
asapersson6eca98b2017-04-04 23:40:50 -07001005 statistics_proxy_.reset();
1006 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1007 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 3));
1008}
1009
1010TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
asapersson09f05612017-05-15 23:40:18 -07001011 // First RTP packet sent, cpu adaptation enabled.
asapersson0944a802017-04-07 00:57:58 -07001012 UpdateDataCounters(kFirstSsrc);
Niels Möller213618e2018-07-24 09:29:58 +02001013 SendStatisticsProxy::AdaptationSteps cpu_counts;
1014 SendStatisticsProxy::AdaptationSteps quality_counts;
1015 quality_counts.num_framerate_reductions = absl::nullopt;
1016 quality_counts.num_resolution_reductions = absl::nullopt;
1017 statistics_proxy_->OnAdaptationChanged(
1018 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1019 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001020
asapersson0944a802017-04-07 00:57:58 -07001021 // Adapt changes: 2, elapsed time: 15 sec => 8 per minute.
Niels Möller213618e2018-07-24 09:29:58 +02001022 statistics_proxy_->OnAdaptationChanged(
1023 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1024 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001025 fake_clock_.AdvanceTimeMilliseconds(6000);
Niels Möller213618e2018-07-24 09:29:58 +02001026 statistics_proxy_->OnAdaptationChanged(
1027 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1028 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001029 fake_clock_.AdvanceTimeMilliseconds(9000);
1030
1031 // Switch content type, real-time stats should be updated.
1032 VideoEncoderConfig config;
1033 config.content_type = VideoEncoderConfig::ContentType::kScreen;
Niels Möller97e04882018-05-25 09:43:26 +02001034 statistics_proxy_->OnEncoderReconfigured(config, {});
asapersson6eca98b2017-04-04 23:40:50 -07001035 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1036 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 8));
1037 EXPECT_EQ(0,
1038 metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
1039
asapersson0944a802017-04-07 00:57:58 -07001040 // First RTP packet sent, scaling enabled.
1041 UpdateDataCounters(kFirstSsrc);
Niels Möller213618e2018-07-24 09:29:58 +02001042 statistics_proxy_->OnAdaptationChanged(
1043 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1044 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001045
asapersson0944a802017-04-07 00:57:58 -07001046 // Adapt changes: 4, elapsed time: 120 sec => 2 per minute.
Niels Möller213618e2018-07-24 09:29:58 +02001047 statistics_proxy_->OnAdaptationChanged(
1048 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1049 quality_counts);
1050 statistics_proxy_->OnAdaptationChanged(
1051 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1052 quality_counts);
1053 statistics_proxy_->OnAdaptationChanged(
1054 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1055 quality_counts);
1056 statistics_proxy_->OnAdaptationChanged(
1057 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1058 quality_counts);
asapersson6eca98b2017-04-04 23:40:50 -07001059 fake_clock_.AdvanceTimeMilliseconds(120000);
1060
1061 statistics_proxy_.reset();
1062 EXPECT_EQ(1, metrics::NumSamples(
1063 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu"));
1064 EXPECT_EQ(1, metrics::NumEvents(
1065 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu", 2));
1066 EXPECT_EQ(0, metrics::NumSamples(
1067 "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Quality"));
1068}
1069
Henrik Boströmce33b6a2019-05-28 17:42:38 +02001070TEST_F(SendStatisticsProxyTest,
1071 QualityLimitationReasonIsCpuWhenCpuIsResolutionLimited) {
1072 SendStatisticsProxy::AdaptationSteps cpu_counts;
1073 SendStatisticsProxy::AdaptationSteps quality_counts;
1074
1075 cpu_counts.num_resolution_reductions = 1;
1076
1077 statistics_proxy_->OnAdaptationChanged(
1078 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1079 quality_counts);
1080
1081 EXPECT_EQ(QualityLimitationReason::kCpu,
1082 statistics_proxy_->GetStats().quality_limitation_reason);
1083}
1084
1085TEST_F(SendStatisticsProxyTest,
1086 QualityLimitationReasonIsCpuWhenCpuIsFramerateLimited) {
1087 SendStatisticsProxy::AdaptationSteps cpu_counts;
1088 SendStatisticsProxy::AdaptationSteps quality_counts;
1089
1090 cpu_counts.num_framerate_reductions = 1;
1091
1092 statistics_proxy_->OnAdaptationChanged(
1093 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1094 quality_counts);
1095
1096 EXPECT_EQ(QualityLimitationReason::kCpu,
1097 statistics_proxy_->GetStats().quality_limitation_reason);
1098}
1099
1100TEST_F(SendStatisticsProxyTest,
1101 QualityLimitationReasonIsBandwidthWhenQualityIsResolutionLimited) {
1102 SendStatisticsProxy::AdaptationSteps cpu_counts;
1103 SendStatisticsProxy::AdaptationSteps quality_counts;
1104
1105 quality_counts.num_resolution_reductions = 1;
1106
1107 statistics_proxy_->OnAdaptationChanged(
1108 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
1109 quality_counts);
1110
1111 EXPECT_EQ(QualityLimitationReason::kBandwidth,
1112 statistics_proxy_->GetStats().quality_limitation_reason);
1113}
1114
1115TEST_F(SendStatisticsProxyTest,
1116 QualityLimitationReasonIsBandwidthWhenQualityIsFramerateLimited) {
1117 SendStatisticsProxy::AdaptationSteps cpu_counts;
1118 SendStatisticsProxy::AdaptationSteps quality_counts;
1119
1120 quality_counts.num_framerate_reductions = 1;
1121
1122 statistics_proxy_->OnAdaptationChanged(
1123 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
1124 quality_counts);
1125
1126 EXPECT_EQ(QualityLimitationReason::kBandwidth,
1127 statistics_proxy_->GetStats().quality_limitation_reason);
1128}
1129
1130TEST_F(SendStatisticsProxyTest,
1131 QualityLimitationReasonIsBandwidthWhenBothCpuAndQualityIsLimited) {
1132 SendStatisticsProxy::AdaptationSteps cpu_counts;
1133 SendStatisticsProxy::AdaptationSteps quality_counts;
1134
1135 cpu_counts.num_resolution_reductions = 1;
1136 quality_counts.num_resolution_reductions = 1;
1137
1138 // Even if the last adaptation reason is kCpu, if the counters indicate being
1139 // both CPU and quality (=bandwidth) limited, kBandwidth takes precedence.
1140 statistics_proxy_->OnAdaptationChanged(
1141 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1142 quality_counts);
1143
1144 EXPECT_EQ(QualityLimitationReason::kBandwidth,
1145 statistics_proxy_->GetStats().quality_limitation_reason);
1146}
1147
1148TEST_F(SendStatisticsProxyTest, QualityLimitationReasonIsNoneWhenNotLimited) {
1149 SendStatisticsProxy::AdaptationSteps cpu_counts;
1150 SendStatisticsProxy::AdaptationSteps quality_counts;
1151
1152 // Observe a limitation due to CPU. This makes sure the test doesn't pass
1153 // due to "none" being the default value.
1154 cpu_counts.num_resolution_reductions = 1;
1155 statistics_proxy_->OnAdaptationChanged(
1156 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1157 quality_counts);
1158 // Go back to not being limited.
1159 cpu_counts.num_resolution_reductions = 0;
1160 statistics_proxy_->OnAdaptationChanged(
1161 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1162 quality_counts);
1163
1164 EXPECT_EQ(QualityLimitationReason::kNone,
1165 statistics_proxy_->GetStats().quality_limitation_reason);
1166}
1167
1168TEST_F(SendStatisticsProxyTest, QualityLimitationDurationIncreasesWithTime) {
1169 SendStatisticsProxy::AdaptationSteps cpu_counts;
1170 SendStatisticsProxy::AdaptationSteps quality_counts;
1171
1172 // Not limited for 3000 ms
1173 fake_clock_.AdvanceTimeMilliseconds(3000);
1174 // CPU limited for 2000 ms
1175 cpu_counts.num_resolution_reductions = 1;
1176 statistics_proxy_->OnAdaptationChanged(
1177 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1178 quality_counts);
1179 fake_clock_.AdvanceTimeMilliseconds(2000);
1180 // Bandwidth limited for 1000 ms
1181 cpu_counts.num_resolution_reductions = 0;
1182 quality_counts.num_resolution_reductions = 1;
1183 statistics_proxy_->OnAdaptationChanged(
1184 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
1185 quality_counts);
1186 fake_clock_.AdvanceTimeMilliseconds(1000);
1187 // CPU limited for another 2000 ms
1188 cpu_counts.num_resolution_reductions = 1;
1189 quality_counts.num_resolution_reductions = 0;
1190 statistics_proxy_->OnAdaptationChanged(
1191 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1192 quality_counts);
1193 fake_clock_.AdvanceTimeMilliseconds(2000);
1194
1195 auto quality_limitation_durations_ms =
1196 statistics_proxy_->GetStats().quality_limitation_durations_ms;
1197
1198 EXPECT_EQ(3000,
1199 quality_limitation_durations_ms[QualityLimitationReason::kNone]);
1200 EXPECT_EQ(4000,
1201 quality_limitation_durations_ms[QualityLimitationReason::kCpu]);
1202 EXPECT_EQ(
1203 1000,
1204 quality_limitation_durations_ms[QualityLimitationReason::kBandwidth]);
1205 EXPECT_EQ(0,
1206 quality_limitation_durations_ms[QualityLimitationReason::kOther]);
1207}
1208
asapersson59bac1a2016-01-07 23:36:00 -08001209TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
perkj803d97f2016-11-01 11:45:46 -07001210 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
asapersson59bac1a2016-01-07 23:36:00 -08001211 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1212
Pera48ddb72016-09-29 11:48:50 +02001213 // No switch, stats should not be updated.
1214 VideoEncoderConfig config;
1215 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
Niels Möller97e04882018-05-25 09:43:26 +02001216 statistics_proxy_->OnEncoderReconfigured(config, {});
asapersson01d70a32016-05-20 06:29:46 -07001217 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
asapersson59bac1a2016-01-07 23:36:00 -08001218
1219 // Switch to screenshare, real-time stats should be updated.
Pera48ddb72016-09-29 11:48:50 +02001220 config.content_type = VideoEncoderConfig::ContentType::kScreen;
Niels Möller97e04882018-05-25 09:43:26 +02001221 statistics_proxy_->OnEncoderReconfigured(config, {});
asapersson01d70a32016-05-20 06:29:46 -07001222 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
asapersson59bac1a2016-01-07 23:36:00 -08001223}
1224
asapersson320e45a2016-11-29 01:40:35 -08001225TEST_F(SendStatisticsProxyTest, InputResolutionHistogramsAreUpdated) {
1226 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1227 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
perkj803d97f2016-11-01 11:45:46 -07001228
asapersson320e45a2016-11-29 01:40:35 -08001229 statistics_proxy_.reset();
1230 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
1231 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputWidthInPixels", kWidth));
1232 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputHeightInPixels"));
1233 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputHeightInPixels", kHeight));
1234}
1235
1236TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) {
Åsa Persson0122e842017-10-16 12:19:23 +02001237 const int64_t kMaxEncodedFrameWindowMs = 800;
Åsa Persson20317f92018-08-15 08:57:54 +02001238 const int kFps = 5;
Åsa Persson0122e842017-10-16 12:19:23 +02001239 const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
1240 const int kMinSamples = // Sample added when removed from EncodedFrameMap.
1241 SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
asapersson320e45a2016-11-29 01:40:35 -08001242 EncodedImage encoded_image;
Åsa Persson0122e842017-10-16 12:19:23 +02001243
1244 // Not enough samples, stats should not be updated.
1245 for (int i = 0; i < kMinSamples - 1; ++i) {
1246 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001247 encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps);
asapersson320e45a2016-11-29 01:40:35 -08001248 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1249 }
Åsa Persson0122e842017-10-16 12:19:23 +02001250 SetUp(); // Reset stats proxy also causes histograms to be reported.
1251 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
1252 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
1253
1254 // Enough samples, max resolution per frame should be reported.
Niels Möller23775882018-08-16 10:24:12 +02001255 encoded_image.SetTimestamp(0xffff0000); // Will wrap.
Åsa Persson0122e842017-10-16 12:19:23 +02001256 for (int i = 0; i < kMinSamples; ++i) {
1257 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001258 encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps);
Åsa Persson0122e842017-10-16 12:19:23 +02001259 encoded_image._encodedWidth = kWidth;
1260 encoded_image._encodedHeight = kHeight;
1261 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1262 encoded_image._encodedWidth = kWidth / 2;
1263 encoded_image._encodedHeight = kHeight / 2;
1264 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1265 }
1266
asapersson320e45a2016-11-29 01:40:35 -08001267 statistics_proxy_.reset();
1268 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
1269 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentWidthInPixels", kWidth));
1270 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
1271 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentHeightInPixels", kHeight));
1272}
1273
1274TEST_F(SendStatisticsProxyTest, InputFpsHistogramIsUpdated) {
1275 const int kFps = 20;
1276 const int kMinPeriodicSamples = 6;
1277 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
1278 for (int i = 0; i <= frames; ++i) {
1279 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1280 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1281 }
1282 statistics_proxy_.reset();
1283 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
1284 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
1285}
1286
1287TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) {
1288 EncodedImage encoded_image;
1289 const int kFps = 20;
1290 const int kMinPeriodicSamples = 6;
1291 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1;
Åsa Persson0122e842017-10-16 12:19:23 +02001292 for (int i = 0; i < frames; ++i) {
asapersson320e45a2016-11-29 01:40:35 -08001293 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001294 encoded_image.SetTimestamp(encoded_image.Timestamp() + 1);
Åsa Persson0122e842017-10-16 12:19:23 +02001295 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1296 // Frame with same timestamp should not be counted.
asapersson320e45a2016-11-29 01:40:35 -08001297 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1298 }
1299 statistics_proxy_.reset();
1300 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
1301 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
1302}
1303
1304TEST_F(SendStatisticsProxyTest, InputFpsHistogramExcludesSuspendedTime) {
1305 const int kFps = 20;
1306 const int kSuspendTimeMs = 10000;
1307 const int kMinPeriodicSamples = 6;
1308 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
1309 for (int i = 0; i < frames; ++i) {
1310 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1311 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1312 }
1313 // Suspend.
1314 statistics_proxy_->OnSuspendChange(true);
1315 fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
1316
1317 for (int i = 0; i < frames; ++i) {
1318 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1319 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1320 }
1321 // Suspended time interval should not affect the framerate.
1322 statistics_proxy_.reset();
1323 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
1324 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
1325}
1326
1327TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) {
1328 EncodedImage encoded_image;
1329 const int kFps = 20;
1330 const int kSuspendTimeMs = 10000;
1331 const int kMinPeriodicSamples = 6;
1332 int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
Åsa Persson0122e842017-10-16 12:19:23 +02001333 for (int i = 0; i < frames; ++i) {
asapersson320e45a2016-11-29 01:40:35 -08001334 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001335 encoded_image.SetTimestamp(i + 1);
asapersson320e45a2016-11-29 01:40:35 -08001336 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1337 }
1338 // Suspend.
1339 statistics_proxy_->OnSuspendChange(true);
1340 fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
1341
Åsa Persson0122e842017-10-16 12:19:23 +02001342 for (int i = 0; i < frames; ++i) {
asapersson320e45a2016-11-29 01:40:35 -08001343 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001344 encoded_image.SetTimestamp(i + 1);
asapersson320e45a2016-11-29 01:40:35 -08001345 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1346 }
1347 // Suspended time interval should not affect the framerate.
1348 statistics_proxy_.reset();
1349 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
1350 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
1351}
1352
asaperssonf4e44af2017-04-19 02:01:06 -07001353TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) {
Niels Möller213618e2018-07-24 09:29:58 +02001354 SendStatisticsProxy::AdaptationSteps cpu_counts;
1355 SendStatisticsProxy::AdaptationSteps quality_counts;
1356 cpu_counts.num_resolution_reductions = absl::nullopt;
1357 statistics_proxy_->OnAdaptationChanged(
1358 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1359 quality_counts);
asaperssonf4e44af2017-04-19 02:01:06 -07001360
1361 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1362 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1363
1364 statistics_proxy_.reset();
1365 EXPECT_EQ(0,
1366 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1367}
1368
1369TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramUpdated) {
Niels Möller213618e2018-07-24 09:29:58 +02001370 SendStatisticsProxy::AdaptationSteps cpu_counts;
1371 SendStatisticsProxy::AdaptationSteps quality_counts;
1372 cpu_counts.num_resolution_reductions = 0;
1373 statistics_proxy_->OnAdaptationChanged(
1374 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1375 quality_counts);
asaperssonf4e44af2017-04-19 02:01:06 -07001376
perkj803d97f2016-11-01 11:45:46 -07001377 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1378 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1379
Niels Möller213618e2018-07-24 09:29:58 +02001380 cpu_counts.num_resolution_reductions = 1;
1381 statistics_proxy_->OnAdaptationChanged(
1382 VideoStreamEncoderObserver::AdaptationReason::kCpu, cpu_counts,
1383 quality_counts);
perkj803d97f2016-11-01 11:45:46 -07001384
1385 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1386 statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1387
1388 statistics_proxy_.reset();
1389 EXPECT_EQ(1,
1390 metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1391 EXPECT_EQ(
1392 1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1393}
1394
asapersson4374a092016-07-27 00:39:09 -07001395TEST_F(SendStatisticsProxyTest, LifetimeHistogramIsUpdated) {
1396 const int64_t kTimeSec = 3;
1397 fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
1398 statistics_proxy_.reset();
1399 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.SendStreamLifetimeInSeconds"));
1400 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.SendStreamLifetimeInSeconds",
1401 kTimeSec));
1402}
1403
1404TEST_F(SendStatisticsProxyTest, CodecTypeHistogramIsUpdated) {
1405 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1406 statistics_proxy_.reset();
1407 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoder.CodecType"));
1408}
1409
asapersson66d4b372016-12-19 06:50:53 -08001410TEST_F(SendStatisticsProxyTest, PauseEventHistogramIsUpdated) {
1411 // First RTP packet sent.
1412 UpdateDataCounters(kFirstSsrc);
1413
1414 // Min runtime has passed.
1415 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1416 statistics_proxy_.reset();
1417 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1418 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
1419}
1420
1421TEST_F(SendStatisticsProxyTest,
1422 PauseEventHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
1423 // First RTP packet sent.
1424 UpdateDataCounters(kFirstSsrc);
1425
1426 // Min runtime has not passed.
1427 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
1428 statistics_proxy_.reset();
1429 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1430 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1431}
1432
1433TEST_F(SendStatisticsProxyTest,
1434 PauseEventHistogramIsNotUpdatedIfNoMediaIsSent) {
1435 // First RTP packet not sent.
1436 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1437 statistics_proxy_.reset();
1438 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1439}
1440
1441TEST_F(SendStatisticsProxyTest, NoPauseEvent) {
1442 // First RTP packet sent and min runtime passed.
1443 UpdateDataCounters(kFirstSsrc);
1444
1445 // No change. Video: 10000 ms, paused: 0 ms (0%).
1446 statistics_proxy_->OnSetEncoderTargetRate(50000);
1447 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1448 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
1449
1450 statistics_proxy_.reset();
1451 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1452 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
1453 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1454 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 0));
1455}
1456
1457TEST_F(SendStatisticsProxyTest, OnePauseEvent) {
1458 // First RTP packet sent and min runtime passed.
1459 UpdateDataCounters(kFirstSsrc);
1460
1461 // One change. Video: 7000 ms, paused: 3000 ms (30%).
1462 statistics_proxy_->OnSetEncoderTargetRate(50000);
1463 fake_clock_.AdvanceTimeMilliseconds(7000);
1464 statistics_proxy_->OnSetEncoderTargetRate(0);
1465 fake_clock_.AdvanceTimeMilliseconds(3000);
1466 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
1467
1468 statistics_proxy_.reset();
1469 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1470 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 1));
1471 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1472 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 30));
1473}
1474
1475TEST_F(SendStatisticsProxyTest, TwoPauseEvents) {
1476 // First RTP packet sent.
1477 UpdateDataCounters(kFirstSsrc);
1478
1479 // Two changes. Video: 19000 ms, paused: 1000 ms (5%).
1480 statistics_proxy_->OnSetEncoderTargetRate(0);
1481 fake_clock_.AdvanceTimeMilliseconds(1000);
1482 statistics_proxy_->OnSetEncoderTargetRate(50000); // Starts on bitrate > 0.
1483 fake_clock_.AdvanceTimeMilliseconds(7000);
1484 statistics_proxy_->OnSetEncoderTargetRate(60000);
1485 fake_clock_.AdvanceTimeMilliseconds(3000);
1486 statistics_proxy_->OnSetEncoderTargetRate(0);
1487 fake_clock_.AdvanceTimeMilliseconds(250);
1488 statistics_proxy_->OnSetEncoderTargetRate(0);
1489 fake_clock_.AdvanceTimeMilliseconds(750);
1490 statistics_proxy_->OnSetEncoderTargetRate(60000);
1491 fake_clock_.AdvanceTimeMilliseconds(5000);
1492 statistics_proxy_->OnSetEncoderTargetRate(50000);
1493 fake_clock_.AdvanceTimeMilliseconds(4000);
1494 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
1495
1496 statistics_proxy_.reset();
1497 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1498 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 2));
1499 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1500 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 5));
1501}
1502
1503TEST_F(SendStatisticsProxyTest,
1504 PausedTimeHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
1505 // First RTP packet sent.
1506 UpdateDataCounters(kFirstSsrc);
1507 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1508
1509 // Min runtime has not passed.
1510 statistics_proxy_->OnSetEncoderTargetRate(50000);
1511 fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
1512 statistics_proxy_->OnSetEncoderTargetRate(0); // VideoSendStream::Stop
1513
1514 statistics_proxy_.reset();
1515 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1516}
1517
asapersson118ef002016-03-31 00:00:19 -07001518TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8) {
asapersson118ef002016-03-31 00:00:19 -07001519 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001520 CodecSpecificInfo codec_info;
1521 codec_info.codecType = kVideoCodecVP8;
asapersson118ef002016-03-31 00:00:19 -07001522
perkj803d97f2016-11-01 11:45:46 -07001523 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
Niels Möllerd3b8c632018-08-27 15:33:42 +02001524 encoded_image.SetSpatialIndex(0);
asapersson118ef002016-03-31 00:00:19 -07001525 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001526 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Niels Möllerd3b8c632018-08-27 15:33:42 +02001527 encoded_image.SetSpatialIndex(1);
asapersson118ef002016-03-31 00:00:19 -07001528 encoded_image.qp_ = kQpIdx1;
kjellander02b3d272016-04-20 05:05:54 -07001529 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson118ef002016-03-31 00:00:19 -07001530 }
1531 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001532 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S0"));
1533 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S0", kQpIdx0));
1534 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S1"));
1535 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S1", kQpIdx1));
asapersson118ef002016-03-31 00:00:19 -07001536}
1537
1538TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8OneSsrc) {
1539 VideoSendStream::Config config(nullptr);
1540 config.rtp.ssrcs.push_back(kFirstSsrc);
1541 statistics_proxy_.reset(new SendStatisticsProxy(
1542 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1543
asapersson118ef002016-03-31 00:00:19 -07001544 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001545 CodecSpecificInfo codec_info;
1546 codec_info.codecType = kVideoCodecVP8;
asapersson118ef002016-03-31 00:00:19 -07001547
perkj803d97f2016-11-01 11:45:46 -07001548 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
Niels Möllerd3b8c632018-08-27 15:33:42 +02001549 encoded_image.SetSpatialIndex(0);
asapersson118ef002016-03-31 00:00:19 -07001550 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001551 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson118ef002016-03-31 00:00:19 -07001552 }
1553 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001554 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8"));
1555 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8", kQpIdx0));
asapersson118ef002016-03-31 00:00:19 -07001556}
1557
asapersson5265fed2016-04-18 02:58:47 -07001558TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9) {
asapersson5265fed2016-04-18 02:58:47 -07001559 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001560 CodecSpecificInfo codec_info;
1561 codec_info.codecType = kVideoCodecVP9;
1562 codec_info.codecSpecific.VP9.num_spatial_layers = 2;
asapersson5265fed2016-04-18 02:58:47 -07001563
perkj803d97f2016-11-01 11:45:46 -07001564 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asapersson5265fed2016-04-18 02:58:47 -07001565 encoded_image.qp_ = kQpIdx0;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001566 encoded_image.SetSpatialIndex(0);
kjellander02b3d272016-04-20 05:05:54 -07001567 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001568 encoded_image.qp_ = kQpIdx1;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001569 encoded_image.SetSpatialIndex(1);
kjellander02b3d272016-04-20 05:05:54 -07001570 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001571 }
1572 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001573 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S0"));
1574 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S0", kQpIdx0));
1575 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S1"));
1576 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S1", kQpIdx1));
asapersson5265fed2016-04-18 02:58:47 -07001577}
1578
1579TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9OneSpatialLayer) {
1580 VideoSendStream::Config config(nullptr);
1581 config.rtp.ssrcs.push_back(kFirstSsrc);
1582 statistics_proxy_.reset(new SendStatisticsProxy(
1583 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
1584
asapersson5265fed2016-04-18 02:58:47 -07001585 EncodedImage encoded_image;
kjellander02b3d272016-04-20 05:05:54 -07001586 CodecSpecificInfo codec_info;
1587 codec_info.codecType = kVideoCodecVP9;
1588 codec_info.codecSpecific.VP9.num_spatial_layers = 1;
asapersson5265fed2016-04-18 02:58:47 -07001589
perkj803d97f2016-11-01 11:45:46 -07001590 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
asapersson5265fed2016-04-18 02:58:47 -07001591 encoded_image.qp_ = kQpIdx0;
kjellander02b3d272016-04-20 05:05:54 -07001592 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson5265fed2016-04-18 02:58:47 -07001593 }
1594 statistics_proxy_.reset();
asapersson01d70a32016-05-20 06:29:46 -07001595 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9"));
1596 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9", kQpIdx0));
asapersson5265fed2016-04-18 02:58:47 -07001597}
1598
asapersson827cab32016-11-02 09:08:47 -07001599TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_H264) {
1600 EncodedImage encoded_image;
1601 CodecSpecificInfo codec_info;
1602 codec_info.codecType = kVideoCodecH264;
1603
1604 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
Niels Möllerd3b8c632018-08-27 15:33:42 +02001605 encoded_image.SetSpatialIndex(0);
asapersson827cab32016-11-02 09:08:47 -07001606 encoded_image.qp_ = kQpIdx0;
1607 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Niels Möllerd3b8c632018-08-27 15:33:42 +02001608 encoded_image.SetSpatialIndex(1);
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +02001609 encoded_image.qp_ = kQpIdx1;
1610 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
asapersson827cab32016-11-02 09:08:47 -07001611 }
1612 statistics_proxy_.reset();
Sergio Garcia Murillo43800f92018-06-21 16:16:38 +02001613 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.H264.S0"));
1614 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.H264.S0", kQpIdx0));
1615 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.H264.S1"));
1616 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.H264.S1", kQpIdx1));
asapersson827cab32016-11-02 09:08:47 -07001617}
1618
asapersson4ee70462016-10-31 04:05:12 -07001619TEST_F(SendStatisticsProxyTest,
Åsa Perssonaa329e72017-12-15 15:54:44 +01001620 BandwidthLimitedHistogramsNotUpdatedForOneStream) {
1621 // Configure one stream.
1622 VideoEncoderConfig config;
1623 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1624 VideoStream stream1;
1625 stream1.width = kWidth;
1626 stream1.height = kHeight;
Niels Möller97e04882018-05-25 09:43:26 +02001627 statistics_proxy_->OnEncoderReconfigured(config, {stream1});
Åsa Perssonaa329e72017-12-15 15:54:44 +01001628
1629 const int64_t kMaxEncodedFrameWindowMs = 800;
1630 const int kFps = 20;
1631 const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
1632 const int kMinSamples = // Sample added when removed from EncodedFrameMap.
1633 SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
1634
1635 // Stream encoded.
asapersson4ee70462016-10-31 04:05:12 -07001636 EncodedImage encoded_image;
Åsa Perssonaa329e72017-12-15 15:54:44 +01001637 encoded_image._encodedWidth = kWidth;
1638 encoded_image._encodedHeight = kHeight;
1639 for (int i = 0; i < kMinSamples; ++i) {
1640 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001641 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1642 (kRtpClockRateHz / kFps));
asapersson4ee70462016-10-31 04:05:12 -07001643 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
Åsa Perssonaa329e72017-12-15 15:54:44 +01001644 }
asapersson4ee70462016-10-31 04:05:12 -07001645
1646 // Histograms are updated when the statistics_proxy_ is deleted.
1647 statistics_proxy_.reset();
1648 EXPECT_EQ(0, metrics::NumSamples(
1649 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1650 EXPECT_EQ(0, metrics::NumSamples(
1651 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
1652}
1653
1654TEST_F(SendStatisticsProxyTest,
Åsa Perssonaa329e72017-12-15 15:54:44 +01001655 BandwidthLimitedHistogramsUpdatedForTwoStreams_NoResolutionDisabled) {
1656 // Configure two streams.
1657 VideoEncoderConfig config;
1658 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1659 VideoStream stream1;
1660 stream1.width = kWidth / 2;
1661 stream1.height = kHeight / 2;
1662 VideoStream stream2;
1663 stream2.width = kWidth;
1664 stream2.height = kHeight;
Niels Möller97e04882018-05-25 09:43:26 +02001665 statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
Åsa Perssonaa329e72017-12-15 15:54:44 +01001666
1667 const int64_t kMaxEncodedFrameWindowMs = 800;
1668 const int kFps = 20;
1669 const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
1670 const int kMinSamples = // Sample added when removed from EncodedFrameMap.
1671 SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
1672
1673 // Two streams encoded.
asapersson4ee70462016-10-31 04:05:12 -07001674 EncodedImage encoded_image;
Åsa Perssonaa329e72017-12-15 15:54:44 +01001675 for (int i = 0; i < kMinSamples; ++i) {
1676 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001677 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1678 (kRtpClockRateHz / kFps));
Åsa Perssonaa329e72017-12-15 15:54:44 +01001679 encoded_image._encodedWidth = kWidth;
1680 encoded_image._encodedHeight = kHeight;
asapersson4ee70462016-10-31 04:05:12 -07001681 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
Åsa Perssonaa329e72017-12-15 15:54:44 +01001682 encoded_image._encodedWidth = kWidth / 2;
1683 encoded_image._encodedHeight = kHeight / 2;
1684 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1685 }
asapersson4ee70462016-10-31 04:05:12 -07001686
1687 // Histograms are updated when the statistics_proxy_ is deleted.
1688 statistics_proxy_.reset();
1689 EXPECT_EQ(1, metrics::NumSamples(
1690 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1691 EXPECT_EQ(1, metrics::NumEvents(
1692 "WebRTC.Video.BandwidthLimitedResolutionInPercent", 0));
1693 // No resolution disabled.
1694 EXPECT_EQ(0, metrics::NumSamples(
1695 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
1696}
1697
1698TEST_F(SendStatisticsProxyTest,
Åsa Perssonaa329e72017-12-15 15:54:44 +01001699 BandwidthLimitedHistogramsUpdatedForTwoStreams_OneResolutionDisabled) {
1700 // Configure two streams.
1701 VideoEncoderConfig config;
1702 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1703 VideoStream stream1;
1704 stream1.width = kWidth / 2;
1705 stream1.height = kHeight / 2;
1706 VideoStream stream2;
1707 stream2.width = kWidth;
1708 stream2.height = kHeight;
Niels Möller97e04882018-05-25 09:43:26 +02001709 statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
Åsa Perssonaa329e72017-12-15 15:54:44 +01001710
1711 const int64_t kMaxEncodedFrameWindowMs = 800;
1712 const int kFps = 20;
1713 const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
1714 const int kMinSamples = // Sample added when removed from EncodedFrameMap.
1715 SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
1716
1717 // One stream encoded.
asapersson4ee70462016-10-31 04:05:12 -07001718 EncodedImage encoded_image;
Åsa Perssonaa329e72017-12-15 15:54:44 +01001719 encoded_image._encodedWidth = kWidth / 2;
1720 encoded_image._encodedHeight = kHeight / 2;
1721 for (int i = 0; i < kMinSamples; ++i) {
1722 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001723 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1724 (kRtpClockRateHz / kFps));
asapersson4ee70462016-10-31 04:05:12 -07001725 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
Åsa Perssonaa329e72017-12-15 15:54:44 +01001726 }
asapersson4ee70462016-10-31 04:05:12 -07001727
1728 // Histograms are updated when the statistics_proxy_ is deleted.
1729 statistics_proxy_.reset();
1730 EXPECT_EQ(1, metrics::NumSamples(
1731 "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
1732 EXPECT_EQ(1, metrics::NumEvents(
1733 "WebRTC.Video.BandwidthLimitedResolutionInPercent", 100));
Åsa Perssonaa329e72017-12-15 15:54:44 +01001734 // One resolution disabled.
asapersson4ee70462016-10-31 04:05:12 -07001735 EXPECT_EQ(1, metrics::NumSamples(
1736 "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
Åsa Perssonaa329e72017-12-15 15:54:44 +01001737 EXPECT_EQ(1, metrics::NumEvents(
1738 "WebRTC.Video.BandwidthLimitedResolutionsDisabled", 1));
asapersson4ee70462016-10-31 04:05:12 -07001739}
1740
1741TEST_F(SendStatisticsProxyTest,
1742 QualityLimitedHistogramsNotUpdatedWhenDisabled) {
Niels Möller213618e2018-07-24 09:29:58 +02001743 SendStatisticsProxy::AdaptationSteps cpu_counts;
1744 SendStatisticsProxy::AdaptationSteps quality_counts;
1745 quality_counts.num_resolution_reductions = absl::nullopt;
1746 statistics_proxy_->OnAdaptationChanged(
1747 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1748 quality_counts);
asapersson4ee70462016-10-31 04:05:12 -07001749 EncodedImage encoded_image;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001750 encoded_image.SetSpatialIndex(0);
perkj803d97f2016-11-01 11:45:46 -07001751 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001752 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001753
1754 // Histograms are updated when the statistics_proxy_ is deleted.
1755 statistics_proxy_.reset();
1756 EXPECT_EQ(
1757 0, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1758 EXPECT_EQ(0, metrics::NumSamples(
1759 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1760}
1761
1762TEST_F(SendStatisticsProxyTest,
1763 QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale) {
Niels Möller213618e2018-07-24 09:29:58 +02001764 SendStatisticsProxy::AdaptationSteps cpu_counts;
1765 SendStatisticsProxy::AdaptationSteps quality_counts;
1766 quality_counts.num_resolution_reductions = 0;
1767 statistics_proxy_->OnAdaptationChanged(
1768 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1769 quality_counts);
asapersson4ee70462016-10-31 04:05:12 -07001770 EncodedImage encoded_image;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001771 encoded_image.SetSpatialIndex(0);
perkj803d97f2016-11-01 11:45:46 -07001772 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001773 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001774
1775 // Histograms are updated when the statistics_proxy_ is deleted.
1776 statistics_proxy_.reset();
1777 EXPECT_EQ(
1778 1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1779 EXPECT_EQ(1, metrics::NumEvents(
1780 "WebRTC.Video.QualityLimitedResolutionInPercent", 0));
1781 // No resolution downscale.
1782 EXPECT_EQ(0, metrics::NumSamples(
1783 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1784}
1785
1786TEST_F(SendStatisticsProxyTest,
1787 QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales) {
1788 const int kDownscales = 2;
Niels Möller213618e2018-07-24 09:29:58 +02001789 SendStatisticsProxy::AdaptationSteps cpu_counts;
1790 SendStatisticsProxy::AdaptationSteps quality_counts;
1791 quality_counts.num_resolution_reductions = kDownscales;
1792 statistics_proxy_->OnAdaptationChanged(
1793 VideoStreamEncoderObserver::AdaptationReason::kNone, cpu_counts,
1794 quality_counts);
asapersson4ee70462016-10-31 04:05:12 -07001795 EncodedImage encoded_image;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001796 encoded_image.SetSpatialIndex(0);
perkj803d97f2016-11-01 11:45:46 -07001797 for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
kthelgason0cd27ba2016-12-19 06:32:16 -08001798 statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
asapersson4ee70462016-10-31 04:05:12 -07001799 // Histograms are updated when the statistics_proxy_ is deleted.
1800 statistics_proxy_.reset();
1801 EXPECT_EQ(
1802 1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
1803 EXPECT_EQ(1, metrics::NumEvents(
1804 "WebRTC.Video.QualityLimitedResolutionInPercent", 100));
1805 // Resolution downscales.
1806 EXPECT_EQ(1, metrics::NumSamples(
1807 "WebRTC.Video.QualityLimitedResolutionDownscales"));
1808 EXPECT_EQ(
1809 1, metrics::NumEvents("WebRTC.Video.QualityLimitedResolutionDownscales",
1810 kDownscales));
1811}
1812
1813TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) {
1814 // Initially false.
1815 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
Åsa Persson59283e42017-12-12 14:14:42 +01001816
Åsa Perssonaa329e72017-12-15 15:54:44 +01001817 // Configure two streams.
1818 VideoEncoderConfig config;
1819 config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1820 VideoStream stream1;
1821 stream1.width = kWidth / 2;
1822 stream1.height = kHeight / 2;
1823 VideoStream stream2;
1824 stream2.width = kWidth;
1825 stream2.height = kHeight;
Niels Möller97e04882018-05-25 09:43:26 +02001826 statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
Åsa Perssonaa329e72017-12-15 15:54:44 +01001827
1828 const int64_t kMaxEncodedFrameWindowMs = 800;
1829 const int kFps = 20;
1830 const int kMinSamples = // Sample added when removed from EncodedFrameMap.
1831 kFps * kMaxEncodedFrameWindowMs / 1000;
1832
1833 // One stream encoded.
1834 EncodedImage encoded_image;
1835 encoded_image._encodedWidth = kWidth / 2;
1836 encoded_image._encodedHeight = kHeight / 2;
1837 for (int i = 0; i < kMinSamples; ++i) {
1838 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001839 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1840 (kRtpClockRateHz / kFps));
Åsa Perssonaa329e72017-12-15 15:54:44 +01001841 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1842 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1843 }
1844
1845 // First frame removed from EncodedFrameMap, stats updated.
1846 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001847 encoded_image.SetTimestamp(encoded_image.Timestamp() + 1);
kthelgason0cd27ba2016-12-19 06:32:16 -08001848 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1849 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1850
Åsa Perssonaa329e72017-12-15 15:54:44 +01001851 // Two streams encoded.
1852 for (int i = 0; i < kMinSamples; ++i) {
1853 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001854 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1855 (kRtpClockRateHz / kFps));
Åsa Perssonaa329e72017-12-15 15:54:44 +01001856 encoded_image._encodedWidth = kWidth;
1857 encoded_image._encodedHeight = kHeight;
1858 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1859 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1860 encoded_image._encodedWidth = kWidth / 2;
1861 encoded_image._encodedHeight = kHeight / 2;
1862 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1863 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1864 }
1865
1866 // First frame with two streams removed, expect no resolution limit.
1867 fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
Niels Möller23775882018-08-16 10:24:12 +02001868 encoded_image.SetTimestamp(encoded_image.Timestamp() +
1869 (kRtpClockRateHz / kFps));
asapersson4ee70462016-10-31 04:05:12 -07001870 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1871 EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
kthelgason0cd27ba2016-12-19 06:32:16 -08001872
1873 // Resolution scaled due to quality.
Niels Möller213618e2018-07-24 09:29:58 +02001874 SendStatisticsProxy::AdaptationSteps cpu_counts;
1875 SendStatisticsProxy::AdaptationSteps quality_counts;
1876 quality_counts.num_resolution_reductions = 1;
1877 statistics_proxy_->OnAdaptationChanged(
1878 VideoStreamEncoderObserver::AdaptationReason::kQuality, cpu_counts,
1879 quality_counts);
asapersson4ee70462016-10-31 04:05:12 -07001880 statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1881 EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1882}
1883
asapersson66d4b372016-12-19 06:50:53 -08001884TEST_F(SendStatisticsProxyTest, GetStatsReportsTargetMediaBitrate) {
1885 // Initially zero.
1886 EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
1887
1888 const int kBitrate = 100000;
1889 statistics_proxy_->OnSetEncoderTargetRate(kBitrate);
1890 EXPECT_EQ(kBitrate, statistics_proxy_->GetStats().target_media_bitrate_bps);
1891
1892 statistics_proxy_->OnSetEncoderTargetRate(0);
1893 EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
1894}
1895
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001896TEST_F(SendStatisticsProxyTest, NoSubstreams) {
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001897 uint32_t excluded_ssrc =
Steve Antonbd631a02019-03-28 10:51:27 -07001898 std::max(*absl::c_max_element(config_.rtp.ssrcs),
1899 *absl::c_max_element(config_.rtp.rtx.ssrcs)) +
stefan@webrtc.org58e2d262014-08-14 15:10:49 +00001900 1;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001901 // From RtcpStatisticsCallback.
1902 RtcpStatistics rtcp_stats;
1903 RtcpStatisticsCallback* rtcp_callback = statistics_proxy_.get();
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001904 rtcp_callback->StatisticsUpdated(rtcp_stats, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001905
1906 // From BitrateStatisticsObserver.
sprangcd349d92016-07-13 09:11:28 -07001907 uint32_t total = 0;
1908 uint32_t retransmit = 0;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001909 BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001910 bitrate_observer->Notify(total, retransmit, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001911
1912 // From FrameCountObserver.
1913 FrameCountObserver* fps_observer = statistics_proxy_.get();
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +00001914 FrameCounts frame_counts;
1915 frame_counts.key_frames = 1;
pbos@webrtc.org49096de2015-02-24 22:37:52 +00001916 fps_observer->FrameCountUpdated(frame_counts, excluded_ssrc);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001917
1918 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
1919 EXPECT_TRUE(stats.substreams.empty());
1920}
1921
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001922TEST_F(SendStatisticsProxyTest, EncodedResolutionTimesOut) {
1923 static const int kEncodedWidth = 123;
1924 static const int kEncodedHeight = 81;
1925 EncodedImage encoded_image;
1926 encoded_image._encodedWidth = kEncodedWidth;
1927 encoded_image._encodedHeight = kEncodedHeight;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001928 encoded_image.SetSpatialIndex(0);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001929
kjellander02b3d272016-04-20 05:05:54 -07001930 CodecSpecificInfo codec_info;
1931 codec_info.codecType = kVideoCodecVP8;
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001932
kjellander02b3d272016-04-20 05:05:54 -07001933 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Niels Möllerd3b8c632018-08-27 15:33:42 +02001934 encoded_image.SetSpatialIndex(1);
kjellander02b3d272016-04-20 05:05:54 -07001935 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001936
1937 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001938 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1939 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
1940 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
1941 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001942
1943 // Forward almost to timeout, this should not have removed stats.
1944 fake_clock_.AdvanceTimeMilliseconds(SendStatisticsProxy::kStatsTimeoutMs - 1);
1945 stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001946 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1947 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001948
1949 // Update the first SSRC with bogus RTCP stats to make sure that encoded
1950 // resolution still times out (no global timeout for all stats).
1951 RtcpStatistics rtcp_statistics;
1952 RtcpStatisticsCallback* rtcp_stats = statistics_proxy_.get();
1953 rtcp_stats->StatisticsUpdated(rtcp_statistics, config_.rtp.ssrcs[0]);
1954
1955 // Report stats for second SSRC to make sure it's not outdated along with the
1956 // first SSRC.
kjellander02b3d272016-04-20 05:05:54 -07001957 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001958
1959 // Forward 1 ms, reach timeout, substream 0 should have no resolution
1960 // reported, but substream 1 should.
1961 fake_clock_.AdvanceTimeMilliseconds(1);
1962 stats = statistics_proxy_->GetStats();
pbos@webrtc.org09c77b92015-02-25 10:42:16 +00001963 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].width);
1964 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].height);
1965 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
1966 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
pbos@webrtc.org273a4142014-12-01 15:23:21 +00001967}
1968
Peter Boström20f3f942015-05-15 11:33:39 +02001969TEST_F(SendStatisticsProxyTest, ClearsResolutionFromInactiveSsrcs) {
1970 static const int kEncodedWidth = 123;
1971 static const int kEncodedHeight = 81;
1972 EncodedImage encoded_image;
1973 encoded_image._encodedWidth = kEncodedWidth;
1974 encoded_image._encodedHeight = kEncodedHeight;
Niels Möllerd3b8c632018-08-27 15:33:42 +02001975 encoded_image.SetSpatialIndex(0);
Peter Boström20f3f942015-05-15 11:33:39 +02001976
kjellander02b3d272016-04-20 05:05:54 -07001977 CodecSpecificInfo codec_info;
1978 codec_info.codecType = kVideoCodecVP8;
Peter Boström20f3f942015-05-15 11:33:39 +02001979
kjellander02b3d272016-04-20 05:05:54 -07001980 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Niels Möllerd3b8c632018-08-27 15:33:42 +02001981 encoded_image.SetSpatialIndex(1);
kjellander02b3d272016-04-20 05:05:54 -07001982 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
Peter Boström20f3f942015-05-15 11:33:39 +02001983
1984 statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
1985 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
1986 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
1987 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
1988 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].width);
1989 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].height);
1990}
1991
1992TEST_F(SendStatisticsProxyTest, ClearsBitratesFromInactiveSsrcs) {
sprangcd349d92016-07-13 09:11:28 -07001993 uint32_t bitrate = 42;
Peter Boström20f3f942015-05-15 11:33:39 +02001994 BitrateStatisticsObserver* observer = statistics_proxy_.get();
1995 observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[0]);
1996 observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[1]);
1997
1998 statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
1999
2000 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
sprangcd349d92016-07-13 09:11:28 -07002001 EXPECT_EQ(static_cast<int>(bitrate),
Peter Boström20f3f942015-05-15 11:33:39 +02002002 stats.substreams[config_.rtp.ssrcs[0]].total_bitrate_bps);
sprangcd349d92016-07-13 09:11:28 -07002003 EXPECT_EQ(static_cast<int>(bitrate),
Peter Boström20f3f942015-05-15 11:33:39 +02002004 stats.substreams[config_.rtp.ssrcs[0]].retransmit_bitrate_bps);
2005 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].total_bitrate_bps);
2006 EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].retransmit_bitrate_bps);
2007}
2008
sprang07fb9be2016-02-24 07:55:00 -08002009TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) {
2010 RtcpPacketTypeCounterObserver* proxy =
2011 static_cast<RtcpPacketTypeCounterObserver*>(statistics_proxy_.get());
2012 RtcpPacketTypeCounter counters;
2013 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
2014 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2015 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2016
2017 fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
2018
2019 counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
2020 counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
2021 counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
2022 counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
2023 counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
2024
2025 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2026 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2027
2028 // Changing content type causes histograms to be reported.
Pera48ddb72016-09-29 11:48:50 +02002029 VideoEncoderConfig config;
2030 config.content_type = VideoEncoderConfig::ContentType::kScreen;
Niels Möller97e04882018-05-25 09:43:26 +02002031 statistics_proxy_->OnEncoderReconfigured(config, {});
sprang07fb9be2016-02-24 07:55:00 -08002032
asapersson01d70a32016-05-20 06:29:46 -07002033 EXPECT_EQ(1,
2034 metrics::NumSamples("WebRTC.Video.NackPacketsReceivedPerMinute"));
2035 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FirPacketsReceivedPerMinute"));
2036 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PliPacketsReceivedPerMinute"));
2037 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08002038 "WebRTC.Video.UniqueNackRequestsReceivedInPercent"));
2039
2040 const int kRate = 60 * 2; // Packets per minute with two streams.
2041
asapersson01d70a32016-05-20 06:29:46 -07002042 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.NackPacketsReceivedPerMinute",
2043 1 * kRate));
2044 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FirPacketsReceivedPerMinute",
2045 2 * kRate));
2046 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PliPacketsReceivedPerMinute",
2047 3 * kRate));
2048 EXPECT_EQ(
2049 1, metrics::NumEvents("WebRTC.Video.UniqueNackRequestsReceivedInPercent",
2050 4 * 100 / 5));
sprang07fb9be2016-02-24 07:55:00 -08002051
2052 // New start time but same counter values.
2053 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2054 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2055
2056 fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
2057
2058 counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
2059 counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
2060 counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
2061 counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
2062 counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
2063
2064 proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2065 proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2066
2067 SetUp(); // Reset stats proxy also causes histograms to be reported.
2068
asapersson01d70a32016-05-20 06:29:46 -07002069 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08002070 "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute"));
asapersson01d70a32016-05-20 06:29:46 -07002071 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08002072 "WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute"));
asapersson01d70a32016-05-20 06:29:46 -07002073 EXPECT_EQ(1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08002074 "WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute"));
2075 EXPECT_EQ(
asapersson01d70a32016-05-20 06:29:46 -07002076 1, metrics::NumSamples(
sprang07fb9be2016-02-24 07:55:00 -08002077 "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent"));
2078
asapersson01d70a32016-05-20 06:29:46 -07002079 EXPECT_EQ(1, metrics::NumEvents(
2080 "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute",
2081 1 * kRate));
2082 EXPECT_EQ(1, metrics::NumEvents(
2083 "WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute",
2084 2 * kRate));
2085 EXPECT_EQ(1, metrics::NumEvents(
2086 "WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute",
2087 3 * kRate));
2088 EXPECT_EQ(1,
2089 metrics::NumEvents(
2090 "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent",
2091 4 * 100 / 5));
sprang07fb9be2016-02-24 07:55:00 -08002092}
2093
asaperssona6a699a2016-11-25 03:52:46 -08002094TEST_F(SendStatisticsProxyTest, GetStatsReportsIsFlexFec) {
2095 statistics_proxy_.reset(
2096 new SendStatisticsProxy(&fake_clock_, GetTestConfigWithFlexFec(),
2097 VideoEncoderConfig::ContentType::kRealtimeVideo));
2098
2099 StreamDataCountersCallback* proxy =
2100 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2101 StreamDataCounters counters;
2102 proxy->DataCountersUpdated(counters, kFirstSsrc);
2103 proxy->DataCountersUpdated(counters, kFlexFecSsrc);
2104
2105 EXPECT_FALSE(GetStreamStats(kFirstSsrc).is_flexfec);
2106 EXPECT_TRUE(GetStreamStats(kFlexFecSsrc).is_flexfec);
2107}
2108
2109TEST_F(SendStatisticsProxyTest, SendBitratesAreReportedWithFlexFecEnabled) {
2110 statistics_proxy_.reset(
2111 new SendStatisticsProxy(&fake_clock_, GetTestConfigWithFlexFec(),
2112 VideoEncoderConfig::ContentType::kRealtimeVideo));
2113
2114 StreamDataCountersCallback* proxy =
2115 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
asaperssona6a699a2016-11-25 03:52:46 -08002116 StreamDataCounters counters;
2117 StreamDataCounters rtx_counters;
asaperssona6a699a2016-11-25 03:52:46 -08002118
asapersson93e1e232017-02-06 05:18:35 -08002119 const int kMinRequiredPeriodSamples = 8;
2120 const int kPeriodIntervalMs = 2000;
2121 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2122 counters.transmitted.packets += 20;
2123 counters.transmitted.header_bytes += 500;
2124 counters.transmitted.padding_bytes += 1000;
2125 counters.transmitted.payload_bytes += 2000;
2126 counters.retransmitted.packets += 2;
2127 counters.retransmitted.header_bytes += 25;
2128 counters.retransmitted.padding_bytes += 100;
2129 counters.retransmitted.payload_bytes += 250;
2130 counters.fec = counters.retransmitted;
2131 rtx_counters.transmitted = counters.transmitted;
2132 // Advance one interval and update counters.
2133 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2134 proxy->DataCountersUpdated(counters, kFirstSsrc);
2135 proxy->DataCountersUpdated(counters, kSecondSsrc);
2136 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2137 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2138 proxy->DataCountersUpdated(counters, kFlexFecSsrc);
2139 }
asaperssona6a699a2016-11-25 03:52:46 -08002140
asaperssona6a699a2016-11-25 03:52:46 -08002141 statistics_proxy_.reset();
asapersson93e1e232017-02-06 05:18:35 -08002142 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asaperssona6a699a2016-11-25 03:52:46 -08002143 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002144 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
2145 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
2146 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2147 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
2148 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asaperssona6a699a2016-11-25 03:52:46 -08002149 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002150 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
2151 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asaperssona6a699a2016-11-25 03:52:46 -08002152 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002153 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
2154 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2155 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2156 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
2157 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
asaperssona6a699a2016-11-25 03:52:46 -08002158 EXPECT_EQ(1,
2159 metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
asaperssona6a699a2016-11-25 03:52:46 -08002160 EXPECT_EQ(
asapersson93e1e232017-02-06 05:18:35 -08002161 1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
asaperssona6a699a2016-11-25 03:52:46 -08002162}
2163
Erik Språng22c2b482016-03-01 09:40:42 +01002164TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
2165 StreamDataCountersCallback* proxy =
2166 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2167 StreamDataCounters counters;
2168 StreamDataCounters rtx_counters;
2169 counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
Erik Språng22c2b482016-03-01 09:40:42 +01002170
asapersson93e1e232017-02-06 05:18:35 -08002171 const int kMinRequiredPeriodSamples = 8;
2172 const int kPeriodIntervalMs = 2000;
2173 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2174 counters.transmitted.packets += 20;
2175 counters.transmitted.header_bytes += 500;
2176 counters.transmitted.padding_bytes += 1000;
2177 counters.transmitted.payload_bytes += 2000;
2178 counters.retransmitted.packets += 2;
2179 counters.retransmitted.header_bytes += 25;
2180 counters.retransmitted.padding_bytes += 100;
2181 counters.retransmitted.payload_bytes += 250;
2182 counters.fec = counters.retransmitted;
2183 rtx_counters.transmitted = counters.transmitted;
2184 // Advance one interval and update counters.
2185 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2186 proxy->DataCountersUpdated(counters, kFirstSsrc);
2187 proxy->DataCountersUpdated(counters, kSecondSsrc);
2188 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2189 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2190 }
Erik Språng22c2b482016-03-01 09:40:42 +01002191
2192 // Changing content type causes histograms to be reported.
Pera48ddb72016-09-29 11:48:50 +02002193 VideoEncoderConfig config;
2194 config.content_type = VideoEncoderConfig::ContentType::kScreen;
Niels Möller97e04882018-05-25 09:43:26 +02002195 statistics_proxy_->OnEncoderReconfigured(config, {});
Erik Språng22c2b482016-03-01 09:40:42 +01002196
asapersson93e1e232017-02-06 05:18:35 -08002197 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asapersson01d70a32016-05-20 06:29:46 -07002198 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002199 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
2200 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
2201 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2202 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
2203 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asapersson01d70a32016-05-20 06:29:46 -07002204 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002205 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
2206 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asapersson01d70a32016-05-20 06:29:46 -07002207 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002208 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
2209 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2210 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2211 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
2212 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
Erik Språng22c2b482016-03-01 09:40:42 +01002213 EXPECT_EQ(1,
asapersson01d70a32016-05-20 06:29:46 -07002214 metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
Erik Språng22c2b482016-03-01 09:40:42 +01002215 EXPECT_EQ(
asapersson93e1e232017-02-06 05:18:35 -08002216 1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
Erik Språng22c2b482016-03-01 09:40:42 +01002217
asapersson93e1e232017-02-06 05:18:35 -08002218 // New metric counters but same data counters.
Erik Språng22c2b482016-03-01 09:40:42 +01002219 // Double counter values, this should result in the same counts as before but
2220 // with new histogram names.
asapersson93e1e232017-02-06 05:18:35 -08002221 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2222 counters.transmitted.packets += 20;
2223 counters.transmitted.header_bytes += 500;
2224 counters.transmitted.padding_bytes += 1000;
2225 counters.transmitted.payload_bytes += 2000;
2226 counters.retransmitted.packets += 2;
2227 counters.retransmitted.header_bytes += 25;
2228 counters.retransmitted.padding_bytes += 100;
2229 counters.retransmitted.payload_bytes += 250;
2230 counters.fec = counters.retransmitted;
2231 rtx_counters.transmitted = counters.transmitted;
2232 // Advance one interval and update counters.
2233 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2234 proxy->DataCountersUpdated(counters, kFirstSsrc);
2235 proxy->DataCountersUpdated(counters, kSecondSsrc);
2236 proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2237 proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2238 }
Erik Språng22c2b482016-03-01 09:40:42 +01002239
asapersson93e1e232017-02-06 05:18:35 -08002240 // Reset stats proxy also causes histograms to be reported.
2241 statistics_proxy_.reset();
Erik Språng22c2b482016-03-01 09:40:42 +01002242
asapersson93e1e232017-02-06 05:18:35 -08002243 // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec = 56 kbps
asapersson01d70a32016-05-20 06:29:46 -07002244 EXPECT_EQ(1,
2245 metrics::NumSamples("WebRTC.Video.Screenshare.BitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002246 EXPECT_EQ(
2247 1, metrics::NumEvents("WebRTC.Video.Screenshare.BitrateSentInKbps", 56));
2248 // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec = 28 kbps
2249 EXPECT_EQ(
2250 1, metrics::NumSamples("WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
2251 EXPECT_EQ(1, metrics::NumEvents(
2252 "WebRTC.Video.Screenshare.RtxBitrateSentInKbps", 28));
2253 // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec = 12 kbps
asapersson01d70a32016-05-20 06:29:46 -07002254 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01002255 "WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
asapersson01d70a32016-05-20 06:29:46 -07002256 EXPECT_EQ(1, metrics::NumEvents(
asapersson93e1e232017-02-06 05:18:35 -08002257 "WebRTC.Video.Screenshare.MediaBitrateSentInKbps", 12));
2258 // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
asapersson01d70a32016-05-20 06:29:46 -07002259 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01002260 "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
asapersson93e1e232017-02-06 05:18:35 -08002261 EXPECT_EQ(1, metrics::NumEvents(
2262 "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps", 16));
2263 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2264 EXPECT_EQ(
2265 1, metrics::NumSamples("WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
2266 EXPECT_EQ(1, metrics::NumEvents(
2267 "WebRTC.Video.Screenshare.FecBitrateSentInKbps", 3));
2268 // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
asapersson01d70a32016-05-20 06:29:46 -07002269 EXPECT_EQ(1, metrics::NumSamples(
Erik Språng22c2b482016-03-01 09:40:42 +01002270 "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
asapersson01d70a32016-05-20 06:29:46 -07002271 EXPECT_EQ(1,
2272 metrics::NumEvents(
asapersson93e1e232017-02-06 05:18:35 -08002273 "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps", 3));
2274}
Erik Språng22c2b482016-03-01 09:40:42 +01002275
asapersson93e1e232017-02-06 05:18:35 -08002276TEST_F(SendStatisticsProxyTest, RtxBitrateIsZeroWhenEnabledAndNoRtxDataIsSent) {
2277 StreamDataCountersCallback* proxy =
2278 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2279 StreamDataCounters counters;
2280 StreamDataCounters rtx_counters;
Erik Språng22c2b482016-03-01 09:40:42 +01002281
asapersson93e1e232017-02-06 05:18:35 -08002282 const int kMinRequiredPeriodSamples = 8;
2283 const int kPeriodIntervalMs = 2000;
2284 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2285 counters.transmitted.packets += 20;
2286 counters.transmitted.header_bytes += 500;
2287 counters.transmitted.payload_bytes += 2000;
2288 counters.fec = counters.retransmitted;
2289 // Advance one interval and update counters.
2290 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2291 proxy->DataCountersUpdated(counters, kFirstSsrc);
2292 }
2293
2294 // RTX enabled. No data sent over RTX.
2295 statistics_proxy_.reset();
2296 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2297 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 0));
2298}
2299
2300TEST_F(SendStatisticsProxyTest, RtxBitrateNotReportedWhenNotEnabled) {
2301 VideoSendStream::Config config(nullptr);
2302 config.rtp.ssrcs.push_back(kFirstSsrc); // RTX not configured.
2303 statistics_proxy_.reset(new SendStatisticsProxy(
2304 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
2305
2306 StreamDataCountersCallback* proxy =
2307 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2308 StreamDataCounters counters;
2309
2310 const int kMinRequiredPeriodSamples = 8;
2311 const int kPeriodIntervalMs = 2000;
2312 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2313 counters.transmitted.packets += 20;
2314 counters.transmitted.header_bytes += 500;
2315 counters.transmitted.payload_bytes += 2000;
2316 counters.fec = counters.retransmitted;
2317 // Advance one interval and update counters.
2318 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2319 proxy->DataCountersUpdated(counters, kFirstSsrc);
2320 }
2321
2322 // RTX not enabled.
2323 statistics_proxy_.reset();
2324 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2325}
2326
2327TEST_F(SendStatisticsProxyTest, FecBitrateIsZeroWhenEnabledAndNoFecDataIsSent) {
2328 StreamDataCountersCallback* proxy =
2329 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2330 StreamDataCounters counters;
2331 StreamDataCounters rtx_counters;
2332
2333 const int kMinRequiredPeriodSamples = 8;
2334 const int kPeriodIntervalMs = 2000;
2335 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2336 counters.transmitted.packets += 20;
2337 counters.transmitted.header_bytes += 500;
2338 counters.transmitted.payload_bytes += 2000;
2339 // Advance one interval and update counters.
2340 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2341 proxy->DataCountersUpdated(counters, kFirstSsrc);
2342 }
2343
2344 // FEC enabled. No FEC data sent.
2345 statistics_proxy_.reset();
2346 EXPECT_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2347 EXPECT_EQ(1, metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 0));
2348}
2349
2350TEST_F(SendStatisticsProxyTest, FecBitrateNotReportedWhenNotEnabled) {
2351 VideoSendStream::Config config(nullptr);
2352 config.rtp.ssrcs.push_back(kFirstSsrc); // FEC not configured.
2353 statistics_proxy_.reset(new SendStatisticsProxy(
2354 &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo));
2355
2356 StreamDataCountersCallback* proxy =
2357 static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2358 StreamDataCounters counters;
2359
2360 const int kMinRequiredPeriodSamples = 8;
2361 const int kPeriodIntervalMs = 2000;
2362 for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2363 counters.transmitted.packets += 20;
2364 counters.transmitted.header_bytes += 500;
2365 counters.transmitted.payload_bytes += 2000;
2366 counters.fec = counters.retransmitted;
2367 // Advance one interval and update counters.
2368 fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2369 proxy->DataCountersUpdated(counters, kFirstSsrc);
2370 }
2371
2372 // FEC not enabled.
2373 statistics_proxy_.reset();
2374 EXPECT_EQ(0, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
Erik Språng22c2b482016-03-01 09:40:42 +01002375}
2376
asapersson8d75ac72017-09-15 06:41:15 -07002377TEST_F(SendStatisticsProxyTest, GetStatsReportsEncoderImplementationName) {
Erik Språnge2fd86a2018-10-24 11:32:39 +02002378 const std::string kName = "encoderName";
2379 statistics_proxy_->OnEncoderImplementationChanged(kName);
2380 EXPECT_EQ(kName, statistics_proxy_->GetStats().encoder_implementation_name);
asapersson8d75ac72017-09-15 06:41:15 -07002381}
2382
Sergey Silkinbb081a62018-09-04 18:34:22 +02002383TEST_F(SendStatisticsProxyTest, Vp9SvcLowSpatialLayerDoesNotUpdateResolution) {
2384 static const int kEncodedWidth = 123;
2385 static const int kEncodedHeight = 81;
2386 EncodedImage encoded_image;
2387 encoded_image._encodedWidth = kEncodedWidth;
2388 encoded_image._encodedHeight = kEncodedHeight;
2389 encoded_image.SetSpatialIndex(0);
2390
2391 CodecSpecificInfo codec_info;
2392 codec_info.codecType = kVideoCodecVP9;
2393
2394 // For first picture, it is expected that low layer updates resolution.
2395 codec_info.codecSpecific.VP9.end_of_picture = false;
2396 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2397 VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2398 EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
2399 EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
2400
2401 // Top layer updates resolution.
2402 encoded_image._encodedWidth = kEncodedWidth * 2;
2403 encoded_image._encodedHeight = kEncodedHeight * 2;
2404 codec_info.codecSpecific.VP9.end_of_picture = true;
2405 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2406 stats = statistics_proxy_->GetStats();
2407 EXPECT_EQ(kEncodedWidth * 2, stats.substreams[config_.rtp.ssrcs[0]].width);
2408 EXPECT_EQ(kEncodedHeight * 2, stats.substreams[config_.rtp.ssrcs[0]].height);
2409
2410 // Low layer of next frame doesn't update resolution.
2411 encoded_image._encodedWidth = kEncodedWidth;
2412 encoded_image._encodedHeight = kEncodedHeight;
2413 codec_info.codecSpecific.VP9.end_of_picture = false;
2414 statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2415 stats = statistics_proxy_->GetStats();
2416 EXPECT_EQ(kEncodedWidth * 2, stats.substreams[config_.rtp.ssrcs[0]].width);
2417 EXPECT_EQ(kEncodedHeight * 2, stats.substreams[config_.rtp.ssrcs[0]].height);
2418}
2419
asapersson8d75ac72017-09-15 06:41:15 -07002420class ForcedFallbackTest : public SendStatisticsProxyTest {
2421 public:
2422 explicit ForcedFallbackTest(const std::string& field_trials)
2423 : SendStatisticsProxyTest(field_trials) {
2424 codec_info_.codecType = kVideoCodecVP8;
asapersson8d75ac72017-09-15 06:41:15 -07002425 codec_info_.codecSpecific.VP8.temporalIdx = 0;
Åsa Persson45bbc8a2017-11-13 10:16:47 +01002426 encoded_image_._encodedWidth = kWidth;
2427 encoded_image_._encodedHeight = kHeight;
Niels Möllerd3b8c632018-08-27 15:33:42 +02002428 encoded_image_.SetSpatialIndex(0);
asapersson8d75ac72017-09-15 06:41:15 -07002429 }
2430
2431 ~ForcedFallbackTest() override {}
2432
2433 protected:
2434 void InsertEncodedFrames(int num_frames, int interval_ms) {
Erik Språnge2fd86a2018-10-24 11:32:39 +02002435 statistics_proxy_->OnEncoderImplementationChanged(codec_name_);
2436
asapersson8d75ac72017-09-15 06:41:15 -07002437 // First frame is not updating stats, insert initial frame.
2438 if (statistics_proxy_->GetStats().frames_encoded == 0) {
2439 statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2440 }
2441 for (int i = 0; i < num_frames; ++i) {
2442 statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2443 fake_clock_.AdvanceTimeMilliseconds(interval_ms);
2444 }
2445 // Add frame to include last time interval.
2446 statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2447 }
2448
2449 EncodedImage encoded_image_;
2450 CodecSpecificInfo codec_info_;
Erik Språnge2fd86a2018-10-24 11:32:39 +02002451 std::string codec_name_;
asapersson8d75ac72017-09-15 06:41:15 -07002452 const std::string kPrefix = "WebRTC.Video.Encoder.ForcedSw";
2453 const int kFrameIntervalMs = 1000;
2454 const int kMinFrames = 20; // Min run time 20 sec.
2455};
2456
2457class ForcedFallbackDisabled : public ForcedFallbackTest {
2458 public:
2459 ForcedFallbackDisabled()
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002460 : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled-1," +
2461 std::to_string(kWidth * kHeight) + ",3/") {}
asapersson8d75ac72017-09-15 06:41:15 -07002462};
2463
2464class ForcedFallbackEnabled : public ForcedFallbackTest {
2465 public:
2466 ForcedFallbackEnabled()
Åsa Persson45bbc8a2017-11-13 10:16:47 +01002467 : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled-1," +
2468 std::to_string(kWidth * kHeight) + ",3/") {}
asapersson8d75ac72017-09-15 06:41:15 -07002469};
2470
2471TEST_F(ForcedFallbackEnabled, StatsNotUpdatedIfMinRunTimeHasNotPassed) {
2472 InsertEncodedFrames(kMinFrames, kFrameIntervalMs - 1);
2473 statistics_proxy_.reset();
2474 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2475 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2476}
2477
2478TEST_F(ForcedFallbackEnabled, StatsUpdated) {
2479 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002480 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002481 statistics_proxy_.reset();
2482 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2483 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 0));
2484 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2485 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 0));
2486}
2487
2488TEST_F(ForcedFallbackEnabled, StatsNotUpdatedIfNotVp8) {
2489 codec_info_.codecType = kVideoCodecVP9;
2490 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2491 statistics_proxy_.reset();
2492 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2493 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2494}
2495
2496TEST_F(ForcedFallbackEnabled, StatsNotUpdatedForTemporalLayers) {
2497 codec_info_.codecSpecific.VP8.temporalIdx = 1;
2498 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2499 statistics_proxy_.reset();
2500 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2501 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2502}
2503
2504TEST_F(ForcedFallbackEnabled, StatsNotUpdatedForSimulcast) {
Niels Möllerd3b8c632018-08-27 15:33:42 +02002505 encoded_image_.SetSpatialIndex(1);
asapersson8d75ac72017-09-15 06:41:15 -07002506 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2507 statistics_proxy_.reset();
2508 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2509 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2510}
2511
2512TEST_F(ForcedFallbackDisabled, StatsNotUpdatedIfNoFieldTrial) {
2513 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2514 statistics_proxy_.reset();
2515 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2516 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2517}
2518
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002519TEST_F(ForcedFallbackDisabled, EnteredLowResolutionSetIfAtMaxPixels) {
2520 InsertEncodedFrames(1, kFrameIntervalMs);
2521 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
2522}
2523
2524TEST_F(ForcedFallbackEnabled, EnteredLowResolutionNotSetIfNotLibvpx) {
2525 InsertEncodedFrames(1, kFrameIntervalMs);
2526 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2527}
2528
2529TEST_F(ForcedFallbackEnabled, EnteredLowResolutionSetIfLibvpx) {
Erik Språnge2fd86a2018-10-24 11:32:39 +02002530 codec_name_ = "libvpx";
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002531 InsertEncodedFrames(1, kFrameIntervalMs);
2532 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
2533}
2534
2535TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfAboveMaxPixels) {
2536 encoded_image_._encodedWidth = kWidth + 1;
2537 InsertEncodedFrames(1, kFrameIntervalMs);
2538 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2539}
2540
2541TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfLibvpx) {
Erik Språnge2fd86a2018-10-24 11:32:39 +02002542 codec_name_ = "libvpx";
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002543 InsertEncodedFrames(1, kFrameIntervalMs);
2544 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2545}
2546
2547TEST_F(ForcedFallbackDisabled,
2548 EnteredLowResolutionSetIfOnMinPixelLimitReached) {
2549 encoded_image_._encodedWidth = kWidth + 1;
2550 statistics_proxy_->OnMinPixelLimitReached();
2551 InsertEncodedFrames(1, kFrameIntervalMs);
2552 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
2553}
2554
asapersson8d75ac72017-09-15 06:41:15 -07002555TEST_F(ForcedFallbackEnabled, OneFallbackEvent) {
2556 // One change. Video: 20000 ms, fallback: 5000 ms (25%).
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002557 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002558 InsertEncodedFrames(15, 1000);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002559 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
Erik Språnge2fd86a2018-10-24 11:32:39 +02002560 codec_name_ = "libvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002561 InsertEncodedFrames(5, 1000);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002562 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002563
2564 statistics_proxy_.reset();
2565 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2566 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 25));
2567 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2568 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 3));
2569}
2570
2571TEST_F(ForcedFallbackEnabled, ThreeFallbackEvents) {
2572 codec_info_.codecSpecific.VP8.temporalIdx = kNoTemporalIdx; // Should work.
2573 const int kMaxFrameDiffMs = 2000;
2574
2575 // Three changes. Video: 60000 ms, fallback: 15000 ms (25%).
2576 InsertEncodedFrames(10, 1000);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002577 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
Erik Språnge2fd86a2018-10-24 11:32:39 +02002578 codec_name_ = "libvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002579 InsertEncodedFrames(15, 500);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002580 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
Erik Språnge2fd86a2018-10-24 11:32:39 +02002581 codec_name_ = "notlibvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002582 InsertEncodedFrames(20, 1000);
2583 InsertEncodedFrames(3, kMaxFrameDiffMs); // Should not be included.
2584 InsertEncodedFrames(10, 1000);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002585 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
Erik Språnge2fd86a2018-10-24 11:32:39 +02002586 codec_name_ = "notlibvpx2";
asapersson8d75ac72017-09-15 06:41:15 -07002587 InsertEncodedFrames(10, 500);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002588 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
Erik Språnge2fd86a2018-10-24 11:32:39 +02002589 codec_name_ = "libvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002590 InsertEncodedFrames(15, 500);
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002591 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002592
2593 statistics_proxy_.reset();
2594 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2595 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 25));
2596 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2597 EXPECT_EQ(1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 3));
2598}
2599
Åsa Persson45bbc8a2017-11-13 10:16:47 +01002600TEST_F(ForcedFallbackEnabled, NoFallbackIfAboveMaxPixels) {
2601 encoded_image_._encodedWidth = kWidth + 1;
Erik Språnge2fd86a2018-10-24 11:32:39 +02002602 codec_name_ = "libvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002603 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2604
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002605 EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002606 statistics_proxy_.reset();
2607 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2608 EXPECT_EQ(0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2609}
2610
Åsa Persson45bbc8a2017-11-13 10:16:47 +01002611TEST_F(ForcedFallbackEnabled, FallbackIfAtMaxPixels) {
2612 encoded_image_._encodedWidth = kWidth;
Erik Språnge2fd86a2018-10-24 11:32:39 +02002613 codec_name_ = "libvpx";
asapersson8d75ac72017-09-15 06:41:15 -07002614 InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2615
Åsa Perssonc3ed6302017-11-16 14:04:52 +01002616 EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
asapersson8d75ac72017-09-15 06:41:15 -07002617 statistics_proxy_.reset();
2618 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2619 EXPECT_EQ(1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2620}
2621
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00002622} // namespace webrtc