xref: /aosp_15_r20/external/webrtc/video/send_statistics_proxy_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "video/send_statistics_proxy.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <map>
15*d9f75844SAndroid Build Coastguard Worker #include <memory>
16*d9f75844SAndroid Build Coastguard Worker #include <string>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
20*d9f75844SAndroid Build Coastguard Worker #include "api/units/timestamp.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_adaptation_reason.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_bitrate_allocation.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_codec_type.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/video_codecs/video_codec.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/fake_clock.h"
26*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/metrics.h"
27*d9f75844SAndroid Build Coastguard Worker #include "test/gmock.h"
28*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
29*d9f75844SAndroid Build Coastguard Worker #include "test/scoped_key_value_config.h"
30*d9f75844SAndroid Build Coastguard Worker #include "video/config/video_encoder_config.h"
31*d9f75844SAndroid Build Coastguard Worker #include "video/video_stream_encoder_observer.h"
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
34*d9f75844SAndroid Build Coastguard Worker namespace {
35*d9f75844SAndroid Build Coastguard Worker const uint32_t kFirstSsrc = 17;
36*d9f75844SAndroid Build Coastguard Worker const uint32_t kSecondSsrc = 42;
37*d9f75844SAndroid Build Coastguard Worker const uint32_t kFirstRtxSsrc = 18;
38*d9f75844SAndroid Build Coastguard Worker const uint32_t kSecondRtxSsrc = 43;
39*d9f75844SAndroid Build Coastguard Worker const uint32_t kFlexFecSsrc = 55;
40*d9f75844SAndroid Build Coastguard Worker const int kFpsPeriodicIntervalMs = 2000;
41*d9f75844SAndroid Build Coastguard Worker const int kWidth = 640;
42*d9f75844SAndroid Build Coastguard Worker const int kHeight = 480;
43*d9f75844SAndroid Build Coastguard Worker const int kQpIdx0 = 21;
44*d9f75844SAndroid Build Coastguard Worker const int kQpIdx1 = 39;
45*d9f75844SAndroid Build Coastguard Worker const int kRtpClockRateHz = 90000;
__anon9d468acb0202() 46*d9f75844SAndroid Build Coastguard Worker const CodecSpecificInfo kDefaultCodecInfo = []() {
47*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
48*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
49*d9f75844SAndroid Build Coastguard Worker   return codec_info;
50*d9f75844SAndroid Build Coastguard Worker }();
51*d9f75844SAndroid Build Coastguard Worker 
52*d9f75844SAndroid Build Coastguard Worker const VideoStreamEncoderObserver::AdaptationSettings kScalingEnabled(true,
53*d9f75844SAndroid Build Coastguard Worker                                                                      true);
54*d9f75844SAndroid Build Coastguard Worker const VideoStreamEncoderObserver::AdaptationSettings kFramerateScalingDisabled(
55*d9f75844SAndroid Build Coastguard Worker     true,
56*d9f75844SAndroid Build Coastguard Worker     false);
57*d9f75844SAndroid Build Coastguard Worker const VideoStreamEncoderObserver::AdaptationSettings kResolutionScalingDisabled(
58*d9f75844SAndroid Build Coastguard Worker     false,
59*d9f75844SAndroid Build Coastguard Worker     true);
60*d9f75844SAndroid Build Coastguard Worker const VideoStreamEncoderObserver::AdaptationSettings kScalingDisabled;
61*d9f75844SAndroid Build Coastguard Worker }  // namespace
62*d9f75844SAndroid Build Coastguard Worker 
63*d9f75844SAndroid Build Coastguard Worker class SendStatisticsProxyTest : public ::testing::Test {
64*d9f75844SAndroid Build Coastguard Worker  public:
SendStatisticsProxyTest()65*d9f75844SAndroid Build Coastguard Worker   SendStatisticsProxyTest() : SendStatisticsProxyTest("") {}
SendStatisticsProxyTest(const std::string & field_trials)66*d9f75844SAndroid Build Coastguard Worker   explicit SendStatisticsProxyTest(const std::string& field_trials)
67*d9f75844SAndroid Build Coastguard Worker       : override_field_trials_(field_trials),
68*d9f75844SAndroid Build Coastguard Worker         fake_clock_(1234),
69*d9f75844SAndroid Build Coastguard Worker         config_(GetTestConfig()) {}
~SendStatisticsProxyTest()70*d9f75844SAndroid Build Coastguard Worker   virtual ~SendStatisticsProxyTest() {}
71*d9f75844SAndroid Build Coastguard Worker 
72*d9f75844SAndroid Build Coastguard Worker  protected:
SetUp()73*d9f75844SAndroid Build Coastguard Worker   virtual void SetUp() {
74*d9f75844SAndroid Build Coastguard Worker     metrics::Reset();
75*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_.reset(
76*d9f75844SAndroid Build Coastguard Worker         new SendStatisticsProxy(&fake_clock_, GetTestConfig(),
77*d9f75844SAndroid Build Coastguard Worker                                 VideoEncoderConfig::ContentType::kRealtimeVideo,
78*d9f75844SAndroid Build Coastguard Worker                                 override_field_trials_));
79*d9f75844SAndroid Build Coastguard Worker     expected_ = VideoSendStream::Stats();
80*d9f75844SAndroid Build Coastguard Worker     for (const auto& ssrc : config_.rtp.ssrcs) {
81*d9f75844SAndroid Build Coastguard Worker       expected_.substreams[ssrc].type =
82*d9f75844SAndroid Build Coastguard Worker           VideoSendStream::StreamStats::StreamType::kMedia;
83*d9f75844SAndroid Build Coastguard Worker     }
84*d9f75844SAndroid Build Coastguard Worker     for (size_t i = 0; i < config_.rtp.rtx.ssrcs.size(); ++i) {
85*d9f75844SAndroid Build Coastguard Worker       uint32_t ssrc = config_.rtp.rtx.ssrcs[i];
86*d9f75844SAndroid Build Coastguard Worker       expected_.substreams[ssrc].type =
87*d9f75844SAndroid Build Coastguard Worker           VideoSendStream::StreamStats::StreamType::kRtx;
88*d9f75844SAndroid Build Coastguard Worker       expected_.substreams[ssrc].referenced_media_ssrc = config_.rtp.ssrcs[i];
89*d9f75844SAndroid Build Coastguard Worker     }
90*d9f75844SAndroid Build Coastguard Worker   }
91*d9f75844SAndroid Build Coastguard Worker 
GetTestConfig()92*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config GetTestConfig() {
93*d9f75844SAndroid Build Coastguard Worker     VideoSendStream::Config config(nullptr);
94*d9f75844SAndroid Build Coastguard Worker     config.rtp.ssrcs.push_back(kFirstSsrc);
95*d9f75844SAndroid Build Coastguard Worker     config.rtp.ssrcs.push_back(kSecondSsrc);
96*d9f75844SAndroid Build Coastguard Worker     config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
97*d9f75844SAndroid Build Coastguard Worker     config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
98*d9f75844SAndroid Build Coastguard Worker     config.rtp.ulpfec.red_payload_type = 17;
99*d9f75844SAndroid Build Coastguard Worker     return config;
100*d9f75844SAndroid Build Coastguard Worker   }
101*d9f75844SAndroid Build Coastguard Worker 
GetTestConfigWithFlexFec()102*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config GetTestConfigWithFlexFec() {
103*d9f75844SAndroid Build Coastguard Worker     VideoSendStream::Config config(nullptr);
104*d9f75844SAndroid Build Coastguard Worker     config.rtp.ssrcs.push_back(kFirstSsrc);
105*d9f75844SAndroid Build Coastguard Worker     config.rtp.ssrcs.push_back(kSecondSsrc);
106*d9f75844SAndroid Build Coastguard Worker     config.rtp.rtx.ssrcs.push_back(kFirstRtxSsrc);
107*d9f75844SAndroid Build Coastguard Worker     config.rtp.rtx.ssrcs.push_back(kSecondRtxSsrc);
108*d9f75844SAndroid Build Coastguard Worker     config.rtp.flexfec.payload_type = 50;
109*d9f75844SAndroid Build Coastguard Worker     config.rtp.flexfec.ssrc = kFlexFecSsrc;
110*d9f75844SAndroid Build Coastguard Worker     config.rtp.flexfec.protected_media_ssrcs = {kFirstSsrc};
111*d9f75844SAndroid Build Coastguard Worker     return config;
112*d9f75844SAndroid Build Coastguard Worker   }
113*d9f75844SAndroid Build Coastguard Worker 
GetStreamStats(uint32_t ssrc)114*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::StreamStats GetStreamStats(uint32_t ssrc) {
115*d9f75844SAndroid Build Coastguard Worker     VideoSendStream::Stats stats = statistics_proxy_->GetStats();
116*d9f75844SAndroid Build Coastguard Worker     std::map<uint32_t, VideoSendStream::StreamStats>::iterator it =
117*d9f75844SAndroid Build Coastguard Worker         stats.substreams.find(ssrc);
118*d9f75844SAndroid Build Coastguard Worker     EXPECT_NE(it, stats.substreams.end());
119*d9f75844SAndroid Build Coastguard Worker     return it->second;
120*d9f75844SAndroid Build Coastguard Worker   }
121*d9f75844SAndroid Build Coastguard Worker 
UpdateDataCounters(uint32_t ssrc)122*d9f75844SAndroid Build Coastguard Worker   void UpdateDataCounters(uint32_t ssrc) {
123*d9f75844SAndroid Build Coastguard Worker     StreamDataCountersCallback* proxy =
124*d9f75844SAndroid Build Coastguard Worker         static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
125*d9f75844SAndroid Build Coastguard Worker     StreamDataCounters counters;
126*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, ssrc);
127*d9f75844SAndroid Build Coastguard Worker   }
128*d9f75844SAndroid Build Coastguard Worker 
ExpectEqual(VideoSendStream::Stats one,VideoSendStream::Stats other)129*d9f75844SAndroid Build Coastguard Worker   void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
130*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.frames, other.frames);
131*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
132*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
133*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps);
134*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.suspended, other.suspended);
135*d9f75844SAndroid Build Coastguard Worker 
136*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(one.substreams.size(), other.substreams.size());
137*d9f75844SAndroid Build Coastguard Worker     for (std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
138*d9f75844SAndroid Build Coastguard Worker              one.substreams.begin();
139*d9f75844SAndroid Build Coastguard Worker          it != one.substreams.end(); ++it) {
140*d9f75844SAndroid Build Coastguard Worker       std::map<uint32_t, VideoSendStream::StreamStats>::const_iterator
141*d9f75844SAndroid Build Coastguard Worker           corresponding_it = other.substreams.find(it->first);
142*d9f75844SAndroid Build Coastguard Worker       ASSERT_TRUE(corresponding_it != other.substreams.end());
143*d9f75844SAndroid Build Coastguard Worker       const VideoSendStream::StreamStats& a = it->second;
144*d9f75844SAndroid Build Coastguard Worker       const VideoSendStream::StreamStats& b = corresponding_it->second;
145*d9f75844SAndroid Build Coastguard Worker 
146*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.type, b.type);
147*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.frame_counts.key_frames, b.frame_counts.key_frames);
148*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.frame_counts.delta_frames, b.frame_counts.delta_frames);
149*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
150*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
151*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
152*d9f75844SAndroid Build Coastguard Worker 
153*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.transmitted.payload_bytes,
154*d9f75844SAndroid Build Coastguard Worker                 b.rtp_stats.transmitted.payload_bytes);
155*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.transmitted.header_bytes,
156*d9f75844SAndroid Build Coastguard Worker                 b.rtp_stats.transmitted.header_bytes);
157*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.transmitted.padding_bytes,
158*d9f75844SAndroid Build Coastguard Worker                 b.rtp_stats.transmitted.padding_bytes);
159*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.transmitted.packets,
160*d9f75844SAndroid Build Coastguard Worker                 b.rtp_stats.transmitted.packets);
161*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.retransmitted.packets,
162*d9f75844SAndroid Build Coastguard Worker                 b.rtp_stats.retransmitted.packets);
163*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.rtp_stats.fec.packets, b.rtp_stats.fec.packets);
164*d9f75844SAndroid Build Coastguard Worker 
165*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(a.report_block_data.has_value(),
166*d9f75844SAndroid Build Coastguard Worker                 b.report_block_data.has_value());
167*d9f75844SAndroid Build Coastguard Worker       if (a.report_block_data.has_value()) {
168*d9f75844SAndroid Build Coastguard Worker         const RTCPReportBlock& a_rtcp_stats =
169*d9f75844SAndroid Build Coastguard Worker             a.report_block_data->report_block();
170*d9f75844SAndroid Build Coastguard Worker         const RTCPReportBlock& b_rtcp_stats =
171*d9f75844SAndroid Build Coastguard Worker             b.report_block_data->report_block();
172*d9f75844SAndroid Build Coastguard Worker         EXPECT_EQ(a_rtcp_stats.fraction_lost, b_rtcp_stats.fraction_lost);
173*d9f75844SAndroid Build Coastguard Worker         EXPECT_EQ(a_rtcp_stats.packets_lost, b_rtcp_stats.packets_lost);
174*d9f75844SAndroid Build Coastguard Worker         EXPECT_EQ(a_rtcp_stats.extended_highest_sequence_number,
175*d9f75844SAndroid Build Coastguard Worker                   b_rtcp_stats.extended_highest_sequence_number);
176*d9f75844SAndroid Build Coastguard Worker         EXPECT_EQ(a_rtcp_stats.jitter, b_rtcp_stats.jitter);
177*d9f75844SAndroid Build Coastguard Worker       }
178*d9f75844SAndroid Build Coastguard Worker     }
179*d9f75844SAndroid Build Coastguard Worker   }
180*d9f75844SAndroid Build Coastguard Worker 
181*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig override_field_trials_;
182*d9f75844SAndroid Build Coastguard Worker   SimulatedClock fake_clock_;
183*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<SendStatisticsProxy> statistics_proxy_;
184*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config config_;
185*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats expected_;
186*d9f75844SAndroid Build Coastguard Worker };
187*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ReportBlockDataObserver)188*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ReportBlockDataObserver) {
189*d9f75844SAndroid Build Coastguard Worker   ReportBlockDataObserver* callback = statistics_proxy_.get();
190*d9f75844SAndroid Build Coastguard Worker   for (uint32_t ssrc : config_.rtp.ssrcs) {
191*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
192*d9f75844SAndroid Build Coastguard Worker     uint32_t offset = ssrc * 4;
193*d9f75844SAndroid Build Coastguard Worker     RTCPReportBlock report_block;
194*d9f75844SAndroid Build Coastguard Worker     report_block.source_ssrc = ssrc;
195*d9f75844SAndroid Build Coastguard Worker     report_block.packets_lost = offset;
196*d9f75844SAndroid Build Coastguard Worker     report_block.extended_highest_sequence_number = offset + 1;
197*d9f75844SAndroid Build Coastguard Worker     report_block.fraction_lost = offset + 2;
198*d9f75844SAndroid Build Coastguard Worker     report_block.jitter = offset + 3;
199*d9f75844SAndroid Build Coastguard Worker     ReportBlockData data;
200*d9f75844SAndroid Build Coastguard Worker     data.SetReportBlock(report_block, 0);
201*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].report_block_data = data;
202*d9f75844SAndroid Build Coastguard Worker 
203*d9f75844SAndroid Build Coastguard Worker     callback->OnReportBlockDataUpdated(data);
204*d9f75844SAndroid Build Coastguard Worker   }
205*d9f75844SAndroid Build Coastguard Worker   for (uint32_t ssrc : config_.rtp.rtx.ssrcs) {
206*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
207*d9f75844SAndroid Build Coastguard Worker     uint32_t offset = ssrc * 4;
208*d9f75844SAndroid Build Coastguard Worker     RTCPReportBlock report_block;
209*d9f75844SAndroid Build Coastguard Worker     report_block.source_ssrc = ssrc;
210*d9f75844SAndroid Build Coastguard Worker     report_block.packets_lost = offset;
211*d9f75844SAndroid Build Coastguard Worker     report_block.extended_highest_sequence_number = offset + 1;
212*d9f75844SAndroid Build Coastguard Worker     report_block.fraction_lost = offset + 2;
213*d9f75844SAndroid Build Coastguard Worker     report_block.jitter = offset + 3;
214*d9f75844SAndroid Build Coastguard Worker     ReportBlockData data;
215*d9f75844SAndroid Build Coastguard Worker     data.SetReportBlock(report_block, 0);
216*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].report_block_data = data;
217*d9f75844SAndroid Build Coastguard Worker 
218*d9f75844SAndroid Build Coastguard Worker     callback->OnReportBlockDataUpdated(data);
219*d9f75844SAndroid Build Coastguard Worker   }
220*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
221*d9f75844SAndroid Build Coastguard Worker   ExpectEqual(expected_, stats);
222*d9f75844SAndroid Build Coastguard Worker }
223*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,Suspended)224*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, Suspended) {
225*d9f75844SAndroid Build Coastguard Worker   // Verify that the value is false by default.
226*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
227*d9f75844SAndroid Build Coastguard Worker 
228*d9f75844SAndroid Build Coastguard Worker   // Verify that we can set it to true.
229*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
230*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().suspended);
231*d9f75844SAndroid Build Coastguard Worker 
232*d9f75844SAndroid Build Coastguard Worker   // Verify that we can set it back to false again.
233*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
234*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().suspended);
235*d9f75844SAndroid Build Coastguard Worker }
236*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,FrameCounts)237*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, FrameCounts) {
238*d9f75844SAndroid Build Coastguard Worker   FrameCountObserver* observer = statistics_proxy_.get();
239*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.ssrcs) {
240*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
241*d9f75844SAndroid Build Coastguard Worker     VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
242*d9f75844SAndroid Build Coastguard Worker     uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
243*d9f75844SAndroid Build Coastguard Worker     FrameCounts frame_counts;
244*d9f75844SAndroid Build Coastguard Worker     frame_counts.key_frames = offset;
245*d9f75844SAndroid Build Coastguard Worker     frame_counts.delta_frames = offset + 1;
246*d9f75844SAndroid Build Coastguard Worker     stats.frame_counts = frame_counts;
247*d9f75844SAndroid Build Coastguard Worker     observer->FrameCountUpdated(frame_counts, ssrc);
248*d9f75844SAndroid Build Coastguard Worker   }
249*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
250*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
251*d9f75844SAndroid Build Coastguard Worker     VideoSendStream::StreamStats& stats = expected_.substreams[ssrc];
252*d9f75844SAndroid Build Coastguard Worker     uint32_t offset = ssrc * sizeof(VideoSendStream::StreamStats);
253*d9f75844SAndroid Build Coastguard Worker     FrameCounts frame_counts;
254*d9f75844SAndroid Build Coastguard Worker     frame_counts.key_frames = offset;
255*d9f75844SAndroid Build Coastguard Worker     frame_counts.delta_frames = offset + 1;
256*d9f75844SAndroid Build Coastguard Worker     stats.frame_counts = frame_counts;
257*d9f75844SAndroid Build Coastguard Worker     observer->FrameCountUpdated(frame_counts, ssrc);
258*d9f75844SAndroid Build Coastguard Worker   }
259*d9f75844SAndroid Build Coastguard Worker 
260*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
261*d9f75844SAndroid Build Coastguard Worker   ExpectEqual(expected_, stats);
262*d9f75844SAndroid Build Coastguard Worker }
263*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,DataCounters)264*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, DataCounters) {
265*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* callback = statistics_proxy_.get();
266*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.ssrcs) {
267*d9f75844SAndroid Build Coastguard Worker     StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
268*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
269*d9f75844SAndroid Build Coastguard Worker     size_t offset = ssrc * sizeof(StreamDataCounters);
270*d9f75844SAndroid Build Coastguard Worker     uint32_t offset_uint32 = static_cast<uint32_t>(offset);
271*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes = offset;
272*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes = offset + 1;
273*d9f75844SAndroid Build Coastguard Worker     counters.fec.packets = offset_uint32 + 2;
274*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.padding_bytes = offset + 3;
275*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.packets = offset_uint32 + 4;
276*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets = offset_uint32 + 5;
277*d9f75844SAndroid Build Coastguard Worker     callback->DataCountersUpdated(counters, ssrc);
278*d9f75844SAndroid Build Coastguard Worker   }
279*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
280*d9f75844SAndroid Build Coastguard Worker     StreamDataCounters& counters = expected_.substreams[ssrc].rtp_stats;
281*d9f75844SAndroid Build Coastguard Worker     // Add statistics with some arbitrary, but unique, numbers.
282*d9f75844SAndroid Build Coastguard Worker     size_t offset = ssrc * sizeof(StreamDataCounters);
283*d9f75844SAndroid Build Coastguard Worker     uint32_t offset_uint32 = static_cast<uint32_t>(offset);
284*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes = offset;
285*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes = offset + 1;
286*d9f75844SAndroid Build Coastguard Worker     counters.fec.packets = offset_uint32 + 2;
287*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.padding_bytes = offset + 3;
288*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.packets = offset_uint32 + 4;
289*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets = offset_uint32 + 5;
290*d9f75844SAndroid Build Coastguard Worker     callback->DataCountersUpdated(counters, ssrc);
291*d9f75844SAndroid Build Coastguard Worker   }
292*d9f75844SAndroid Build Coastguard Worker 
293*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
294*d9f75844SAndroid Build Coastguard Worker   ExpectEqual(expected_, stats);
295*d9f75844SAndroid Build Coastguard Worker }
296*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,Bitrate)297*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, Bitrate) {
298*d9f75844SAndroid Build Coastguard Worker   BitrateStatisticsObserver* observer = statistics_proxy_.get();
299*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.ssrcs) {
300*d9f75844SAndroid Build Coastguard Worker     // Use ssrc as bitrate_bps to get a unique value for each stream.
301*d9f75844SAndroid Build Coastguard Worker     uint32_t total = ssrc;
302*d9f75844SAndroid Build Coastguard Worker     uint32_t retransmit = ssrc + 1;
303*d9f75844SAndroid Build Coastguard Worker     observer->Notify(total, retransmit, ssrc);
304*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].total_bitrate_bps = total;
305*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
306*d9f75844SAndroid Build Coastguard Worker   }
307*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
308*d9f75844SAndroid Build Coastguard Worker     // Use ssrc as bitrate_bps to get a unique value for each stream.
309*d9f75844SAndroid Build Coastguard Worker     uint32_t total = ssrc;
310*d9f75844SAndroid Build Coastguard Worker     uint32_t retransmit = ssrc + 1;
311*d9f75844SAndroid Build Coastguard Worker     observer->Notify(total, retransmit, ssrc);
312*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].total_bitrate_bps = total;
313*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit;
314*d9f75844SAndroid Build Coastguard Worker   }
315*d9f75844SAndroid Build Coastguard Worker 
316*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
317*d9f75844SAndroid Build Coastguard Worker   ExpectEqual(expected_, stats);
318*d9f75844SAndroid Build Coastguard Worker }
319*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SendSideDelay)320*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SendSideDelay) {
321*d9f75844SAndroid Build Coastguard Worker   SendSideDelayObserver* observer = statistics_proxy_.get();
322*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.ssrcs) {
323*d9f75844SAndroid Build Coastguard Worker     // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
324*d9f75844SAndroid Build Coastguard Worker     // stream.
325*d9f75844SAndroid Build Coastguard Worker     int avg_delay_ms = ssrc;
326*d9f75844SAndroid Build Coastguard Worker     int max_delay_ms = ssrc + 1;
327*d9f75844SAndroid Build Coastguard Worker     observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
328*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
329*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
330*d9f75844SAndroid Build Coastguard Worker   }
331*d9f75844SAndroid Build Coastguard Worker   for (const auto& ssrc : config_.rtp.rtx.ssrcs) {
332*d9f75844SAndroid Build Coastguard Worker     // Use ssrc as avg_delay_ms and max_delay_ms to get a unique value for each
333*d9f75844SAndroid Build Coastguard Worker     // stream.
334*d9f75844SAndroid Build Coastguard Worker     int avg_delay_ms = ssrc;
335*d9f75844SAndroid Build Coastguard Worker     int max_delay_ms = ssrc + 1;
336*d9f75844SAndroid Build Coastguard Worker     observer->SendSideDelayUpdated(avg_delay_ms, max_delay_ms, ssrc);
337*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].avg_delay_ms = avg_delay_ms;
338*d9f75844SAndroid Build Coastguard Worker     expected_.substreams[ssrc].max_delay_ms = max_delay_ms;
339*d9f75844SAndroid Build Coastguard Worker   }
340*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
341*d9f75844SAndroid Build Coastguard Worker   ExpectEqual(expected_, stats);
342*d9f75844SAndroid Build Coastguard Worker }
343*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,OnEncodedFrameTimeMeasured)344*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, OnEncodedFrameTimeMeasured) {
345*d9f75844SAndroid Build Coastguard Worker   const int kEncodeTimeMs = 11;
346*d9f75844SAndroid Build Coastguard Worker   int encode_usage_percent = 80;
347*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncodedFrameTimeMeasured(kEncodeTimeMs,
348*d9f75844SAndroid Build Coastguard Worker                                                 encode_usage_percent);
349*d9f75844SAndroid Build Coastguard Worker 
350*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
351*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodeTimeMs, stats.avg_encode_time_ms);
352*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(encode_usage_percent, stats.encode_usage_percent);
353*d9f75844SAndroid Build Coastguard Worker }
354*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,TotalEncodeTimeIncreasesPerFrameMeasured)355*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, TotalEncodeTimeIncreasesPerFrameMeasured) {
356*d9f75844SAndroid Build Coastguard Worker   const int kEncodeUsagePercent = 0;  // Don't care for this test.
357*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, statistics_proxy_->GetStats().total_encode_time_ms);
358*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncodedFrameTimeMeasured(10, kEncodeUsagePercent);
359*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(10u, statistics_proxy_->GetStats().total_encode_time_ms);
360*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncodedFrameTimeMeasured(20, kEncodeUsagePercent);
361*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(30u, statistics_proxy_->GetStats().total_encode_time_ms);
362*d9f75844SAndroid Build Coastguard Worker }
363*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,OnSendEncodedImageIncreasesFramesEncoded)364*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesFramesEncoded) {
365*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
366*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
367*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, statistics_proxy_->GetStats().frames_encoded);
368*d9f75844SAndroid Build Coastguard Worker   for (uint32_t i = 1; i <= 3; ++i) {
369*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
370*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(i, statistics_proxy_->GetStats().frames_encoded);
371*d9f75844SAndroid Build Coastguard Worker   }
372*d9f75844SAndroid Build Coastguard Worker }
373*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,OnSendEncodedImageIncreasesQpSum)374*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, OnSendEncodedImageIncreasesQpSum) {
375*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
376*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
377*d9f75844SAndroid Build Coastguard Worker   auto ssrc = config_.rtp.ssrcs[0];
378*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(absl::nullopt,
379*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
380*d9f75844SAndroid Build Coastguard Worker   encoded_image.qp_ = 3;
381*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
382*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(3u, statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
383*d9f75844SAndroid Build Coastguard Worker   encoded_image.qp_ = 127;
384*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
385*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(130u, statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
386*d9f75844SAndroid Build Coastguard Worker }
387*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,OnSendEncodedImageWithoutQpQpSumWontExist)388*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, OnSendEncodedImageWithoutQpQpSumWontExist) {
389*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
390*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
391*d9f75844SAndroid Build Coastguard Worker   auto ssrc = config_.rtp.ssrcs[0];
392*d9f75844SAndroid Build Coastguard Worker   encoded_image.qp_ = -1;
393*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(absl::nullopt,
394*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
395*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
396*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(absl::nullopt,
397*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().substreams[ssrc].qp_sum);
398*d9f75844SAndroid Build Coastguard Worker }
399*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,TotalEncodedBytesTargetFirstFrame)400*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, TotalEncodedBytesTargetFirstFrame) {
401*d9f75844SAndroid Build Coastguard Worker   const uint32_t kTargetBytesPerSecond = 100000;
402*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(kTargetBytesPerSecond * 8);
403*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, statistics_proxy_->GetStats().total_encoded_bytes_target);
404*d9f75844SAndroid Build Coastguard Worker 
405*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
406*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
407*d9f75844SAndroid Build Coastguard Worker   // On the first frame we don't know the frame rate yet, calculation yields
408*d9f75844SAndroid Build Coastguard Worker   // zero. Our estimate assumes at least 1 FPS, so we expect the frame size to
409*d9f75844SAndroid Build Coastguard Worker   // increment by a full `kTargetBytesPerSecond`.
410*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kTargetBytesPerSecond,
411*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().total_encoded_bytes_target);
412*d9f75844SAndroid Build Coastguard Worker }
413*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,TotalEncodedBytesTargetIncrementsBasedOnFrameRate)414*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
415*d9f75844SAndroid Build Coastguard Worker        TotalEncodedBytesTargetIncrementsBasedOnFrameRate) {
416*d9f75844SAndroid Build Coastguard Worker   const uint32_t kTargetBytesPerSecond = 100000;
417*d9f75844SAndroid Build Coastguard Worker   const int kInterframeDelayMs = 100;
418*d9f75844SAndroid Build Coastguard Worker 
419*d9f75844SAndroid Build Coastguard Worker   // SendStatisticsProxy uses a RateTracker internally. SendStatisticsProxy uses
420*d9f75844SAndroid Build Coastguard Worker   // `fake_clock_` for testing, but the RateTracker relies on a global clock.
421*d9f75844SAndroid Build Coastguard Worker   // This test relies on rtc::ScopedFakeClock to synchronize these two clocks.
422*d9f75844SAndroid Build Coastguard Worker   // TODO(https://crbug.com/webrtc/10640): When the RateTracker uses a Clock
423*d9f75844SAndroid Build Coastguard Worker   // this test can stop relying on rtc::ScopedFakeClock.
424*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_global_clock;
425*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
426*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
427*d9f75844SAndroid Build Coastguard Worker 
428*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(kTargetBytesPerSecond * 8);
429*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
430*d9f75844SAndroid Build Coastguard Worker 
431*d9f75844SAndroid Build Coastguard Worker   // First frame
432*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
433*d9f75844SAndroid Build Coastguard Worker   uint64_t first_total_encoded_bytes_target =
434*d9f75844SAndroid Build Coastguard Worker       statistics_proxy_->GetStats().total_encoded_bytes_target;
435*d9f75844SAndroid Build Coastguard Worker   // Second frame
436*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
437*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
438*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
439*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetTimestamp(encoded_image.Timestamp() +
440*d9f75844SAndroid Build Coastguard Worker                              90 * kInterframeDelayMs);
441*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
442*d9f75844SAndroid Build Coastguard Worker 
443*d9f75844SAndroid Build Coastguard Worker   auto stats = statistics_proxy_->GetStats();
444*d9f75844SAndroid Build Coastguard Worker   // By the time the second frame arrives, one frame has previously arrived
445*d9f75844SAndroid Build Coastguard Worker   // during a `kInterframeDelayMs` interval. The estimated encode frame rate at
446*d9f75844SAndroid Build Coastguard Worker   // the second frame's arrival should be 10 FPS.
447*d9f75844SAndroid Build Coastguard Worker   uint64_t delta_encoded_bytes_target =
448*d9f75844SAndroid Build Coastguard Worker       stats.total_encoded_bytes_target - first_total_encoded_bytes_target;
449*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kTargetBytesPerSecond / 10, delta_encoded_bytes_target);
450*d9f75844SAndroid Build Coastguard Worker }
451*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,EncodeFrameRateInSubStream)452*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStream) {
453*d9f75844SAndroid Build Coastguard Worker   const int kInterframeDelayMs = 100;
454*d9f75844SAndroid Build Coastguard Worker   const auto ssrc = config_.rtp.ssrcs[0];
455*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_global_clock;
456*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
457*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
458*d9f75844SAndroid Build Coastguard Worker 
459*d9f75844SAndroid Build Coastguard Worker   // First frame
460*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
461*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
462*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
463*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
464*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
465*d9f75844SAndroid Build Coastguard Worker   // Second frame
466*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetTimestamp(encoded_image.Timestamp() +
467*d9f75844SAndroid Build Coastguard Worker                              90 * kInterframeDelayMs);
468*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
469*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
470*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
471*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
472*d9f75844SAndroid Build Coastguard Worker 
473*d9f75844SAndroid Build Coastguard Worker   auto stats = statistics_proxy_->GetStats();
474*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[ssrc].encode_frame_rate, 10);
475*d9f75844SAndroid Build Coastguard Worker }
476*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,EncodeFrameRateInSubStreamsVp8Simulcast)477*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp8Simulcast) {
478*d9f75844SAndroid Build Coastguard Worker   const int kInterframeDelayMs = 100;
479*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_global_clock;
480*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
481*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
482*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
483*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
484*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
485*d9f75844SAndroid Build Coastguard Worker 
486*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 10; ++i) {
487*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
488*d9f75844SAndroid Build Coastguard Worker                                90 * kInterframeDelayMs);
489*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
490*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
491*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
492*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
493*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
494*d9f75844SAndroid Build Coastguard Worker     fake_global_clock.SetTime(
495*d9f75844SAndroid Build Coastguard Worker         Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
496*d9f75844SAndroid Build Coastguard Worker   }
497*d9f75844SAndroid Build Coastguard Worker 
498*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
499*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, stats.substreams.size());
500*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
501*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 10);
502*d9f75844SAndroid Build Coastguard Worker 
503*d9f75844SAndroid Build Coastguard Worker   // Stop encoding second stream, expect framerate to be zero.
504*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 10; ++i) {
505*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
506*d9f75844SAndroid Build Coastguard Worker                                90 * kInterframeDelayMs);
507*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
508*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
509*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
510*d9f75844SAndroid Build Coastguard Worker     fake_global_clock.SetTime(
511*d9f75844SAndroid Build Coastguard Worker         Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
512*d9f75844SAndroid Build Coastguard Worker   }
513*d9f75844SAndroid Build Coastguard Worker 
514*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
515*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, stats.substreams.size());
516*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
517*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 0);
518*d9f75844SAndroid Build Coastguard Worker 
519*d9f75844SAndroid Build Coastguard Worker   // Start encoding second stream.
520*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 10; ++i) {
521*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
522*d9f75844SAndroid Build Coastguard Worker                                90 * kInterframeDelayMs);
523*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
524*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
525*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
526*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
527*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
528*d9f75844SAndroid Build Coastguard Worker     fake_global_clock.SetTime(
529*d9f75844SAndroid Build Coastguard Worker         Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
530*d9f75844SAndroid Build Coastguard Worker   }
531*d9f75844SAndroid Build Coastguard Worker 
532*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
533*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2u, stats.substreams.size());
534*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
535*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[1]].encode_frame_rate, 10);
536*d9f75844SAndroid Build Coastguard Worker }
537*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,EncodeFrameRateInSubStreamsVp9Svc)538*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, EncodeFrameRateInSubStreamsVp9Svc) {
539*d9f75844SAndroid Build Coastguard Worker   const int kInterframeDelayMs = 100;
540*d9f75844SAndroid Build Coastguard Worker   rtc::ScopedFakeClock fake_global_clock;
541*d9f75844SAndroid Build Coastguard Worker   fake_global_clock.SetTime(
542*d9f75844SAndroid Build Coastguard Worker       Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
543*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
544*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
545*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP9;
546*d9f75844SAndroid Build Coastguard Worker 
547*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 10; ++i) {
548*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
549*d9f75844SAndroid Build Coastguard Worker                                90 * kInterframeDelayMs);
550*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
551*d9f75844SAndroid Build Coastguard Worker     codec_info.end_of_picture = false;
552*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
553*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
554*d9f75844SAndroid Build Coastguard Worker     codec_info.end_of_picture = true;
555*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
556*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kInterframeDelayMs);
557*d9f75844SAndroid Build Coastguard Worker     fake_global_clock.SetTime(
558*d9f75844SAndroid Build Coastguard Worker         Timestamp::Millis(fake_clock_.TimeInMilliseconds()));
559*d9f75844SAndroid Build Coastguard Worker   }
560*d9f75844SAndroid Build Coastguard Worker 
561*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
562*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1u, stats.substreams.size());
563*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(stats.substreams[config_.rtp.ssrcs[0]].encode_frame_rate, 10);
564*d9f75844SAndroid Build Coastguard Worker }
565*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetCpuAdaptationStats)566*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetCpuAdaptationStats) {
567*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
568*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
569*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
570*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
571*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 1;
572*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
573*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
574*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
575*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
576*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
577*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
578*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 0;
579*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
580*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
581*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
582*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
583*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
584*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 1;
585*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
586*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
587*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
588*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
589*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
590*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
591*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
592*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
593*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
594*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
595*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
596*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
597*d9f75844SAndroid Build Coastguard Worker }
598*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetQualityAdaptationStats)599*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetQualityAdaptationStats) {
600*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
601*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
602*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
603*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
604*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
605*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 0;
606*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
607*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
608*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
609*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
610*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
611*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 0;
612*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
613*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
614*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
615*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
616*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
617*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
618*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
619*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
620*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
621*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
622*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
623*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
624*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
625*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
626*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
627*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
628*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
629*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
630*d9f75844SAndroid Build Coastguard Worker }
631*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsCpuAdaptChanges)632*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsCpuAdaptChanges) {
633*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
634*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
635*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
636*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
637*d9f75844SAndroid Build Coastguard Worker 
638*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
639*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
640*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
641*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
642*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
643*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
644*d9f75844SAndroid Build Coastguard Worker 
645*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 2;
646*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
647*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
648*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
649*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
650*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
651*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
652*d9f75844SAndroid Build Coastguard Worker }
653*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsQualityAdaptChanges)654*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsQualityAdaptChanges) {
655*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
656*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
657*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
658*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
659*d9f75844SAndroid Build Coastguard Worker 
660*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
661*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
662*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
663*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
664*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
665*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
666*d9f75844SAndroid Build Coastguard Worker 
667*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 0;
668*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
669*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
670*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
671*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
672*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
673*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
674*d9f75844SAndroid Build Coastguard Worker }
675*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,TestAdaptationStatisticsMasking)676*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, TestAdaptationStatisticsMasking) {
677*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
678*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
679*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
680*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
681*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
682*d9f75844SAndroid Build Coastguard Worker 
683*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
684*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
685*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
686*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
687*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
688*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
689*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
690*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
691*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
692*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 1;
693*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
694*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
695*d9f75844SAndroid Build Coastguard Worker   // We have 1 fps and resolution reduction for both cpu and quality
696*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
697*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
698*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
699*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
700*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
701*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
702*d9f75844SAndroid Build Coastguard Worker 
703*d9f75844SAndroid Build Coastguard Worker   // Disable quality scaling. Expect quality scaling not limited.
704*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled,
705*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
706*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
707*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
708*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
709*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
710*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
711*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
712*d9f75844SAndroid Build Coastguard Worker 
713*d9f75844SAndroid Build Coastguard Worker   // Disable framerate scaling.
714*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kFramerateScalingDisabled,
715*d9f75844SAndroid Build Coastguard Worker                                               kFramerateScalingDisabled);
716*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
717*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
718*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_framerate);
719*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
720*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
721*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
722*d9f75844SAndroid Build Coastguard Worker 
723*d9f75844SAndroid Build Coastguard Worker   // Disable resolution scaling.
724*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
725*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
726*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
727*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
728*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
729*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().cpu_limited_resolution);
730*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
731*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
732*d9f75844SAndroid Build Coastguard Worker 
733*d9f75844SAndroid Build Coastguard Worker   // Enable all
734*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
735*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
736*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
737*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_framerate);
738*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().cpu_limited_resolution);
739*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_quality_adapt_changes);
740*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2, statistics_proxy_->GetStats().number_of_cpu_adapt_changes);
741*d9f75844SAndroid Build Coastguard Worker }
742*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesNotReported_AdaptationNotEnabled)743*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_AdaptationNotEnabled) {
744*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
745*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
746*d9f75844SAndroid Build Coastguard Worker   // Min runtime has passed.
747*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
748*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
749*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
750*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
751*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
752*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
753*d9f75844SAndroid Build Coastguard Worker }
754*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesNotReported_MinRuntimeNotPassed)755*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesNotReported_MinRuntimeNotPassed) {
756*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
757*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
758*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
759*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
760*d9f75844SAndroid Build Coastguard Worker   // Min runtime has not passed.
761*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
762*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
763*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
764*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
765*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
766*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
767*d9f75844SAndroid Build Coastguard Worker }
768*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ZeroAdaptChangesReported)769*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ZeroAdaptChangesReported) {
770*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
771*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
772*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
773*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
774*d9f75844SAndroid Build Coastguard Worker   // Min runtime has passed.
775*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
776*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
777*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
778*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
779*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
780*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 0));
781*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
782*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
783*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
784*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
785*d9f75844SAndroid Build Coastguard Worker }
786*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,CpuAdaptChangesReported)787*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, CpuAdaptChangesReported) {
788*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
789*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
790*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
791*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
792*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
793*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
794*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
795*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
796*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
797*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
798*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
799*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
800*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
801*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
802*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
803*d9f75844SAndroid Build Coastguard Worker }
804*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ExcludesInitialQualityAdaptDownChange)805*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChange) {
806*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
807*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
808*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
809*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
810*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
811*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
812*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1 (1 initial) = 0, elapsed time: 10 sec => 0 per minute.
813*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
814*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
815*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
816*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
817*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
818*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
819*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
820*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
821*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 0));
822*d9f75844SAndroid Build Coastguard Worker }
823*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ExcludesInitialQualityAdaptDownChanges)824*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownChanges) {
825*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
826*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
827*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
828*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
829*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
830*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
831*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 3 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
832*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
833*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
834*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
835*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
836*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 2;
837*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
838*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
839*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
840*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 3;
841*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
842*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
843*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
844*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
845*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
846*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
847*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
848*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
849*d9f75844SAndroid Build Coastguard Worker }
850*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,InitialQualityAdaptChangesNotExcludedOnError)851*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, InitialQualityAdaptChangesNotExcludedOnError) {
852*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
853*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
854*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
855*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
856*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
857*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
858*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1 (2 initial) = 1, elapsed time: 10 sec => 6 per minute.
859*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
860*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
861*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
862*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
863*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
864*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
865*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
866*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
867*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
868*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
869*d9f75844SAndroid Build Coastguard Worker }
870*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ExcludesInitialQualityAdaptDownAndUpChanges)871*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ExcludesInitialQualityAdaptDownAndUpChanges) {
872*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
873*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
874*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
875*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
876*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
877*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
878*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->ClearAdaptationStats();
879*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 8 (4 initial) = 4, elapsed time: 10 sec => 24 per minute.
880*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
881*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
882*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
883*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
884*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 2;
885*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
886*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
887*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInitialQualityResolutionAdaptDown();
888*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 3;
889*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
890*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
891*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
892*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
893*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
894*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 0;
895*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
896*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
897*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 2;  // Initial resolution up.
898*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
899*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
900*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;  // Initial resolution up.
901*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
902*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
903*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 0;
904*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
905*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
906*d9f75844SAndroid Build Coastguard Worker 
907*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
908*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
909*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
910*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
911*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
912*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 24));
913*d9f75844SAndroid Build Coastguard Worker }
914*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesStatsExcludesDisabledTime)915*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesStatsExcludesDisabledTime) {
916*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
917*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
918*d9f75844SAndroid Build Coastguard Worker 
919*d9f75844SAndroid Build Coastguard Worker   // Disable quality adaptation.
920*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
921*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
922*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled,
923*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
924*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
925*d9f75844SAndroid Build Coastguard Worker 
926*d9f75844SAndroid Build Coastguard Worker   // Enable quality adaptation.
927*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 2, elapsed time: 20 sec.
928*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 0;
929*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
930*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
931*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(5000);
932*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
933*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
934*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(9000);
935*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
936*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
937*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(6000);
938*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
939*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
940*d9f75844SAndroid Build Coastguard Worker 
941*d9f75844SAndroid Build Coastguard Worker   // Disable quality adaptation.
942*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
943*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
944*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
945*d9f75844SAndroid Build Coastguard Worker 
946*d9f75844SAndroid Build Coastguard Worker   // Enable quality adaptation.
947*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec.
948*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 0;
949*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kFramerateScalingDisabled,
950*d9f75844SAndroid Build Coastguard Worker                                               kFramerateScalingDisabled);
951*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
952*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
953*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
954*d9f75844SAndroid Build Coastguard Worker 
955*d9f75844SAndroid Build Coastguard Worker   // Disable quality adaptation.
956*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
957*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
958*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(5000);
959*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
960*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
961*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(20000);
962*d9f75844SAndroid Build Coastguard Worker 
963*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
964*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
965*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
966*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
967*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
968*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
969*d9f75844SAndroid Build Coastguard Worker }
970*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesNotReported_ScalingNotEnabledVideoResumed)971*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
972*d9f75844SAndroid Build Coastguard Worker        AdaptChangesNotReported_ScalingNotEnabledVideoResumed) {
973*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
974*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
975*d9f75844SAndroid Build Coastguard Worker 
976*d9f75844SAndroid Build Coastguard Worker   // Suspend and resume video.
977*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
978*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(5000);
979*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
980*d9f75844SAndroid Build Coastguard Worker 
981*d9f75844SAndroid Build Coastguard Worker   // Min runtime has passed but scaling not enabled.
982*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
983*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
984*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
985*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
986*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
987*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
988*d9f75844SAndroid Build Coastguard Worker }
989*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityAdaptChangesStatsExcludesSuspendedTime)990*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, QualityAdaptChangesStatsExcludesSuspendedTime) {
991*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
992*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
993*d9f75844SAndroid Build Coastguard Worker 
994*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
995*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
996*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
997*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 2, elapsed time: 20 sec.
998*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
999*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(20000);
1000*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1001*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1002*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1003*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1004*d9f75844SAndroid Build Coastguard Worker 
1005*d9f75844SAndroid Build Coastguard Worker   // Suspend and resume video.
1006*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
1007*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
1008*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
1009*d9f75844SAndroid Build Coastguard Worker 
1010*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec.
1011*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1012*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1013*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1014*d9f75844SAndroid Build Coastguard Worker 
1015*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 3, elapsed time: 30 sec => 6 per minute.
1016*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1017*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1018*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
1019*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1020*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
1021*d9f75844SAndroid Build Coastguard Worker }
1022*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,CpuAdaptChangesStatsExcludesSuspendedTime)1023*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, CpuAdaptChangesStatsExcludesSuspendedTime) {
1024*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1025*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1026*d9f75844SAndroid Build Coastguard Worker 
1027*d9f75844SAndroid Build Coastguard Worker   // Video not suspended.
1028*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
1029*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
1030*d9f75844SAndroid Build Coastguard Worker 
1031*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
1032*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1033*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1034*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 20 sec.
1035*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1036*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1037*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1038*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1039*d9f75844SAndroid Build Coastguard Worker 
1040*d9f75844SAndroid Build Coastguard Worker   // Video not suspended, stats time already started.
1041*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
1042*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1043*d9f75844SAndroid Build Coastguard Worker 
1044*d9f75844SAndroid Build Coastguard Worker   // Disable adaptation.
1045*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
1046*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
1047*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
1048*d9f75844SAndroid Build Coastguard Worker 
1049*d9f75844SAndroid Build Coastguard Worker   // Suspend and resume video, stats time not started when scaling not enabled.
1050*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
1051*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
1052*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
1053*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(30000);
1054*d9f75844SAndroid Build Coastguard Worker 
1055*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
1056*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec.
1057*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 0;
1058*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
1059*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1060*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1061*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1062*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1063*d9f75844SAndroid Build Coastguard Worker 
1064*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 2, elapsed time: 30 sec => 4 per minute.
1065*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1066*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1067*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1068*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1069*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 4));
1070*d9f75844SAndroid Build Coastguard Worker }
1071*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesStatsNotStartedIfVideoSuspended)1072*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesStatsNotStartedIfVideoSuspended) {
1073*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1074*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1075*d9f75844SAndroid Build Coastguard Worker 
1076*d9f75844SAndroid Build Coastguard Worker   // Video suspended.
1077*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
1078*d9f75844SAndroid Build Coastguard Worker 
1079*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation, stats time not started when suspended.
1080*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1081*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1082*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1083*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1084*d9f75844SAndroid Build Coastguard Worker 
1085*d9f75844SAndroid Build Coastguard Worker   // Resume video, stats time started.
1086*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec.
1087*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(false);
1088*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1089*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1090*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1091*d9f75844SAndroid Build Coastguard Worker 
1092*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
1093*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1094*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1095*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1096*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1097*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 6));
1098*d9f75844SAndroid Build Coastguard Worker }
1099*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesStatsRestartsOnFirstSentPacket)1100*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesStatsRestartsOnFirstSentPacket) {
1101*d9f75844SAndroid Build Coastguard Worker   // Send first packet, adaptation enabled.
1102*d9f75844SAndroid Build Coastguard Worker   // Elapsed time before first packet is sent should be excluded.
1103*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1104*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1105*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1106*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1107*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1108*d9f75844SAndroid Build Coastguard Worker 
1109*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec.
1110*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1111*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1112*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1113*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1114*d9f75844SAndroid Build Coastguard Worker 
1115*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 10 sec => 6 per minute.
1116*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1117*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1118*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
1119*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1120*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Quality", 6));
1121*d9f75844SAndroid Build Coastguard Worker }
1122*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesStatsStartedAfterFirstSentPacket)1123*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesStatsStartedAfterFirstSentPacket) {
1124*d9f75844SAndroid Build Coastguard Worker   // Enable and disable adaptation.
1125*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1126*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1127*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1128*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(60000);
1129*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingDisabled,
1130*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
1131*d9f75844SAndroid Build Coastguard Worker 
1132*d9f75844SAndroid Build Coastguard Worker   // Send first packet, scaling disabled.
1133*d9f75844SAndroid Build Coastguard Worker   // Elapsed time before first packet is sent should be excluded.
1134*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1135*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(60000);
1136*d9f75844SAndroid Build Coastguard Worker 
1137*d9f75844SAndroid Build Coastguard Worker   // Enable adaptation.
1138*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
1139*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kFramerateScalingDisabled,
1140*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
1141*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1142*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1143*d9f75844SAndroid Build Coastguard Worker 
1144*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 20 sec.
1145*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(10000);
1146*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1147*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1148*d9f75844SAndroid Build Coastguard Worker 
1149*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 1, elapsed time: 20 sec => 3 per minute.
1150*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1151*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1152*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1153*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1154*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 3));
1155*d9f75844SAndroid Build Coastguard Worker }
1156*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,AdaptChangesReportedAfterContentSwitch)1157*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, AdaptChangesReportedAfterContentSwitch) {
1158*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent, cpu adaptation enabled.
1159*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1160*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1161*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1162*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled,
1163*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
1164*d9f75844SAndroid Build Coastguard Worker 
1165*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 2, elapsed time: 15 sec => 8 per minute.
1166*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1167*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1168*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(6000);
1169*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1170*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1171*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(9000);
1172*d9f75844SAndroid Build Coastguard Worker 
1173*d9f75844SAndroid Build Coastguard Worker   // Switch content type, real-time stats should be updated.
1174*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
1175*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kScreen;
1176*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {});
1177*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1178*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Cpu"));
1179*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1180*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.AdaptChangesPerMinute.Cpu", 8));
1181*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1182*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.AdaptChangesPerMinute.Quality"));
1183*d9f75844SAndroid Build Coastguard Worker 
1184*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent, scaling enabled.
1185*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1186*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled,
1187*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
1188*d9f75844SAndroid Build Coastguard Worker 
1189*d9f75844SAndroid Build Coastguard Worker   // Adapt changes: 4, elapsed time: 120 sec => 2 per minute.
1190*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1191*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1192*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1193*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1194*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1195*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1196*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1197*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1198*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(120000);
1199*d9f75844SAndroid Build Coastguard Worker 
1200*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1201*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1202*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(
1203*d9f75844SAndroid Build Coastguard Worker                        "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu"));
1204*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1205*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(
1206*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Cpu", 2));
1207*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1208*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(
1209*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.AdaptChangesPerMinute.Quality"));
1210*d9f75844SAndroid Build Coastguard Worker }
1211*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsCpuWhenCpuIsResolutionLimited)1212*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1213*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonIsCpuWhenCpuIsResolutionLimited) {
1214*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1215*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1216*d9f75844SAndroid Build Coastguard Worker 
1217*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1218*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1219*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1220*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1221*d9f75844SAndroid Build Coastguard Worker 
1222*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kCpu,
1223*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1224*d9f75844SAndroid Build Coastguard Worker }
1225*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsCpuWhenCpuIsFramerateLimited)1226*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1227*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonIsCpuWhenCpuIsFramerateLimited) {
1228*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1229*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1230*d9f75844SAndroid Build Coastguard Worker 
1231*d9f75844SAndroid Build Coastguard Worker   cpu_counts.fps_adaptations = 1;
1232*d9f75844SAndroid Build Coastguard Worker 
1233*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1234*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1235*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1236*d9f75844SAndroid Build Coastguard Worker 
1237*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kCpu,
1238*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1239*d9f75844SAndroid Build Coastguard Worker }
1240*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsBandwidthWhenQualityIsResolutionLimited)1241*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1242*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonIsBandwidthWhenQualityIsResolutionLimited) {
1243*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1244*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1245*d9f75844SAndroid Build Coastguard Worker 
1246*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
1247*d9f75844SAndroid Build Coastguard Worker 
1248*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1249*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1250*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1251*d9f75844SAndroid Build Coastguard Worker 
1252*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kBandwidth,
1253*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1254*d9f75844SAndroid Build Coastguard Worker }
1255*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsBandwidthWhenQualityIsFramerateLimited)1256*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1257*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonIsBandwidthWhenQualityIsFramerateLimited) {
1258*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1259*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1260*d9f75844SAndroid Build Coastguard Worker 
1261*d9f75844SAndroid Build Coastguard Worker   quality_counts.fps_adaptations = 1;
1262*d9f75844SAndroid Build Coastguard Worker 
1263*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1264*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1265*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1266*d9f75844SAndroid Build Coastguard Worker 
1267*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kBandwidth,
1268*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1269*d9f75844SAndroid Build Coastguard Worker }
1270*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsBandwidthWhenBothCpuAndQualityIsLimited)1271*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1272*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonIsBandwidthWhenBothCpuAndQualityIsLimited) {
1273*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1274*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1275*d9f75844SAndroid Build Coastguard Worker 
1276*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1277*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
1278*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1279*d9f75844SAndroid Build Coastguard Worker 
1280*d9f75844SAndroid Build Coastguard Worker   // Even if the last adaptation reason is kCpu, if the counters indicate being
1281*d9f75844SAndroid Build Coastguard Worker   // both CPU and quality (=bandwidth) limited, kBandwidth takes precedence.
1282*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1283*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1284*d9f75844SAndroid Build Coastguard Worker 
1285*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kBandwidth,
1286*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1287*d9f75844SAndroid Build Coastguard Worker }
1288*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonIsNoneWhenNotLimited)1289*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, QualityLimitationReasonIsNoneWhenNotLimited) {
1290*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1291*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1292*d9f75844SAndroid Build Coastguard Worker 
1293*d9f75844SAndroid Build Coastguard Worker   // Observe a limitation due to CPU. This makes sure the test doesn't pass
1294*d9f75844SAndroid Build Coastguard Worker   // due to "none" being the default value.
1295*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1296*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1297*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1298*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1299*d9f75844SAndroid Build Coastguard Worker   // Go back to not being limited.
1300*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
1301*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1302*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1303*d9f75844SAndroid Build Coastguard Worker 
1304*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(QualityLimitationReason::kNone,
1305*d9f75844SAndroid Build Coastguard Worker             statistics_proxy_->GetStats().quality_limitation_reason);
1306*d9f75844SAndroid Build Coastguard Worker }
1307*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationDurationIncreasesWithTime)1308*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, QualityLimitationDurationIncreasesWithTime) {
1309*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1310*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1311*d9f75844SAndroid Build Coastguard Worker 
1312*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1313*d9f75844SAndroid Build Coastguard Worker   // Not limited for 3000 ms
1314*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(3000);
1315*d9f75844SAndroid Build Coastguard Worker   // CPU limited for 2000 ms
1316*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1317*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1318*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1319*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(2000);
1320*d9f75844SAndroid Build Coastguard Worker   // Bandwidth limited for 1000 ms
1321*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
1322*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
1323*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
1324*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1325*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(1000);
1326*d9f75844SAndroid Build Coastguard Worker   // CPU limited for another 2000 ms
1327*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1328*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 0;
1329*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1330*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1331*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(2000);
1332*d9f75844SAndroid Build Coastguard Worker 
1333*d9f75844SAndroid Build Coastguard Worker   auto quality_limitation_durations_ms =
1334*d9f75844SAndroid Build Coastguard Worker       statistics_proxy_->GetStats().quality_limitation_durations_ms;
1335*d9f75844SAndroid Build Coastguard Worker 
1336*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(3000,
1337*d9f75844SAndroid Build Coastguard Worker             quality_limitation_durations_ms[QualityLimitationReason::kNone]);
1338*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(4000,
1339*d9f75844SAndroid Build Coastguard Worker             quality_limitation_durations_ms[QualityLimitationReason::kCpu]);
1340*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1341*d9f75844SAndroid Build Coastguard Worker       1000,
1342*d9f75844SAndroid Build Coastguard Worker       quality_limitation_durations_ms[QualityLimitationReason::kBandwidth]);
1343*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0,
1344*d9f75844SAndroid Build Coastguard Worker             quality_limitation_durations_ms[QualityLimitationReason::kOther]);
1345*d9f75844SAndroid Build Coastguard Worker }
1346*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionChangesDefaultZero)1347*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, QualityLimitationResolutionChangesDefaultZero) {
1348*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1349*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1350*d9f75844SAndroid Build Coastguard Worker }
1351*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionChangesNotChangesWithOnlyDefaultAllocation)1352*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1353*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionChangesNotChangesWithOnlyDefaultAllocation) {
1354*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1355*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1356*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1357*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1358*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1359*d9f75844SAndroid Build Coastguard Worker }
1360*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionChangesDoesNotIncreaseOnFirstAllocation)1361*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1362*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionChangesDoesNotIncreaseOnFirstAllocation) {
1363*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1364*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1365*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1366*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = true;
1367*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1368*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1369*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1370*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1371*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1372*d9f75844SAndroid Build Coastguard Worker }
1373*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionChangesWhenNewLayerGetsBandwidth)1374*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1375*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionChangesWhenNewLayerGetsBandwidth) {
1376*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1377*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1378*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1379*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = true;
1380*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1381*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1382*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1383*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 100);
1384*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1385*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1386*d9f75844SAndroid Build Coastguard Worker       1u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1387*d9f75844SAndroid Build Coastguard Worker }
1388*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionDoesNotChangeWhenLayerSame)1389*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1390*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionDoesNotChangeWhenLayerSame) {
1391*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1392*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1393*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1394*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1395*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1396*d9f75844SAndroid Build Coastguard Worker   // Layer 0 got more bandwidth, but still only one layer on
1397*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 200);
1398*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1399*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1400*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1401*d9f75844SAndroid Build Coastguard Worker }
1402*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionChangesWithTogglingLayers)1403*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1404*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionChangesWithTogglingLayers) {
1405*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1406*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1407*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1408*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = true;
1409*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1410*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1411*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1412*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1413*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1414*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 300);
1415*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1416*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1417*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1418*d9f75844SAndroid Build Coastguard Worker       1u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1419*d9f75844SAndroid Build Coastguard Worker   // Layer 2 off
1420*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 0);
1421*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1422*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1423*d9f75844SAndroid Build Coastguard Worker       2u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1424*d9f75844SAndroid Build Coastguard Worker   // Layer 2 back on
1425*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1426*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1427*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1428*d9f75844SAndroid Build Coastguard Worker       3u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1429*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 0);
1430*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 0);
1431*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 0);
1432*d9f75844SAndroid Build Coastguard Worker   // All layers off
1433*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1434*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1435*d9f75844SAndroid Build Coastguard Worker       4u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1436*d9f75844SAndroid Build Coastguard Worker }
1437*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionDoesNotUpdateOnCodecSimulcastStreamChanges)1438*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1439*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionDoesNotUpdateOnCodecSimulcastStreamChanges) {
1440*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1441*d9f75844SAndroid Build Coastguard Worker   // 3 layers
1442*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1443*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1444*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = true;
1445*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1446*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 500);
1447*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 500);
1448*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1449*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1450*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1451*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1452*d9f75844SAndroid Build Coastguard Worker 
1453*d9f75844SAndroid Build Coastguard Worker   // Down to one layer now, triggered by a config change
1454*d9f75844SAndroid Build Coastguard Worker   codec.numberOfSimulcastStreams = 1;
1455*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = false;
1456*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = false;
1457*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1458*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1459*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1460*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1461*d9f75844SAndroid Build Coastguard Worker 
1462*d9f75844SAndroid Build Coastguard Worker   // Up to 3 layers again.
1463*d9f75844SAndroid Build Coastguard Worker   codec.numberOfSimulcastStreams = 3;
1464*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1465*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[2].active = true;
1466*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 500);
1467*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 500);
1468*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1469*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1470*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1471*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1472*d9f75844SAndroid Build Coastguard Worker }
1473*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationResolutionDoesNotUpdateForSpatialLayerChanges)1474*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1475*d9f75844SAndroid Build Coastguard Worker        QualityLimitationResolutionDoesNotUpdateForSpatialLayerChanges) {
1476*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1477*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1478*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[0].active = true;
1479*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[1].active = true;
1480*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[2].active = true;
1481*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1482*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 500);
1483*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 500);
1484*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1485*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1486*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1487*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1488*d9f75844SAndroid Build Coastguard Worker 
1489*d9f75844SAndroid Build Coastguard Worker   // Down to one layer now, triggered by a config change
1490*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[1].active = false;
1491*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[2].active = false;
1492*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 100);
1493*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1494*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1495*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1496*d9f75844SAndroid Build Coastguard Worker 
1497*d9f75844SAndroid Build Coastguard Worker   // Up to 3 layers again.
1498*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[1].active = true;
1499*d9f75844SAndroid Build Coastguard Worker   codec.spatialLayers[2].active = true;
1500*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 500);
1501*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 500);
1502*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(2, 0, 500);
1503*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1504*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(
1505*d9f75844SAndroid Build Coastguard Worker       0u, statistics_proxy_->GetStats().quality_limitation_resolution_changes);
1506*d9f75844SAndroid Build Coastguard Worker }
1507*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitationReasonsAreCorrectForContentType)1508*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1509*d9f75844SAndroid Build Coastguard Worker        QualityLimitationReasonsAreCorrectForContentType) {
1510*d9f75844SAndroid Build Coastguard Worker   // Realtime case.
1511*d9f75844SAndroid Build Coastguard Worker   // Configure two streams.
1512*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
1513*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1514*d9f75844SAndroid Build Coastguard Worker   config.number_of_streams = 2;
1515*d9f75844SAndroid Build Coastguard Worker   VideoStream stream1;
1516*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth / 2;
1517*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight / 2;
1518*d9f75844SAndroid Build Coastguard Worker   VideoStream stream2;
1519*d9f75844SAndroid Build Coastguard Worker   stream2.width = kWidth;
1520*d9f75844SAndroid Build Coastguard Worker   stream2.height = kHeight;
1521*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
1522*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1523*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
1524*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1525*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kNone);
1526*d9f75844SAndroid Build Coastguard Worker   // Bw disabled one layer.
1527*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
1528*d9f75844SAndroid Build Coastguard Worker   codec.numberOfSimulcastStreams = 2;
1529*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
1530*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
1531*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
1532*d9f75844SAndroid Build Coastguard Worker   // Some positive bitrate only on the first stream.
1533*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 10000);
1534*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 0);
1535*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(true);
1536*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1537*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
1538*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
1539*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1540*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kBandwidth);
1541*d9f75844SAndroid Build Coastguard Worker   // Bw enabled all layers.
1542*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 10000);
1543*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(false);
1544*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1545*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1546*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
1547*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1548*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kNone);
1549*d9f75844SAndroid Build Coastguard Worker 
1550*d9f75844SAndroid Build Coastguard Worker   // Screencast case
1551*d9f75844SAndroid Build Coastguard Worker   // Configure two streams.
1552*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kScreen;
1553*d9f75844SAndroid Build Coastguard Worker   config.number_of_streams = 2;
1554*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth;
1555*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight;
1556*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
1557*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_framerate);
1558*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1559*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1560*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kNone);
1561*d9f75844SAndroid Build Coastguard Worker   // Bw disabled one layer.
1562*d9f75844SAndroid Build Coastguard Worker   // Some positive bitrate only on the second stream.
1563*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(0, 0, 10000);
1564*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 0);
1565*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(true);
1566*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1567*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_framerate);
1568*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1569*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1570*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kBandwidth);
1571*d9f75844SAndroid Build Coastguard Worker   // Bw enabled all layers.
1572*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 10000);
1573*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(false);
1574*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
1575*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1576*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
1577*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(statistics_proxy_->GetStats().quality_limitation_reason,
1578*d9f75844SAndroid Build Coastguard Worker             QualityLimitationReason::kNone);
1579*d9f75844SAndroid Build Coastguard Worker }
1580*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SwitchContentTypeUpdatesHistograms)1581*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SwitchContentTypeUpdatesHistograms) {
1582*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1583*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1584*d9f75844SAndroid Build Coastguard Worker 
1585*d9f75844SAndroid Build Coastguard Worker   // No switch, stats should not be updated.
1586*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
1587*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
1588*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {});
1589*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
1590*d9f75844SAndroid Build Coastguard Worker 
1591*d9f75844SAndroid Build Coastguard Worker   // Switch to screenshare, real-time stats should be updated.
1592*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kScreen;
1593*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {});
1594*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
1595*d9f75844SAndroid Build Coastguard Worker }
1596*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,InputResolutionHistogramsAreUpdated)1597*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, InputResolutionHistogramsAreUpdated) {
1598*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1599*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1600*d9f75844SAndroid Build Coastguard Worker 
1601*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1602*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InputWidthInPixels"));
1603*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1604*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.InputWidthInPixels", kWidth));
1605*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InputHeightInPixels"));
1606*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1607*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.InputHeightInPixels", kHeight));
1608*d9f75844SAndroid Build Coastguard Worker }
1609*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SentResolutionHistogramsAreUpdated)1610*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SentResolutionHistogramsAreUpdated) {
1611*d9f75844SAndroid Build Coastguard Worker   const int64_t kMaxEncodedFrameWindowMs = 800;
1612*d9f75844SAndroid Build Coastguard Worker   const int kFps = 5;
1613*d9f75844SAndroid Build Coastguard Worker   const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
1614*d9f75844SAndroid Build Coastguard Worker   const int kMinSamples =  // Sample added when removed from EncodedFrameMap.
1615*d9f75844SAndroid Build Coastguard Worker       SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
1616*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1617*d9f75844SAndroid Build Coastguard Worker 
1618*d9f75844SAndroid Build Coastguard Worker   // Not enough samples, stats should not be updated.
1619*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinSamples - 1; ++i) {
1620*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1621*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps);
1622*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1623*d9f75844SAndroid Build Coastguard Worker   }
1624*d9f75844SAndroid Build Coastguard Worker   SetUp();  // Reset stats proxy also causes histograms to be reported.
1625*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
1626*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
1627*d9f75844SAndroid Build Coastguard Worker 
1628*d9f75844SAndroid Build Coastguard Worker   // Enough samples, max resolution per frame should be reported.
1629*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetTimestamp(0xffff0000);  // Will wrap.
1630*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinSamples; ++i) {
1631*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1632*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() + 90 * 1000 / kFps);
1633*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedWidth = kWidth;
1634*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedHeight = kHeight;
1635*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1636*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedWidth = kWidth / 2;
1637*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedHeight = kHeight / 2;
1638*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1639*d9f75844SAndroid Build Coastguard Worker   }
1640*d9f75844SAndroid Build Coastguard Worker 
1641*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1642*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.SentWidthInPixels"));
1643*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1644*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.SentWidthInPixels", kWidth));
1645*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.SentHeightInPixels"));
1646*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1647*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.SentHeightInPixels", kHeight));
1648*d9f75844SAndroid Build Coastguard Worker }
1649*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,InputFpsHistogramIsUpdated)1650*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, InputFpsHistogramIsUpdated) {
1651*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
1652*d9f75844SAndroid Build Coastguard Worker   const int kMinPeriodicSamples = 6;
1653*d9f75844SAndroid Build Coastguard Worker   int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
1654*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i <= frames; ++i) {
1655*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1656*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1657*d9f75844SAndroid Build Coastguard Worker   }
1658*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1659*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
1660*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1661*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
1662*d9f75844SAndroid Build Coastguard Worker }
1663*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SentFpsHistogramIsUpdated)1664*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SentFpsHistogramIsUpdated) {
1665*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1666*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
1667*d9f75844SAndroid Build Coastguard Worker   const int kMinPeriodicSamples = 6;
1668*d9f75844SAndroid Build Coastguard Worker   int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000 + 1;
1669*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < frames; ++i) {
1670*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1671*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() + 1);
1672*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1673*d9f75844SAndroid Build Coastguard Worker     // Frame with same timestamp should not be counted.
1674*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1675*d9f75844SAndroid Build Coastguard Worker   }
1676*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1677*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
1678*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1679*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
1680*d9f75844SAndroid Build Coastguard Worker }
1681*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,InputFpsHistogramExcludesSuspendedTime)1682*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, InputFpsHistogramExcludesSuspendedTime) {
1683*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
1684*d9f75844SAndroid Build Coastguard Worker   const int kSuspendTimeMs = 10000;
1685*d9f75844SAndroid Build Coastguard Worker   const int kMinPeriodicSamples = 6;
1686*d9f75844SAndroid Build Coastguard Worker   int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
1687*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < frames; ++i) {
1688*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1689*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1690*d9f75844SAndroid Build Coastguard Worker   }
1691*d9f75844SAndroid Build Coastguard Worker   // Suspend.
1692*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
1693*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
1694*d9f75844SAndroid Build Coastguard Worker 
1695*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < frames; ++i) {
1696*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1697*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1698*d9f75844SAndroid Build Coastguard Worker   }
1699*d9f75844SAndroid Build Coastguard Worker   // Suspended time interval should not affect the framerate.
1700*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1701*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.InputFramesPerSecond"));
1702*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1703*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.InputFramesPerSecond", kFps));
1704*d9f75844SAndroid Build Coastguard Worker }
1705*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SentFpsHistogramExcludesSuspendedTime)1706*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SentFpsHistogramExcludesSuspendedTime) {
1707*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1708*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
1709*d9f75844SAndroid Build Coastguard Worker   const int kSuspendTimeMs = 10000;
1710*d9f75844SAndroid Build Coastguard Worker   const int kMinPeriodicSamples = 6;
1711*d9f75844SAndroid Build Coastguard Worker   int frames = kMinPeriodicSamples * kFpsPeriodicIntervalMs * kFps / 1000;
1712*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < frames; ++i) {
1713*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1714*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(i + 1);
1715*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1716*d9f75844SAndroid Build Coastguard Worker   }
1717*d9f75844SAndroid Build Coastguard Worker   // Suspend.
1718*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSuspendChange(true);
1719*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kSuspendTimeMs);
1720*d9f75844SAndroid Build Coastguard Worker 
1721*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < frames; ++i) {
1722*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
1723*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(i + 1);
1724*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
1725*d9f75844SAndroid Build Coastguard Worker   }
1726*d9f75844SAndroid Build Coastguard Worker   // Suspended time interval should not affect the framerate.
1727*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1728*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.SentFramesPerSecond"));
1729*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1730*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.SentFramesPerSecond", kFps));
1731*d9f75844SAndroid Build Coastguard Worker }
1732*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,CpuLimitedHistogramNotUpdatedWhenDisabled)1733*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramNotUpdatedWhenDisabled) {
1734*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kResolutionScalingDisabled,
1735*d9f75844SAndroid Build Coastguard Worker                                               kResolutionScalingDisabled);
1736*d9f75844SAndroid Build Coastguard Worker 
1737*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1738*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1739*d9f75844SAndroid Build Coastguard Worker 
1740*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1741*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1742*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1743*d9f75844SAndroid Build Coastguard Worker }
1744*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,CpuLimitedHistogramUpdated)1745*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, CpuLimitedHistogramUpdated) {
1746*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
1747*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
1748*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 0;
1749*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
1750*d9f75844SAndroid Build Coastguard Worker 
1751*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1752*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1753*d9f75844SAndroid Build Coastguard Worker 
1754*d9f75844SAndroid Build Coastguard Worker   cpu_counts.resolution_adaptations = 1;
1755*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kCpu,
1756*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
1757*d9f75844SAndroid Build Coastguard Worker 
1758*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
1759*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnIncomingFrame(kWidth, kHeight);
1760*d9f75844SAndroid Build Coastguard Worker 
1761*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1762*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1763*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.CpuLimitedResolutionInPercent"));
1764*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1765*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.CpuLimitedResolutionInPercent", 50));
1766*d9f75844SAndroid Build Coastguard Worker }
1767*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,LifetimeHistogramIsUpdated)1768*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, LifetimeHistogramIsUpdated) {
1769*d9f75844SAndroid Build Coastguard Worker   const int64_t kTimeSec = 3;
1770*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(kTimeSec * 1000);
1771*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1772*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1773*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.SendStreamLifetimeInSeconds"));
1774*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1775*d9f75844SAndroid Build Coastguard Worker       1,
1776*d9f75844SAndroid Build Coastguard Worker       metrics::NumEvents("WebRTC.Video.SendStreamLifetimeInSeconds", kTimeSec));
1777*d9f75844SAndroid Build Coastguard Worker }
1778*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,CodecTypeHistogramIsUpdated)1779*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, CodecTypeHistogramIsUpdated) {
1780*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1781*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1782*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoder.CodecType"));
1783*d9f75844SAndroid Build Coastguard Worker }
1784*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,PauseEventHistogramIsUpdated)1785*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, PauseEventHistogramIsUpdated) {
1786*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1787*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1788*d9f75844SAndroid Build Coastguard Worker 
1789*d9f75844SAndroid Build Coastguard Worker   // Min runtime has passed.
1790*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1791*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1792*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1793*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1794*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
1795*d9f75844SAndroid Build Coastguard Worker }
1796*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,PauseEventHistogramIsNotUpdatedIfMinRuntimeHasNotPassed)1797*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1798*d9f75844SAndroid Build Coastguard Worker        PauseEventHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
1799*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1800*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1801*d9f75844SAndroid Build Coastguard Worker 
1802*d9f75844SAndroid Build Coastguard Worker   // Min runtime has not passed.
1803*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
1804*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1805*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1806*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1807*d9f75844SAndroid Build Coastguard Worker }
1808*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,PauseEventHistogramIsNotUpdatedIfNoMediaIsSent)1809*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1810*d9f75844SAndroid Build Coastguard Worker        PauseEventHistogramIsNotUpdatedIfNoMediaIsSent) {
1811*d9f75844SAndroid Build Coastguard Worker   // First RTP packet not sent.
1812*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1813*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1814*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1815*d9f75844SAndroid Build Coastguard Worker }
1816*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,NoPauseEvent)1817*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, NoPauseEvent) {
1818*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent and min runtime passed.
1819*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1820*d9f75844SAndroid Build Coastguard Worker 
1821*d9f75844SAndroid Build Coastguard Worker   // No change. Video: 10000 ms, paused: 0 ms (0%).
1822*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(50000);
1823*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1824*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);  // VideoSendStream::Stop
1825*d9f75844SAndroid Build Coastguard Worker 
1826*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1827*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1828*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1829*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 0));
1830*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1831*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1832*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 0));
1833*d9f75844SAndroid Build Coastguard Worker }
1834*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,OnePauseEvent)1835*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, OnePauseEvent) {
1836*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent and min runtime passed.
1837*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1838*d9f75844SAndroid Build Coastguard Worker 
1839*d9f75844SAndroid Build Coastguard Worker   // One change. Video: 7000 ms, paused: 3000 ms (30%).
1840*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(50000);
1841*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(7000);
1842*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);
1843*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(3000);
1844*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);  // VideoSendStream::Stop
1845*d9f75844SAndroid Build Coastguard Worker 
1846*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1847*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1848*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1849*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 1));
1850*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1851*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1852*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 30));
1853*d9f75844SAndroid Build Coastguard Worker }
1854*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,TwoPauseEvents)1855*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, TwoPauseEvents) {
1856*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1857*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1858*d9f75844SAndroid Build Coastguard Worker 
1859*d9f75844SAndroid Build Coastguard Worker   // Two changes. Video: 19000 ms, paused: 1000 ms (5%).
1860*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);
1861*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(1000);
1862*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(50000);  // Starts on bitrate > 0.
1863*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(7000);
1864*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(60000);
1865*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(3000);
1866*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);
1867*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(250);
1868*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);
1869*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(750);
1870*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(60000);
1871*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(5000);
1872*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(50000);
1873*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(4000);
1874*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);  // VideoSendStream::Stop
1875*d9f75844SAndroid Build Coastguard Worker 
1876*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1877*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.NumberOfPauseEvents"));
1878*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1879*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.NumberOfPauseEvents", 2));
1880*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1881*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1882*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.PausedTimeInPercent", 5));
1883*d9f75844SAndroid Build Coastguard Worker }
1884*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,PausedTimeHistogramIsNotUpdatedIfMinRuntimeHasNotPassed)1885*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
1886*d9f75844SAndroid Build Coastguard Worker        PausedTimeHistogramIsNotUpdatedIfMinRuntimeHasNotPassed) {
1887*d9f75844SAndroid Build Coastguard Worker   // First RTP packet sent.
1888*d9f75844SAndroid Build Coastguard Worker   UpdateDataCounters(kFirstSsrc);
1889*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000);
1890*d9f75844SAndroid Build Coastguard Worker 
1891*d9f75844SAndroid Build Coastguard Worker   // Min runtime has not passed.
1892*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(50000);
1893*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(metrics::kMinRunTimeInSeconds * 1000 - 1);
1894*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);  // VideoSendStream::Stop
1895*d9f75844SAndroid Build Coastguard Worker 
1896*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1897*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.PausedTimeInPercent"));
1898*d9f75844SAndroid Build Coastguard Worker }
1899*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,VerifyQpHistogramStats_Vp8)1900*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8) {
1901*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1902*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
1903*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
1904*d9f75844SAndroid Build Coastguard Worker 
1905*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1906*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
1907*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx0;
1908*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1909*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
1910*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx1;
1911*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1912*d9f75844SAndroid Build Coastguard Worker   }
1913*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1914*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S0"));
1915*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1916*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S0", kQpIdx0));
1917*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8.S1"));
1918*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1919*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8.S1", kQpIdx1));
1920*d9f75844SAndroid Build Coastguard Worker }
1921*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,VerifyQpHistogramStats_Vp8OneSsrc)1922*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp8OneSsrc) {
1923*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
1924*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config config(nullptr);
1925*d9f75844SAndroid Build Coastguard Worker   config.rtp.ssrcs.push_back(kFirstSsrc);
1926*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
1927*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo,
1928*d9f75844SAndroid Build Coastguard Worker       field_trials));
1929*d9f75844SAndroid Build Coastguard Worker 
1930*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1931*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
1932*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
1933*d9f75844SAndroid Build Coastguard Worker 
1934*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1935*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
1936*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx0;
1937*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1938*d9f75844SAndroid Build Coastguard Worker   }
1939*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1940*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp8"));
1941*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1942*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp8", kQpIdx0));
1943*d9f75844SAndroid Build Coastguard Worker }
1944*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,VerifyQpHistogramStats_Vp9)1945*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9) {
1946*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1947*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
1948*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP9;
1949*d9f75844SAndroid Build Coastguard Worker   codec_info.codecSpecific.VP9.num_spatial_layers = 2;
1950*d9f75844SAndroid Build Coastguard Worker 
1951*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1952*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx0;
1953*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
1954*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1955*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx1;
1956*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
1957*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1958*d9f75844SAndroid Build Coastguard Worker   }
1959*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1960*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S0"));
1961*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1962*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S0", kQpIdx0));
1963*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9.S1"));
1964*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
1965*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9.S1", kQpIdx1));
1966*d9f75844SAndroid Build Coastguard Worker }
1967*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,VerifyQpHistogramStats_Vp9OneSpatialLayer)1968*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_Vp9OneSpatialLayer) {
1969*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
1970*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config config(nullptr);
1971*d9f75844SAndroid Build Coastguard Worker   config.rtp.ssrcs.push_back(kFirstSsrc);
1972*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
1973*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo,
1974*d9f75844SAndroid Build Coastguard Worker       field_trials));
1975*d9f75844SAndroid Build Coastguard Worker 
1976*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1977*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
1978*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP9;
1979*d9f75844SAndroid Build Coastguard Worker   codec_info.codecSpecific.VP9.num_spatial_layers = 1;
1980*d9f75844SAndroid Build Coastguard Worker 
1981*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1982*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx0;
1983*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
1984*d9f75844SAndroid Build Coastguard Worker   }
1985*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
1986*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.Vp9"));
1987*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
1988*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.Encoded.Qp.Vp9", kQpIdx0));
1989*d9f75844SAndroid Build Coastguard Worker }
1990*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,VerifyQpHistogramStats_H264)1991*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, VerifyQpHistogramStats_H264) {
1992*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
1993*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
1994*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecH264;
1995*d9f75844SAndroid Build Coastguard Worker 
1996*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i) {
1997*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(0);
1998*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx0;
1999*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2000*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetSpatialIndex(1);
2001*d9f75844SAndroid Build Coastguard Worker     encoded_image.qp_ = kQpIdx1;
2002*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2003*d9f75844SAndroid Build Coastguard Worker   }
2004*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2005*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.H264.S0"));
2006*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2007*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.H264.S0", kQpIdx0));
2008*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.Encoded.Qp.H264.S1"));
2009*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2010*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Encoded.Qp.H264.S1", kQpIdx1));
2011*d9f75844SAndroid Build Coastguard Worker }
2012*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,BandwidthLimitedHistogramsNotUpdatedForOneStream)2013*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2014*d9f75844SAndroid Build Coastguard Worker        BandwidthLimitedHistogramsNotUpdatedForOneStream) {
2015*d9f75844SAndroid Build Coastguard Worker   // Configure one stream.
2016*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2017*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
2018*d9f75844SAndroid Build Coastguard Worker   VideoStream stream1;
2019*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth;
2020*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight;
2021*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1});
2022*d9f75844SAndroid Build Coastguard Worker 
2023*d9f75844SAndroid Build Coastguard Worker   const int64_t kMaxEncodedFrameWindowMs = 800;
2024*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
2025*d9f75844SAndroid Build Coastguard Worker   const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
2026*d9f75844SAndroid Build Coastguard Worker   const int kMinSamples =  // Sample added when removed from EncodedFrameMap.
2027*d9f75844SAndroid Build Coastguard Worker       SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
2028*d9f75844SAndroid Build Coastguard Worker 
2029*d9f75844SAndroid Build Coastguard Worker   // Stream encoded.
2030*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2031*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kWidth;
2032*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kHeight;
2033*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinSamples; ++i) {
2034*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
2035*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
2036*d9f75844SAndroid Build Coastguard Worker                                (kRtpClockRateHz / kFps));
2037*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2038*d9f75844SAndroid Build Coastguard Worker   }
2039*d9f75844SAndroid Build Coastguard Worker 
2040*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2041*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2042*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples(
2043*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
2044*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples(
2045*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
2046*d9f75844SAndroid Build Coastguard Worker }
2047*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,BandwidthLimitedHistogramsUpdatedForTwoStreams_NoResolutionDisabled)2048*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2049*d9f75844SAndroid Build Coastguard Worker        BandwidthLimitedHistogramsUpdatedForTwoStreams_NoResolutionDisabled) {
2050*d9f75844SAndroid Build Coastguard Worker   // Configure two streams.
2051*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2052*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
2053*d9f75844SAndroid Build Coastguard Worker   VideoStream stream1;
2054*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth / 2;
2055*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight / 2;
2056*d9f75844SAndroid Build Coastguard Worker   VideoStream stream2;
2057*d9f75844SAndroid Build Coastguard Worker   stream2.width = kWidth;
2058*d9f75844SAndroid Build Coastguard Worker   stream2.height = kHeight;
2059*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
2060*d9f75844SAndroid Build Coastguard Worker 
2061*d9f75844SAndroid Build Coastguard Worker   const int64_t kMaxEncodedFrameWindowMs = 800;
2062*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
2063*d9f75844SAndroid Build Coastguard Worker   const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
2064*d9f75844SAndroid Build Coastguard Worker   const int kMinSamples =  // Sample added when removed from EncodedFrameMap.
2065*d9f75844SAndroid Build Coastguard Worker       SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
2066*d9f75844SAndroid Build Coastguard Worker 
2067*d9f75844SAndroid Build Coastguard Worker   // Two streams encoded.
2068*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2069*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinSamples; ++i) {
2070*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
2071*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
2072*d9f75844SAndroid Build Coastguard Worker                                (kRtpClockRateHz / kFps));
2073*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedWidth = kWidth;
2074*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedHeight = kHeight;
2075*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2076*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedWidth = kWidth / 2;
2077*d9f75844SAndroid Build Coastguard Worker     encoded_image._encodedHeight = kHeight / 2;
2078*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2079*d9f75844SAndroid Build Coastguard Worker   }
2080*d9f75844SAndroid Build Coastguard Worker 
2081*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2082*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2083*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2084*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
2085*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2086*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.BandwidthLimitedResolutionInPercent",
2087*d9f75844SAndroid Build Coastguard Worker                             0));
2088*d9f75844SAndroid Build Coastguard Worker   // No resolution disabled.
2089*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples(
2090*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
2091*d9f75844SAndroid Build Coastguard Worker }
2092*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,BandwidthLimitedHistogramsUpdatedForTwoStreams_OneResolutionDisabled)2093*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2094*d9f75844SAndroid Build Coastguard Worker        BandwidthLimitedHistogramsUpdatedForTwoStreams_OneResolutionDisabled) {
2095*d9f75844SAndroid Build Coastguard Worker   // Configure two streams.
2096*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2097*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
2098*d9f75844SAndroid Build Coastguard Worker   VideoStream stream1;
2099*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth / 2;
2100*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight / 2;
2101*d9f75844SAndroid Build Coastguard Worker   VideoStream stream2;
2102*d9f75844SAndroid Build Coastguard Worker   stream2.width = kWidth;
2103*d9f75844SAndroid Build Coastguard Worker   stream2.height = kHeight;
2104*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
2105*d9f75844SAndroid Build Coastguard Worker 
2106*d9f75844SAndroid Build Coastguard Worker   const int64_t kMaxEncodedFrameWindowMs = 800;
2107*d9f75844SAndroid Build Coastguard Worker   const int kFps = 20;
2108*d9f75844SAndroid Build Coastguard Worker   const int kNumFramesPerWindow = kFps * kMaxEncodedFrameWindowMs / 1000;
2109*d9f75844SAndroid Build Coastguard Worker   const int kMinSamples =  // Sample added when removed from EncodedFrameMap.
2110*d9f75844SAndroid Build Coastguard Worker       SendStatisticsProxy::kMinRequiredMetricsSamples + kNumFramesPerWindow;
2111*d9f75844SAndroid Build Coastguard Worker 
2112*d9f75844SAndroid Build Coastguard Worker   // One stream encoded.
2113*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2114*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kWidth / 2;
2115*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kHeight / 2;
2116*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinSamples; ++i) {
2117*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(1000 / kFps);
2118*d9f75844SAndroid Build Coastguard Worker     encoded_image.SetTimestamp(encoded_image.Timestamp() +
2119*d9f75844SAndroid Build Coastguard Worker                                (kRtpClockRateHz / kFps));
2120*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2121*d9f75844SAndroid Build Coastguard Worker   }
2122*d9f75844SAndroid Build Coastguard Worker 
2123*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2124*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2125*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2126*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionInPercent"));
2127*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2128*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.BandwidthLimitedResolutionInPercent",
2129*d9f75844SAndroid Build Coastguard Worker                             100));
2130*d9f75844SAndroid Build Coastguard Worker   // One resolution disabled.
2131*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2132*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.BandwidthLimitedResolutionsDisabled"));
2133*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2134*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.BandwidthLimitedResolutionsDisabled",
2135*d9f75844SAndroid Build Coastguard Worker                             1));
2136*d9f75844SAndroid Build Coastguard Worker }
2137*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitedHistogramsNotUpdatedWhenDisabled)2138*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2139*d9f75844SAndroid Build Coastguard Worker        QualityLimitedHistogramsNotUpdatedWhenDisabled) {
2140*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kFramerateScalingDisabled,
2141*d9f75844SAndroid Build Coastguard Worker                                               kScalingDisabled);
2142*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2143*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2144*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
2145*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
2146*d9f75844SAndroid Build Coastguard Worker 
2147*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2148*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2149*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2150*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
2151*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples(
2152*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.QualityLimitedResolutionDownscales"));
2153*d9f75844SAndroid Build Coastguard Worker }
2154*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale)2155*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2156*d9f75844SAndroid Build Coastguard Worker        QualityLimitedHistogramsUpdatedWhenEnabled_NoResolutionDownscale) {
2157*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
2158*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2159*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2160*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
2161*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
2162*d9f75844SAndroid Build Coastguard Worker 
2163*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2164*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2165*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2166*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
2167*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumEvents(
2168*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.QualityLimitedResolutionInPercent", 0));
2169*d9f75844SAndroid Build Coastguard Worker   // No resolution downscale.
2170*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples(
2171*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.QualityLimitedResolutionDownscales"));
2172*d9f75844SAndroid Build Coastguard Worker }
2173*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales)2174*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest,
2175*d9f75844SAndroid Build Coastguard Worker        QualityLimitedHistogramsUpdatedWhenEnabled_TwoResolutionDownscales) {
2176*d9f75844SAndroid Build Coastguard Worker   const int kDownscales = 2;
2177*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
2178*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
2179*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = kDownscales;
2180*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kScalingEnabled, kScalingEnabled);
2181*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
2182*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
2183*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2184*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2185*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < SendStatisticsProxy::kMinRequiredMetricsSamples; ++i)
2186*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image, &kDefaultCodecInfo);
2187*d9f75844SAndroid Build Coastguard Worker   // Histograms are updated when the statistics_proxy_ is deleted.
2188*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2189*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2190*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.QualityLimitedResolutionInPercent"));
2191*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2192*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.QualityLimitedResolutionInPercent",
2193*d9f75844SAndroid Build Coastguard Worker                             100));
2194*d9f75844SAndroid Build Coastguard Worker   // Resolution downscales.
2195*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2196*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.QualityLimitedResolutionDownscales"));
2197*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2198*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.QualityLimitedResolutionDownscales",
2199*d9f75844SAndroid Build Coastguard Worker                             kDownscales));
2200*d9f75844SAndroid Build Coastguard Worker }
2201*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsBandwidthLimitedResolution)2202*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsBandwidthLimitedResolution) {
2203*d9f75844SAndroid Build Coastguard Worker   // Initially false.
2204*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
2205*d9f75844SAndroid Build Coastguard Worker 
2206*d9f75844SAndroid Build Coastguard Worker   // Configure two streams.
2207*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2208*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kRealtimeVideo;
2209*d9f75844SAndroid Build Coastguard Worker   config.number_of_streams = 2;
2210*d9f75844SAndroid Build Coastguard Worker   VideoStream stream1;
2211*d9f75844SAndroid Build Coastguard Worker   stream1.width = kWidth / 2;
2212*d9f75844SAndroid Build Coastguard Worker   stream1.height = kHeight / 2;
2213*d9f75844SAndroid Build Coastguard Worker   VideoStream stream2;
2214*d9f75844SAndroid Build Coastguard Worker   stream2.width = kWidth;
2215*d9f75844SAndroid Build Coastguard Worker   stream2.height = kHeight;
2216*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {stream1, stream2});
2217*d9f75844SAndroid Build Coastguard Worker 
2218*d9f75844SAndroid Build Coastguard Worker   // One stream encoded.
2219*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2220*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kWidth / 2;
2221*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kHeight / 2;
2222*d9f75844SAndroid Build Coastguard Worker 
2223*d9f75844SAndroid Build Coastguard Worker   // Resolution scaled due to quality.
2224*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters cpu_counts;
2225*d9f75844SAndroid Build Coastguard Worker   VideoAdaptationCounters quality_counts;
2226*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 1;
2227*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->UpdateAdaptationSettings(kFramerateScalingDisabled,
2228*d9f75844SAndroid Build Coastguard Worker                                               kFramerateScalingDisabled);
2229*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
2230*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
2231*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2232*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
2233*d9f75844SAndroid Build Coastguard Worker 
2234*d9f75844SAndroid Build Coastguard Worker   // Adapt up.
2235*d9f75844SAndroid Build Coastguard Worker   quality_counts.resolution_adaptations = 0;
2236*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnAdaptationChanged(VideoAdaptationReason::kQuality,
2237*d9f75844SAndroid Build Coastguard Worker                                          cpu_counts, quality_counts);
2238*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, nullptr);
2239*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
2240*d9f75844SAndroid Build Coastguard Worker 
2241*d9f75844SAndroid Build Coastguard Worker   // Bw disabled one layer.
2242*d9f75844SAndroid Build Coastguard Worker   VideoCodec codec;
2243*d9f75844SAndroid Build Coastguard Worker   codec.numberOfSimulcastStreams = 2;
2244*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[0].active = true;
2245*d9f75844SAndroid Build Coastguard Worker   codec.simulcastStream[1].active = true;
2246*d9f75844SAndroid Build Coastguard Worker   VideoBitrateAllocation allocation;
2247*d9f75844SAndroid Build Coastguard Worker   // Some positive bitrate only on the second stream.
2248*d9f75844SAndroid Build Coastguard Worker   allocation.SetBitrate(1, 0, 10000);
2249*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(true);
2250*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
2251*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
2252*d9f75844SAndroid Build Coastguard Worker 
2253*d9f75844SAndroid Build Coastguard Worker   // Revert for the next test.
2254*d9f75844SAndroid Build Coastguard Worker   allocation.set_bw_limited(false);
2255*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnBitrateAllocationUpdated(codec, allocation);
2256*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().bw_limited_resolution);
2257*d9f75844SAndroid Build Coastguard Worker 
2258*d9f75844SAndroid Build Coastguard Worker   // Internal encoder scaler reduced resolution.
2259*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderInternalScalerUpdate(/*scaled=*/true);
2260*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().bw_limited_resolution);
2261*d9f75844SAndroid Build Coastguard Worker }
2262*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsTargetMediaBitrate)2263*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsTargetMediaBitrate) {
2264*d9f75844SAndroid Build Coastguard Worker   // Initially zero.
2265*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
2266*d9f75844SAndroid Build Coastguard Worker 
2267*d9f75844SAndroid Build Coastguard Worker   const int kBitrate = 100000;
2268*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(kBitrate);
2269*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kBitrate, statistics_proxy_->GetStats().target_media_bitrate_bps);
2270*d9f75844SAndroid Build Coastguard Worker 
2271*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSetEncoderTargetRate(0);
2272*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, statistics_proxy_->GetStats().target_media_bitrate_bps);
2273*d9f75844SAndroid Build Coastguard Worker }
2274*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,NoSubstreams)2275*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, NoSubstreams) {
2276*d9f75844SAndroid Build Coastguard Worker   uint32_t excluded_ssrc =
2277*d9f75844SAndroid Build Coastguard Worker       std::max(*absl::c_max_element(config_.rtp.ssrcs),
2278*d9f75844SAndroid Build Coastguard Worker                *absl::c_max_element(config_.rtp.rtx.ssrcs)) +
2279*d9f75844SAndroid Build Coastguard Worker       1;
2280*d9f75844SAndroid Build Coastguard Worker   // From ReportBlockDataObserver.
2281*d9f75844SAndroid Build Coastguard Worker   ReportBlockDataObserver* rtcp_callback = statistics_proxy_.get();
2282*d9f75844SAndroid Build Coastguard Worker   RTCPReportBlock report_block;
2283*d9f75844SAndroid Build Coastguard Worker   report_block.source_ssrc = excluded_ssrc;
2284*d9f75844SAndroid Build Coastguard Worker   ReportBlockData data;
2285*d9f75844SAndroid Build Coastguard Worker   data.SetReportBlock(report_block, 0);
2286*d9f75844SAndroid Build Coastguard Worker   rtcp_callback->OnReportBlockDataUpdated(data);
2287*d9f75844SAndroid Build Coastguard Worker 
2288*d9f75844SAndroid Build Coastguard Worker   // From BitrateStatisticsObserver.
2289*d9f75844SAndroid Build Coastguard Worker   uint32_t total = 0;
2290*d9f75844SAndroid Build Coastguard Worker   uint32_t retransmit = 0;
2291*d9f75844SAndroid Build Coastguard Worker   BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
2292*d9f75844SAndroid Build Coastguard Worker   bitrate_observer->Notify(total, retransmit, excluded_ssrc);
2293*d9f75844SAndroid Build Coastguard Worker 
2294*d9f75844SAndroid Build Coastguard Worker   // From FrameCountObserver.
2295*d9f75844SAndroid Build Coastguard Worker   FrameCountObserver* fps_observer = statistics_proxy_.get();
2296*d9f75844SAndroid Build Coastguard Worker   FrameCounts frame_counts;
2297*d9f75844SAndroid Build Coastguard Worker   frame_counts.key_frames = 1;
2298*d9f75844SAndroid Build Coastguard Worker   fps_observer->FrameCountUpdated(frame_counts, excluded_ssrc);
2299*d9f75844SAndroid Build Coastguard Worker 
2300*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2301*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats.substreams.empty());
2302*d9f75844SAndroid Build Coastguard Worker }
2303*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,EncodedResolutionTimesOut)2304*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, EncodedResolutionTimesOut) {
2305*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedWidth = 123;
2306*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedHeight = 81;
2307*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2308*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kEncodedWidth;
2309*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kEncodedHeight;
2310*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2311*d9f75844SAndroid Build Coastguard Worker 
2312*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
2313*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
2314*d9f75844SAndroid Build Coastguard Worker 
2315*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2316*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(1);
2317*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2318*d9f75844SAndroid Build Coastguard Worker 
2319*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2320*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
2321*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
2322*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
2323*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
2324*d9f75844SAndroid Build Coastguard Worker 
2325*d9f75844SAndroid Build Coastguard Worker   // Forward almost to timeout, this should not have removed stats.
2326*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(SendStatisticsProxy::kStatsTimeoutMs - 1);
2327*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
2328*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
2329*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
2330*d9f75844SAndroid Build Coastguard Worker 
2331*d9f75844SAndroid Build Coastguard Worker   // Update the first SSRC with bogus RTCP stats to make sure that encoded
2332*d9f75844SAndroid Build Coastguard Worker   // resolution still times out (no global timeout for all stats).
2333*d9f75844SAndroid Build Coastguard Worker   ReportBlockDataObserver* rtcp_callback = statistics_proxy_.get();
2334*d9f75844SAndroid Build Coastguard Worker   RTCPReportBlock report_block;
2335*d9f75844SAndroid Build Coastguard Worker   report_block.source_ssrc = config_.rtp.ssrcs[0];
2336*d9f75844SAndroid Build Coastguard Worker   ReportBlockData data;
2337*d9f75844SAndroid Build Coastguard Worker   data.SetReportBlock(report_block, 0);
2338*d9f75844SAndroid Build Coastguard Worker   rtcp_callback->OnReportBlockDataUpdated(data);
2339*d9f75844SAndroid Build Coastguard Worker 
2340*d9f75844SAndroid Build Coastguard Worker   // Report stats for second SSRC to make sure it's not outdated along with the
2341*d9f75844SAndroid Build Coastguard Worker   // first SSRC.
2342*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2343*d9f75844SAndroid Build Coastguard Worker 
2344*d9f75844SAndroid Build Coastguard Worker   // Forward 1 ms, reach timeout, substream 0 should have no resolution
2345*d9f75844SAndroid Build Coastguard Worker   // reported, but substream 1 should.
2346*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(1);
2347*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
2348*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].width);
2349*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[0]].height);
2350*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[1]].width);
2351*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[1]].height);
2352*d9f75844SAndroid Build Coastguard Worker }
2353*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ClearsResolutionFromInactiveSsrcs)2354*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ClearsResolutionFromInactiveSsrcs) {
2355*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedWidth = 123;
2356*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedHeight = 81;
2357*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2358*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kEncodedWidth;
2359*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kEncodedHeight;
2360*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2361*d9f75844SAndroid Build Coastguard Worker 
2362*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
2363*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP8;
2364*d9f75844SAndroid Build Coastguard Worker 
2365*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2366*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(1);
2367*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2368*d9f75844SAndroid Build Coastguard Worker 
2369*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
2370*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2371*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
2372*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
2373*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].width);
2374*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].height);
2375*d9f75844SAndroid Build Coastguard Worker }
2376*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ClearsBitratesFromInactiveSsrcs)2377*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ClearsBitratesFromInactiveSsrcs) {
2378*d9f75844SAndroid Build Coastguard Worker   uint32_t bitrate = 42;
2379*d9f75844SAndroid Build Coastguard Worker   BitrateStatisticsObserver* observer = statistics_proxy_.get();
2380*d9f75844SAndroid Build Coastguard Worker   observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[0]);
2381*d9f75844SAndroid Build Coastguard Worker   observer->Notify(bitrate, bitrate, config_.rtp.ssrcs[1]);
2382*d9f75844SAndroid Build Coastguard Worker 
2383*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnInactiveSsrc(config_.rtp.ssrcs[1]);
2384*d9f75844SAndroid Build Coastguard Worker 
2385*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2386*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<int>(bitrate),
2387*d9f75844SAndroid Build Coastguard Worker             stats.substreams[config_.rtp.ssrcs[0]].total_bitrate_bps);
2388*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<int>(bitrate),
2389*d9f75844SAndroid Build Coastguard Worker             stats.substreams[config_.rtp.ssrcs[0]].retransmit_bitrate_bps);
2390*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].total_bitrate_bps);
2391*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0, stats.substreams[config_.rtp.ssrcs[1]].retransmit_bitrate_bps);
2392*d9f75844SAndroid Build Coastguard Worker }
2393*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ResetsRtcpCountersOnContentChange)2394*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ResetsRtcpCountersOnContentChange) {
2395*d9f75844SAndroid Build Coastguard Worker   RtcpPacketTypeCounterObserver* proxy =
2396*d9f75844SAndroid Build Coastguard Worker       static_cast<RtcpPacketTypeCounterObserver*>(statistics_proxy_.get());
2397*d9f75844SAndroid Build Coastguard Worker   RtcpPacketTypeCounter counters;
2398*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2399*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2400*d9f75844SAndroid Build Coastguard Worker 
2401*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
2402*d9f75844SAndroid Build Coastguard Worker 
2403*d9f75844SAndroid Build Coastguard Worker   counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
2404*d9f75844SAndroid Build Coastguard Worker   counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
2405*d9f75844SAndroid Build Coastguard Worker   counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
2406*d9f75844SAndroid Build Coastguard Worker   counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
2407*d9f75844SAndroid Build Coastguard Worker   counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
2408*d9f75844SAndroid Build Coastguard Worker 
2409*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2410*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2411*d9f75844SAndroid Build Coastguard Worker 
2412*d9f75844SAndroid Build Coastguard Worker   // Changing content type causes histograms to be reported.
2413*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2414*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kScreen;
2415*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {});
2416*d9f75844SAndroid Build Coastguard Worker 
2417*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2418*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.NackPacketsReceivedPerMinute"));
2419*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2420*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.FirPacketsReceivedPerMinute"));
2421*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2422*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.PliPacketsReceivedPerMinute"));
2423*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2424*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.UniqueNackRequestsReceivedInPercent"));
2425*d9f75844SAndroid Build Coastguard Worker 
2426*d9f75844SAndroid Build Coastguard Worker   const int kRate = 60 * 2;  // Packets per minute with two streams.
2427*d9f75844SAndroid Build Coastguard Worker 
2428*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2429*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.NackPacketsReceivedPerMinute",
2430*d9f75844SAndroid Build Coastguard Worker                             1 * kRate));
2431*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2432*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.FirPacketsReceivedPerMinute",
2433*d9f75844SAndroid Build Coastguard Worker                             2 * kRate));
2434*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2435*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.PliPacketsReceivedPerMinute",
2436*d9f75844SAndroid Build Coastguard Worker                             3 * kRate));
2437*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2438*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.UniqueNackRequestsReceivedInPercent",
2439*d9f75844SAndroid Build Coastguard Worker                             4 * 100 / 5));
2440*d9f75844SAndroid Build Coastguard Worker 
2441*d9f75844SAndroid Build Coastguard Worker   // New start time but same counter values.
2442*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2443*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2444*d9f75844SAndroid Build Coastguard Worker 
2445*d9f75844SAndroid Build Coastguard Worker   fake_clock_.AdvanceTimeMilliseconds(1000 * metrics::kMinRunTimeInSeconds);
2446*d9f75844SAndroid Build Coastguard Worker 
2447*d9f75844SAndroid Build Coastguard Worker   counters.nack_packets += 1 * metrics::kMinRunTimeInSeconds;
2448*d9f75844SAndroid Build Coastguard Worker   counters.fir_packets += 2 * metrics::kMinRunTimeInSeconds;
2449*d9f75844SAndroid Build Coastguard Worker   counters.pli_packets += 3 * metrics::kMinRunTimeInSeconds;
2450*d9f75844SAndroid Build Coastguard Worker   counters.unique_nack_requests += 4 * metrics::kMinRunTimeInSeconds;
2451*d9f75844SAndroid Build Coastguard Worker   counters.nack_requests += 5 * metrics::kMinRunTimeInSeconds;
2452*d9f75844SAndroid Build Coastguard Worker 
2453*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kFirstSsrc, counters);
2454*d9f75844SAndroid Build Coastguard Worker   proxy->RtcpPacketTypesCounterUpdated(kSecondSsrc, counters);
2455*d9f75844SAndroid Build Coastguard Worker 
2456*d9f75844SAndroid Build Coastguard Worker   SetUp();  // Reset stats proxy also causes histograms to be reported.
2457*d9f75844SAndroid Build Coastguard Worker 
2458*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2459*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(
2460*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute"));
2461*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2462*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(
2463*d9f75844SAndroid Build Coastguard Worker                        "WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute"));
2464*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2465*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(
2466*d9f75844SAndroid Build Coastguard Worker                        "WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute"));
2467*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2468*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(
2469*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent"));
2470*d9f75844SAndroid Build Coastguard Worker 
2471*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2472*d9f75844SAndroid Build Coastguard Worker       1,
2473*d9f75844SAndroid Build Coastguard Worker       metrics::NumEvents(
2474*d9f75844SAndroid Build Coastguard Worker           "WebRTC.Video.Screenshare.NackPacketsReceivedPerMinute", 1 * kRate));
2475*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2476*d9f75844SAndroid Build Coastguard Worker       1,
2477*d9f75844SAndroid Build Coastguard Worker       metrics::NumEvents("WebRTC.Video.Screenshare.FirPacketsReceivedPerMinute",
2478*d9f75844SAndroid Build Coastguard Worker                          2 * kRate));
2479*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2480*d9f75844SAndroid Build Coastguard Worker       1,
2481*d9f75844SAndroid Build Coastguard Worker       metrics::NumEvents("WebRTC.Video.Screenshare.PliPacketsReceivedPerMinute",
2482*d9f75844SAndroid Build Coastguard Worker                          3 * kRate));
2483*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2484*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(
2485*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.UniqueNackRequestsReceivedInPercent",
2486*d9f75844SAndroid Build Coastguard Worker              4 * 100 / 5));
2487*d9f75844SAndroid Build Coastguard Worker }
2488*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsIsRtx)2489*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsIsRtx) {
2490*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2491*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2492*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2493*d9f75844SAndroid Build Coastguard Worker   proxy->DataCountersUpdated(counters, kFirstSsrc);
2494*d9f75844SAndroid Build Coastguard Worker   proxy->DataCountersUpdated(counters, kFirstRtxSsrc);
2495*d9f75844SAndroid Build Coastguard Worker 
2496*d9f75844SAndroid Build Coastguard Worker   EXPECT_NE(GetStreamStats(kFirstSsrc).type,
2497*d9f75844SAndroid Build Coastguard Worker             VideoSendStream::StreamStats::StreamType::kRtx);
2498*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFirstSsrc).referenced_media_ssrc, absl::nullopt);
2499*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFirstRtxSsrc).type,
2500*d9f75844SAndroid Build Coastguard Worker             VideoSendStream::StreamStats::StreamType::kRtx);
2501*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFirstRtxSsrc).referenced_media_ssrc, kFirstSsrc);
2502*d9f75844SAndroid Build Coastguard Worker }
2503*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsIsFlexFec)2504*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsIsFlexFec) {
2505*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
2506*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
2507*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, GetTestConfigWithFlexFec(),
2508*d9f75844SAndroid Build Coastguard Worker       VideoEncoderConfig::ContentType::kRealtimeVideo, field_trials));
2509*d9f75844SAndroid Build Coastguard Worker 
2510*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2511*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2512*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2513*d9f75844SAndroid Build Coastguard Worker   proxy->DataCountersUpdated(counters, kFirstSsrc);
2514*d9f75844SAndroid Build Coastguard Worker   proxy->DataCountersUpdated(counters, kFlexFecSsrc);
2515*d9f75844SAndroid Build Coastguard Worker 
2516*d9f75844SAndroid Build Coastguard Worker   EXPECT_NE(GetStreamStats(kFirstSsrc).type,
2517*d9f75844SAndroid Build Coastguard Worker             VideoSendStream::StreamStats::StreamType::kFlexfec);
2518*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFirstSsrc).referenced_media_ssrc, absl::nullopt);
2519*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFlexFecSsrc).type,
2520*d9f75844SAndroid Build Coastguard Worker             VideoSendStream::StreamStats::StreamType::kFlexfec);
2521*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(GetStreamStats(kFlexFecSsrc).referenced_media_ssrc, kFirstSsrc);
2522*d9f75844SAndroid Build Coastguard Worker }
2523*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,SendBitratesAreReportedWithFlexFecEnabled)2524*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, SendBitratesAreReportedWithFlexFecEnabled) {
2525*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
2526*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
2527*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, GetTestConfigWithFlexFec(),
2528*d9f75844SAndroid Build Coastguard Worker       VideoEncoderConfig::ContentType::kRealtimeVideo, field_trials));
2529*d9f75844SAndroid Build Coastguard Worker 
2530*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2531*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2532*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2533*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters rtx_counters;
2534*d9f75844SAndroid Build Coastguard Worker 
2535*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2536*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2537*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2538*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2539*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2540*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.padding_bytes += 1000;
2541*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2542*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.packets += 2;
2543*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.header_bytes += 25;
2544*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.padding_bytes += 100;
2545*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.payload_bytes += 250;
2546*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2547*d9f75844SAndroid Build Coastguard Worker     rtx_counters.transmitted = counters.transmitted;
2548*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2549*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2550*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2551*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kSecondSsrc);
2552*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2553*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2554*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFlexFecSsrc);
2555*d9f75844SAndroid Build Coastguard Worker   }
2556*d9f75844SAndroid Build Coastguard Worker 
2557*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2558*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec  = 56 kbps
2559*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
2560*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
2561*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec  = 28 kbps
2562*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2563*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2564*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
2565*d9f75844SAndroid Build Coastguard Worker   // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec  = 12 kbps
2566*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2567*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
2568*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2569*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
2570*d9f75844SAndroid Build Coastguard Worker   // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
2571*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2572*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
2573*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2574*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
2575*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2576*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2577*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2578*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
2579*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2580*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2581*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
2582*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2583*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
2584*d9f75844SAndroid Build Coastguard Worker }
2585*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,ResetsRtpCountersOnContentChange)2586*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, ResetsRtpCountersOnContentChange) {
2587*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2588*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2589*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2590*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters rtx_counters;
2591*d9f75844SAndroid Build Coastguard Worker   counters.first_packet_time_ms = fake_clock_.TimeInMilliseconds();
2592*d9f75844SAndroid Build Coastguard Worker 
2593*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2594*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2595*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2596*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2597*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2598*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.padding_bytes += 1000;
2599*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2600*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.packets += 2;
2601*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.header_bytes += 25;
2602*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.padding_bytes += 100;
2603*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.payload_bytes += 250;
2604*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2605*d9f75844SAndroid Build Coastguard Worker     rtx_counters.transmitted = counters.transmitted;
2606*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2607*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2608*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2609*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kSecondSsrc);
2610*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2611*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2612*d9f75844SAndroid Build Coastguard Worker   }
2613*d9f75844SAndroid Build Coastguard Worker 
2614*d9f75844SAndroid Build Coastguard Worker   // Changing content type causes histograms to be reported.
2615*d9f75844SAndroid Build Coastguard Worker   VideoEncoderConfig config;
2616*d9f75844SAndroid Build Coastguard Worker   config.content_type = VideoEncoderConfig::ContentType::kScreen;
2617*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderReconfigured(config, {});
2618*d9f75844SAndroid Build Coastguard Worker 
2619*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec  = 56 kbps
2620*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.BitrateSentInKbps"));
2621*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumEvents("WebRTC.Video.BitrateSentInKbps", 56));
2622*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec  = 28 kbps
2623*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2624*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2625*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 28));
2626*d9f75844SAndroid Build Coastguard Worker   // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec  = 12 kbps
2627*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2628*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples("WebRTC.Video.MediaBitrateSentInKbps"));
2629*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2630*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.MediaBitrateSentInKbps", 12));
2631*d9f75844SAndroid Build Coastguard Worker   // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
2632*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2633*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.PaddingBitrateSentInKbps"));
2634*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2635*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.PaddingBitrateSentInKbps", 16));
2636*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2637*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2638*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2639*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 3));
2640*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2641*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2642*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.RetransmittedBitrateSentInKbps"));
2643*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2644*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.RetransmittedBitrateSentInKbps", 3));
2645*d9f75844SAndroid Build Coastguard Worker 
2646*d9f75844SAndroid Build Coastguard Worker   // New metric counters but same data counters.
2647*d9f75844SAndroid Build Coastguard Worker   // Double counter values, this should result in the same counts as before but
2648*d9f75844SAndroid Build Coastguard Worker   // with new histogram names.
2649*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2650*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2651*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2652*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.padding_bytes += 1000;
2653*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2654*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.packets += 2;
2655*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.header_bytes += 25;
2656*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.padding_bytes += 100;
2657*d9f75844SAndroid Build Coastguard Worker     counters.retransmitted.payload_bytes += 250;
2658*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2659*d9f75844SAndroid Build Coastguard Worker     rtx_counters.transmitted = counters.transmitted;
2660*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2661*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2662*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2663*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kSecondSsrc);
2664*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kFirstRtxSsrc);
2665*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(rtx_counters, kSecondRtxSsrc);
2666*d9f75844SAndroid Build Coastguard Worker   }
2667*d9f75844SAndroid Build Coastguard Worker 
2668*d9f75844SAndroid Build Coastguard Worker   // Reset stats proxy also causes histograms to be reported.
2669*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2670*d9f75844SAndroid Build Coastguard Worker 
2671*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 4 / 2 sec = 7000 bytes / sec  = 56 kbps
2672*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2673*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.Screenshare.BitrateSentInKbps"));
2674*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2675*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Screenshare.BitrateSentInKbps", 56));
2676*d9f75844SAndroid Build Coastguard Worker   // Interval: 3500 bytes * 2 / 2 sec = 3500 bytes / sec  = 28 kbps
2677*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2678*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.Screenshare.RtxBitrateSentInKbps"));
2679*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumEvents(
2680*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.Screenshare.RtxBitrateSentInKbps", 28));
2681*d9f75844SAndroid Build Coastguard Worker   // Interval: (2000 - 2 * 250) bytes / 2 sec = 1500 bytes / sec  = 12 kbps
2682*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2683*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.Screenshare.MediaBitrateSentInKbps"));
2684*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2685*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Screenshare.MediaBitrateSentInKbps",
2686*d9f75844SAndroid Build Coastguard Worker                             12));
2687*d9f75844SAndroid Build Coastguard Worker   // Interval: 1000 bytes * 4 / 2 sec = 2000 bytes / sec = 16 kbps
2688*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples(
2689*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.Screenshare.PaddingBitrateSentInKbps"));
2690*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2691*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents("WebRTC.Video.Screenshare.PaddingBitrateSentInKbps",
2692*d9f75844SAndroid Build Coastguard Worker                             16));
2693*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2694*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2695*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples("WebRTC.Video.Screenshare.FecBitrateSentInKbps"));
2696*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumEvents(
2697*d9f75844SAndroid Build Coastguard Worker                           "WebRTC.Video.Screenshare.FecBitrateSentInKbps", 3));
2698*d9f75844SAndroid Build Coastguard Worker   // Interval: 375 bytes * 2 / 2 sec = 375 bytes / sec = 3 kbps
2699*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2700*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(
2701*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps"));
2702*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2703*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(
2704*d9f75844SAndroid Build Coastguard Worker              "WebRTC.Video.Screenshare.RetransmittedBitrateSentInKbps", 3));
2705*d9f75844SAndroid Build Coastguard Worker }
2706*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,RtxBitrateIsZeroWhenEnabledAndNoRtxDataIsSent)2707*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, RtxBitrateIsZeroWhenEnabledAndNoRtxDataIsSent) {
2708*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2709*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2710*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2711*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters rtx_counters;
2712*d9f75844SAndroid Build Coastguard Worker 
2713*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2714*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2715*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2716*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2717*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2718*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2719*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2720*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2721*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2722*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2723*d9f75844SAndroid Build Coastguard Worker   }
2724*d9f75844SAndroid Build Coastguard Worker 
2725*d9f75844SAndroid Build Coastguard Worker   // RTX enabled. No data sent over RTX.
2726*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2727*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2728*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2729*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.RtxBitrateSentInKbps", 0));
2730*d9f75844SAndroid Build Coastguard Worker }
2731*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,RtxBitrateNotReportedWhenNotEnabled)2732*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, RtxBitrateNotReportedWhenNotEnabled) {
2733*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
2734*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config config(nullptr);
2735*d9f75844SAndroid Build Coastguard Worker   config.rtp.ssrcs.push_back(kFirstSsrc);  // RTX not configured.
2736*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
2737*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo,
2738*d9f75844SAndroid Build Coastguard Worker       field_trials));
2739*d9f75844SAndroid Build Coastguard Worker 
2740*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2741*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2742*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2743*d9f75844SAndroid Build Coastguard Worker 
2744*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2745*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2746*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2747*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2748*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2749*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2750*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2751*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2752*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2753*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2754*d9f75844SAndroid Build Coastguard Worker   }
2755*d9f75844SAndroid Build Coastguard Worker 
2756*d9f75844SAndroid Build Coastguard Worker   // RTX not enabled.
2757*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2758*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.RtxBitrateSentInKbps"));
2759*d9f75844SAndroid Build Coastguard Worker }
2760*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,FecBitrateIsZeroWhenEnabledAndNoFecDataIsSent)2761*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, FecBitrateIsZeroWhenEnabledAndNoFecDataIsSent) {
2762*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2763*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2764*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2765*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters rtx_counters;
2766*d9f75844SAndroid Build Coastguard Worker 
2767*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2768*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2769*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2770*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2771*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2772*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2773*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2774*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2775*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2776*d9f75844SAndroid Build Coastguard Worker   }
2777*d9f75844SAndroid Build Coastguard Worker 
2778*d9f75844SAndroid Build Coastguard Worker   // FEC enabled. No FEC data sent.
2779*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2780*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2781*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2782*d9f75844SAndroid Build Coastguard Worker                    metrics::NumEvents("WebRTC.Video.FecBitrateSentInKbps", 0));
2783*d9f75844SAndroid Build Coastguard Worker }
2784*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,FecBitrateNotReportedWhenNotEnabled)2785*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, FecBitrateNotReportedWhenNotEnabled) {
2786*d9f75844SAndroid Build Coastguard Worker   test::ScopedKeyValueConfig field_trials;
2787*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Config config(nullptr);
2788*d9f75844SAndroid Build Coastguard Worker   config.rtp.ssrcs.push_back(kFirstSsrc);  // FEC not configured.
2789*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset(new SendStatisticsProxy(
2790*d9f75844SAndroid Build Coastguard Worker       &fake_clock_, config, VideoEncoderConfig::ContentType::kRealtimeVideo,
2791*d9f75844SAndroid Build Coastguard Worker       field_trials));
2792*d9f75844SAndroid Build Coastguard Worker 
2793*d9f75844SAndroid Build Coastguard Worker   StreamDataCountersCallback* proxy =
2794*d9f75844SAndroid Build Coastguard Worker       static_cast<StreamDataCountersCallback*>(statistics_proxy_.get());
2795*d9f75844SAndroid Build Coastguard Worker   StreamDataCounters counters;
2796*d9f75844SAndroid Build Coastguard Worker 
2797*d9f75844SAndroid Build Coastguard Worker   const int kMinRequiredPeriodSamples = 8;
2798*d9f75844SAndroid Build Coastguard Worker   const int kPeriodIntervalMs = 2000;
2799*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kMinRequiredPeriodSamples; ++i) {
2800*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.packets += 20;
2801*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.header_bytes += 500;
2802*d9f75844SAndroid Build Coastguard Worker     counters.transmitted.payload_bytes += 2000;
2803*d9f75844SAndroid Build Coastguard Worker     counters.fec = counters.retransmitted;
2804*d9f75844SAndroid Build Coastguard Worker     // Advance one interval and update counters.
2805*d9f75844SAndroid Build Coastguard Worker     fake_clock_.AdvanceTimeMilliseconds(kPeriodIntervalMs);
2806*d9f75844SAndroid Build Coastguard Worker     proxy->DataCountersUpdated(counters, kFirstSsrc);
2807*d9f75844SAndroid Build Coastguard Worker   }
2808*d9f75844SAndroid Build Coastguard Worker 
2809*d9f75844SAndroid Build Coastguard Worker   // FEC not enabled.
2810*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2811*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0, metrics::NumSamples("WebRTC.Video.FecBitrateSentInKbps"));
2812*d9f75844SAndroid Build Coastguard Worker }
2813*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,GetStatsReportsEncoderImplementationName)2814*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, GetStatsReportsEncoderImplementationName) {
2815*d9f75844SAndroid Build Coastguard Worker   const std::string kName = "encoderName";
2816*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnEncoderImplementationChanged(EncoderImplementation{
2817*d9f75844SAndroid Build Coastguard Worker       .name = kName,
2818*d9f75844SAndroid Build Coastguard Worker       .is_hardware_accelerated = true,
2819*d9f75844SAndroid Build Coastguard Worker   });
2820*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kName, statistics_proxy_->GetStats().encoder_implementation_name);
2821*d9f75844SAndroid Build Coastguard Worker   EXPECT_THAT(statistics_proxy_->GetStats().power_efficient_encoder,
2822*d9f75844SAndroid Build Coastguard Worker               ::testing::IsTrue());
2823*d9f75844SAndroid Build Coastguard Worker }
2824*d9f75844SAndroid Build Coastguard Worker 
TEST_F(SendStatisticsProxyTest,Vp9SvcLowSpatialLayerDoesNotUpdateResolution)2825*d9f75844SAndroid Build Coastguard Worker TEST_F(SendStatisticsProxyTest, Vp9SvcLowSpatialLayerDoesNotUpdateResolution) {
2826*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedWidth = 123;
2827*d9f75844SAndroid Build Coastguard Worker   static const int kEncodedHeight = 81;
2828*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image;
2829*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kEncodedWidth;
2830*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kEncodedHeight;
2831*d9f75844SAndroid Build Coastguard Worker   encoded_image.SetSpatialIndex(0);
2832*d9f75844SAndroid Build Coastguard Worker 
2833*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info;
2834*d9f75844SAndroid Build Coastguard Worker   codec_info.codecType = kVideoCodecVP9;
2835*d9f75844SAndroid Build Coastguard Worker 
2836*d9f75844SAndroid Build Coastguard Worker   // For first picture, it is expected that low layer updates resolution.
2837*d9f75844SAndroid Build Coastguard Worker   codec_info.end_of_picture = false;
2838*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2839*d9f75844SAndroid Build Coastguard Worker   VideoSendStream::Stats stats = statistics_proxy_->GetStats();
2840*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth, stats.substreams[config_.rtp.ssrcs[0]].width);
2841*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight, stats.substreams[config_.rtp.ssrcs[0]].height);
2842*d9f75844SAndroid Build Coastguard Worker 
2843*d9f75844SAndroid Build Coastguard Worker   // Top layer updates resolution.
2844*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kEncodedWidth * 2;
2845*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kEncodedHeight * 2;
2846*d9f75844SAndroid Build Coastguard Worker   codec_info.end_of_picture = true;
2847*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2848*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
2849*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth * 2, stats.substreams[config_.rtp.ssrcs[0]].width);
2850*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight * 2, stats.substreams[config_.rtp.ssrcs[0]].height);
2851*d9f75844SAndroid Build Coastguard Worker 
2852*d9f75844SAndroid Build Coastguard Worker   // Low layer of next frame doesn't update resolution.
2853*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedWidth = kEncodedWidth;
2854*d9f75844SAndroid Build Coastguard Worker   encoded_image._encodedHeight = kEncodedHeight;
2855*d9f75844SAndroid Build Coastguard Worker   codec_info.end_of_picture = false;
2856*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnSendEncodedImage(encoded_image, &codec_info);
2857*d9f75844SAndroid Build Coastguard Worker   stats = statistics_proxy_->GetStats();
2858*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedWidth * 2, stats.substreams[config_.rtp.ssrcs[0]].width);
2859*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kEncodedHeight * 2, stats.substreams[config_.rtp.ssrcs[0]].height);
2860*d9f75844SAndroid Build Coastguard Worker }
2861*d9f75844SAndroid Build Coastguard Worker 
2862*d9f75844SAndroid Build Coastguard Worker class ForcedFallbackTest : public SendStatisticsProxyTest {
2863*d9f75844SAndroid Build Coastguard Worker  public:
ForcedFallbackTest(const std::string & field_trials)2864*d9f75844SAndroid Build Coastguard Worker   explicit ForcedFallbackTest(const std::string& field_trials)
2865*d9f75844SAndroid Build Coastguard Worker       : SendStatisticsProxyTest(field_trials) {
2866*d9f75844SAndroid Build Coastguard Worker     codec_info_.codecType = kVideoCodecVP8;
2867*d9f75844SAndroid Build Coastguard Worker     codec_info_.codecSpecific.VP8.temporalIdx = 0;
2868*d9f75844SAndroid Build Coastguard Worker     encoded_image_._encodedWidth = kWidth;
2869*d9f75844SAndroid Build Coastguard Worker     encoded_image_._encodedHeight = kHeight;
2870*d9f75844SAndroid Build Coastguard Worker     encoded_image_.SetSpatialIndex(0);
2871*d9f75844SAndroid Build Coastguard Worker   }
2872*d9f75844SAndroid Build Coastguard Worker 
~ForcedFallbackTest()2873*d9f75844SAndroid Build Coastguard Worker   ~ForcedFallbackTest() override {}
2874*d9f75844SAndroid Build Coastguard Worker 
2875*d9f75844SAndroid Build Coastguard Worker  protected:
InsertEncodedFrames(int num_frames,int interval_ms)2876*d9f75844SAndroid Build Coastguard Worker   void InsertEncodedFrames(int num_frames, int interval_ms) {
2877*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnEncoderImplementationChanged(
2878*d9f75844SAndroid Build Coastguard Worker         {.name = codec_name_, .is_hardware_accelerated = false});
2879*d9f75844SAndroid Build Coastguard Worker 
2880*d9f75844SAndroid Build Coastguard Worker     // First frame is not updating stats, insert initial frame.
2881*d9f75844SAndroid Build Coastguard Worker     if (statistics_proxy_->GetStats().frames_encoded == 0) {
2882*d9f75844SAndroid Build Coastguard Worker       statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2883*d9f75844SAndroid Build Coastguard Worker     }
2884*d9f75844SAndroid Build Coastguard Worker     for (int i = 0; i < num_frames; ++i) {
2885*d9f75844SAndroid Build Coastguard Worker       statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2886*d9f75844SAndroid Build Coastguard Worker       fake_clock_.AdvanceTimeMilliseconds(interval_ms);
2887*d9f75844SAndroid Build Coastguard Worker     }
2888*d9f75844SAndroid Build Coastguard Worker     // Add frame to include last time interval.
2889*d9f75844SAndroid Build Coastguard Worker     statistics_proxy_->OnSendEncodedImage(encoded_image_, &codec_info_);
2890*d9f75844SAndroid Build Coastguard Worker   }
2891*d9f75844SAndroid Build Coastguard Worker 
2892*d9f75844SAndroid Build Coastguard Worker   EncodedImage encoded_image_;
2893*d9f75844SAndroid Build Coastguard Worker   CodecSpecificInfo codec_info_;
2894*d9f75844SAndroid Build Coastguard Worker   std::string codec_name_;
2895*d9f75844SAndroid Build Coastguard Worker   const std::string kPrefix = "WebRTC.Video.Encoder.ForcedSw";
2896*d9f75844SAndroid Build Coastguard Worker   const int kFrameIntervalMs = 1000;
2897*d9f75844SAndroid Build Coastguard Worker   const int kMinFrames = 20;  // Min run time 20 sec.
2898*d9f75844SAndroid Build Coastguard Worker };
2899*d9f75844SAndroid Build Coastguard Worker 
2900*d9f75844SAndroid Build Coastguard Worker class ForcedFallbackDisabled : public ForcedFallbackTest {
2901*d9f75844SAndroid Build Coastguard Worker  public:
ForcedFallbackDisabled()2902*d9f75844SAndroid Build Coastguard Worker   ForcedFallbackDisabled()
2903*d9f75844SAndroid Build Coastguard Worker       : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Disabled-1," +
2904*d9f75844SAndroid Build Coastguard Worker                            std::to_string(kWidth * kHeight) + ",3/") {}
2905*d9f75844SAndroid Build Coastguard Worker };
2906*d9f75844SAndroid Build Coastguard Worker 
2907*d9f75844SAndroid Build Coastguard Worker class ForcedFallbackEnabled : public ForcedFallbackTest {
2908*d9f75844SAndroid Build Coastguard Worker  public:
ForcedFallbackEnabled()2909*d9f75844SAndroid Build Coastguard Worker   ForcedFallbackEnabled()
2910*d9f75844SAndroid Build Coastguard Worker       : ForcedFallbackTest("WebRTC-VP8-Forced-Fallback-Encoder-v2/Enabled-1," +
2911*d9f75844SAndroid Build Coastguard Worker                            std::to_string(kWidth * kHeight) + ",3/") {}
2912*d9f75844SAndroid Build Coastguard Worker };
2913*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,StatsNotUpdatedIfMinRunTimeHasNotPassed)2914*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, StatsNotUpdatedIfMinRunTimeHasNotPassed) {
2915*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs - 1);
2916*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2917*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
2918*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2919*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2920*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2921*d9f75844SAndroid Build Coastguard Worker }
2922*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,StatsUpdated)2923*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, StatsUpdated) {
2924*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2925*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2926*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2927*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
2928*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2929*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2930*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 0));
2931*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2932*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2933*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2934*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 0));
2935*d9f75844SAndroid Build Coastguard Worker }
2936*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,StatsNotUpdatedIfNotVp8)2937*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, StatsNotUpdatedIfNotVp8) {
2938*d9f75844SAndroid Build Coastguard Worker   codec_info_.codecType = kVideoCodecVP9;
2939*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2940*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2941*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
2942*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2943*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2944*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2945*d9f75844SAndroid Build Coastguard Worker }
2946*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,StatsNotUpdatedForTemporalLayers)2947*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, StatsNotUpdatedForTemporalLayers) {
2948*d9f75844SAndroid Build Coastguard Worker   codec_info_.codecSpecific.VP8.temporalIdx = 1;
2949*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2950*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2951*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
2952*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2953*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2954*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2955*d9f75844SAndroid Build Coastguard Worker }
2956*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,StatsNotUpdatedForSimulcast)2957*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, StatsNotUpdatedForSimulcast) {
2958*d9f75844SAndroid Build Coastguard Worker   encoded_image_.SetSpatialIndex(1);
2959*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2960*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2961*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
2962*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2963*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2964*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2965*d9f75844SAndroid Build Coastguard Worker }
2966*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackDisabled,StatsNotUpdatedIfNoFieldTrial)2967*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackDisabled, StatsNotUpdatedIfNoFieldTrial) {
2968*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
2969*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
2970*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
2971*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
2972*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
2973*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
2974*d9f75844SAndroid Build Coastguard Worker }
2975*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackDisabled,EnteredLowResolutionSetIfAtMaxPixels)2976*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackDisabled, EnteredLowResolutionSetIfAtMaxPixels) {
2977*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
2978*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
2979*d9f75844SAndroid Build Coastguard Worker }
2980*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,EnteredLowResolutionNotSetIfNotLibvpx)2981*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, EnteredLowResolutionNotSetIfNotLibvpx) {
2982*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
2983*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2984*d9f75844SAndroid Build Coastguard Worker }
2985*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,EnteredLowResolutionSetIfLibvpx)2986*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, EnteredLowResolutionSetIfLibvpx) {
2987*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
2988*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
2989*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
2990*d9f75844SAndroid Build Coastguard Worker }
2991*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackDisabled,EnteredLowResolutionNotSetIfAboveMaxPixels)2992*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfAboveMaxPixels) {
2993*d9f75844SAndroid Build Coastguard Worker   encoded_image_._encodedWidth = kWidth + 1;
2994*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
2995*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
2996*d9f75844SAndroid Build Coastguard Worker }
2997*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackDisabled,EnteredLowResolutionNotSetIfLibvpx)2998*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackDisabled, EnteredLowResolutionNotSetIfLibvpx) {
2999*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3000*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
3001*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
3002*d9f75844SAndroid Build Coastguard Worker }
3003*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackDisabled,EnteredLowResolutionSetIfOnMinPixelLimitReached)3004*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackDisabled,
3005*d9f75844SAndroid Build Coastguard Worker        EnteredLowResolutionSetIfOnMinPixelLimitReached) {
3006*d9f75844SAndroid Build Coastguard Worker   encoded_image_._encodedWidth = kWidth + 1;
3007*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_->OnMinPixelLimitReached();
3008*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(1, kFrameIntervalMs);
3009*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3010*d9f75844SAndroid Build Coastguard Worker }
3011*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,OneFallbackEvent)3012*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, OneFallbackEvent) {
3013*d9f75844SAndroid Build Coastguard Worker   // One change. Video: 20000 ms, fallback: 5000 ms (25%).
3014*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
3015*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(15, 1000);
3016*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
3017*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3018*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(5, 1000);
3019*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3020*d9f75844SAndroid Build Coastguard Worker 
3021*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
3022*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
3023*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
3024*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3025*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 25));
3026*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3027*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
3028*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3029*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 3));
3030*d9f75844SAndroid Build Coastguard Worker }
3031*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,ThreeFallbackEvents)3032*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, ThreeFallbackEvents) {
3033*d9f75844SAndroid Build Coastguard Worker   codec_info_.codecSpecific.VP8.temporalIdx = kNoTemporalIdx;  // Should work.
3034*d9f75844SAndroid Build Coastguard Worker   const int kMaxFrameDiffMs = 2000;
3035*d9f75844SAndroid Build Coastguard Worker 
3036*d9f75844SAndroid Build Coastguard Worker   // Three changes. Video: 60000 ms, fallback: 15000 ms (25%).
3037*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(10, 1000);
3038*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
3039*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3040*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(15, 500);
3041*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3042*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "notlibvpx";
3043*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(20, 1000);
3044*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(3, kMaxFrameDiffMs);  // Should not be included.
3045*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(10, 1000);
3046*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3047*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "notlibvpx2";
3048*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(10, 500);
3049*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3050*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3051*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(15, 500);
3052*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3053*d9f75844SAndroid Build Coastguard Worker 
3054*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
3055*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
3056*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
3057*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3058*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackTimeInPercent.Vp8", 25));
3059*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3060*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
3061*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3062*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumEvents(kPrefix + "FallbackChangesPerMinute.Vp8", 3));
3063*d9f75844SAndroid Build Coastguard Worker }
3064*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,NoFallbackIfAboveMaxPixels)3065*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, NoFallbackIfAboveMaxPixels) {
3066*d9f75844SAndroid Build Coastguard Worker   encoded_image_._encodedWidth = kWidth + 1;
3067*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3068*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
3069*d9f75844SAndroid Build Coastguard Worker 
3070*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(statistics_proxy_->GetStats().has_entered_low_resolution);
3071*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
3072*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(0,
3073*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
3074*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3075*d9f75844SAndroid Build Coastguard Worker       0, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
3076*d9f75844SAndroid Build Coastguard Worker }
3077*d9f75844SAndroid Build Coastguard Worker 
TEST_F(ForcedFallbackEnabled,FallbackIfAtMaxPixels)3078*d9f75844SAndroid Build Coastguard Worker TEST_F(ForcedFallbackEnabled, FallbackIfAtMaxPixels) {
3079*d9f75844SAndroid Build Coastguard Worker   encoded_image_._encodedWidth = kWidth;
3080*d9f75844SAndroid Build Coastguard Worker   codec_name_ = "libvpx";
3081*d9f75844SAndroid Build Coastguard Worker   InsertEncodedFrames(kMinFrames, kFrameIntervalMs);
3082*d9f75844SAndroid Build Coastguard Worker 
3083*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(statistics_proxy_->GetStats().has_entered_low_resolution);
3084*d9f75844SAndroid Build Coastguard Worker   statistics_proxy_.reset();
3085*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(1,
3086*d9f75844SAndroid Build Coastguard Worker                    metrics::NumSamples(kPrefix + "FallbackTimeInPercent.Vp8"));
3087*d9f75844SAndroid Build Coastguard Worker   EXPECT_METRIC_EQ(
3088*d9f75844SAndroid Build Coastguard Worker       1, metrics::NumSamples(kPrefix + "FallbackChangesPerMinute.Vp8"));
3089*d9f75844SAndroid Build Coastguard Worker }
3090*d9f75844SAndroid Build Coastguard Worker 
3091*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
3092