xref: /aosp_15_r20/external/webrtc/call/adaptation/video_stream_adapter_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "call/adaptation/video_stream_adapter.h"
12 
13 #include <string>
14 #include <utility>
15 
16 #include "absl/types/optional.h"
17 #include "api/scoped_refptr.h"
18 #include "api/video/video_adaptation_reason.h"
19 #include "api/video_codecs/video_codec.h"
20 #include "api/video_codecs/video_encoder.h"
21 #include "call/adaptation/adaptation_constraint.h"
22 #include "call/adaptation/encoder_settings.h"
23 #include "call/adaptation/test/fake_frame_rate_provider.h"
24 #include "call/adaptation/test/fake_resource.h"
25 #include "call/adaptation/test/fake_video_stream_input_state_provider.h"
26 #include "call/adaptation/video_source_restrictions.h"
27 #include "call/adaptation/video_stream_input_state.h"
28 #include "rtc_base/string_encode.h"
29 #include "test/gmock.h"
30 #include "test/gtest.h"
31 #include "test/scoped_key_value_config.h"
32 #include "test/testsupport/rtc_expect_death.h"
33 #include "video/config/video_encoder_config.h"
34 
35 namespace webrtc {
36 
37 using ::testing::_;
38 using ::testing::DoAll;
39 using ::testing::Return;
40 using ::testing::SaveArg;
41 
42 namespace {
43 
44 const int kBalancedHighResolutionPixels = 1280 * 720;
45 const int kBalancedHighFrameRateFps = 30;
46 
47 const int kBalancedMediumResolutionPixels = 640 * 480;
48 const int kBalancedMediumFrameRateFps = 20;
49 
50 const int kBalancedLowResolutionPixels = 320 * 240;
51 const int kBalancedLowFrameRateFps = 10;
52 
BalancedFieldTrialConfig()53 std::string BalancedFieldTrialConfig() {
54   return "WebRTC-Video-BalancedDegradationSettings/pixels:" +
55          rtc::ToString(kBalancedLowResolutionPixels) + "|" +
56          rtc::ToString(kBalancedMediumResolutionPixels) + "|" +
57          rtc::ToString(kBalancedHighResolutionPixels) +
58          ",fps:" + rtc::ToString(kBalancedLowFrameRateFps) + "|" +
59          rtc::ToString(kBalancedMediumFrameRateFps) + "|" +
60          rtc::ToString(kBalancedHighFrameRateFps) + "/";
61 }
62 
63 // Responsible for adjusting the inputs to VideoStreamAdapter (SetInput), such
64 // as pixels and frame rate, according to the most recent source restrictions.
65 // This helps tests that apply adaptations multiple times: if the input is not
66 // adjusted between adaptations, the subsequent adaptations fail with
67 // kAwaitingPreviousAdaptation.
68 class FakeVideoStream {
69  public:
FakeVideoStream(VideoStreamAdapter * adapter,FakeVideoStreamInputStateProvider * provider,int input_pixels,int input_fps,int min_pixels_per_frame)70   FakeVideoStream(VideoStreamAdapter* adapter,
71                   FakeVideoStreamInputStateProvider* provider,
72                   int input_pixels,
73                   int input_fps,
74                   int min_pixels_per_frame)
75       : adapter_(adapter),
76         provider_(provider),
77         input_pixels_(input_pixels),
78         input_fps_(input_fps),
79         min_pixels_per_frame_(min_pixels_per_frame) {
80     provider_->SetInputState(input_pixels_, input_fps_, min_pixels_per_frame_);
81   }
82 
input_pixels() const83   int input_pixels() const { return input_pixels_; }
input_fps() const84   int input_fps() const { return input_fps_; }
85 
86   // Performs ApplyAdaptation() followed by SetInput() with input pixels and
87   // frame rate adjusted according to the resulting restrictions.
ApplyAdaptation(Adaptation adaptation)88   void ApplyAdaptation(Adaptation adaptation) {
89     adapter_->ApplyAdaptation(adaptation, nullptr);
90     // Update input pixels and fps according to the resulting restrictions.
91     auto restrictions = adapter_->source_restrictions();
92     if (restrictions.target_pixels_per_frame().has_value()) {
93       RTC_DCHECK(!restrictions.max_pixels_per_frame().has_value() ||
94                  restrictions.max_pixels_per_frame().value() >=
95                      restrictions.target_pixels_per_frame().value());
96       input_pixels_ = restrictions.target_pixels_per_frame().value();
97     } else if (restrictions.max_pixels_per_frame().has_value()) {
98       input_pixels_ = restrictions.max_pixels_per_frame().value();
99     }
100     if (restrictions.max_frame_rate().has_value()) {
101       input_fps_ = restrictions.max_frame_rate().value();
102     }
103     provider_->SetInputState(input_pixels_, input_fps_, min_pixels_per_frame_);
104   }
105 
106  private:
107   VideoStreamAdapter* adapter_;
108   FakeVideoStreamInputStateProvider* provider_;
109   int input_pixels_;
110   int input_fps_;
111   int min_pixels_per_frame_;
112 };
113 
114 class FakeVideoStreamAdapterListner : public VideoSourceRestrictionsListener {
115  public:
OnVideoSourceRestrictionsUpdated(VideoSourceRestrictions restrictions,const VideoAdaptationCounters & adaptation_counters,rtc::scoped_refptr<Resource> reason,const VideoSourceRestrictions & unfiltered_restrictions)116   void OnVideoSourceRestrictionsUpdated(
117       VideoSourceRestrictions restrictions,
118       const VideoAdaptationCounters& adaptation_counters,
119       rtc::scoped_refptr<Resource> reason,
120       const VideoSourceRestrictions& unfiltered_restrictions) override {
121     calls_++;
122     last_restrictions_ = unfiltered_restrictions;
123   }
124 
calls() const125   int calls() const { return calls_; }
126 
last_restrictions() const127   VideoSourceRestrictions last_restrictions() const {
128     return last_restrictions_;
129   }
130 
131  private:
132   int calls_ = 0;
133   VideoSourceRestrictions last_restrictions_;
134 };
135 
136 class MockAdaptationConstraint : public AdaptationConstraint {
137  public:
138   MOCK_METHOD(bool,
139               IsAdaptationUpAllowed,
140               (const VideoStreamInputState& input_state,
141                const VideoSourceRestrictions& restrictions_before,
142                const VideoSourceRestrictions& restrictions_after),
143               (const, override));
144 
145   // MOCK_METHOD(std::string, Name, (), (const, override));
Name() const146   std::string Name() const override { return "MockAdaptationConstraint"; }
147 };
148 
149 }  // namespace
150 
151 class VideoStreamAdapterTest : public ::testing::Test {
152  public:
VideoStreamAdapterTest()153   VideoStreamAdapterTest()
154       : field_trials_(BalancedFieldTrialConfig()),
155         resource_(FakeResource::Create("FakeResource")),
156         adapter_(&input_state_provider_,
157                  &encoder_stats_observer_,
158                  field_trials_) {}
159 
160  protected:
161   webrtc::test::ScopedKeyValueConfig field_trials_;
162   FakeVideoStreamInputStateProvider input_state_provider_;
163   rtc::scoped_refptr<Resource> resource_;
164   testing::StrictMock<MockVideoStreamEncoderObserver> encoder_stats_observer_;
165   VideoStreamAdapter adapter_;
166 };
167 
TEST_F(VideoStreamAdapterTest,NoRestrictionsByDefault)168 TEST_F(VideoStreamAdapterTest, NoRestrictionsByDefault) {
169   EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
170   EXPECT_EQ(0, adapter_.adaptation_counters().Total());
171 }
172 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_DecreasesPixelsToThreeFifths)173 TEST_F(VideoStreamAdapterTest, MaintainFramerate_DecreasesPixelsToThreeFifths) {
174   const int kInputPixels = 1280 * 720;
175   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
176   input_state_provider_.SetInputState(kInputPixels, 30,
177                                       kDefaultMinPixelsPerFrame);
178   Adaptation adaptation = adapter_.GetAdaptationDown();
179   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
180   adapter_.ApplyAdaptation(adaptation, nullptr);
181   EXPECT_EQ(static_cast<size_t>((kInputPixels * 3) / 5),
182             adapter_.source_restrictions().max_pixels_per_frame());
183   EXPECT_EQ(absl::nullopt,
184             adapter_.source_restrictions().target_pixels_per_frame());
185   EXPECT_EQ(absl::nullopt, adapter_.source_restrictions().max_frame_rate());
186   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
187 }
188 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_DecreasesPixelsToLimitReached)189 TEST_F(VideoStreamAdapterTest,
190        MaintainFramerate_DecreasesPixelsToLimitReached) {
191   const int kMinPixelsPerFrame = 640 * 480;
192 
193   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
194   input_state_provider_.SetInputState(kMinPixelsPerFrame + 1, 30,
195                                       kMinPixelsPerFrame);
196   EXPECT_CALL(encoder_stats_observer_, OnMinPixelLimitReached());
197   // Even though we are above kMinPixelsPerFrame, because adapting down would
198   // have exceeded the limit, we are said to have reached the limit already.
199   // This differs from the frame rate adaptation logic, which would have clamped
200   // to the limit in the first step and reported kLimitReached in the second
201   // step.
202   Adaptation adaptation = adapter_.GetAdaptationDown();
203   EXPECT_EQ(Adaptation::Status::kLimitReached, adaptation.status());
204 }
205 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_IncreasePixelsToFiveThirds)206 TEST_F(VideoStreamAdapterTest, MaintainFramerate_IncreasePixelsToFiveThirds) {
207   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
208   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
209                               kDefaultMinPixelsPerFrame);
210   // Go down twice, ensuring going back up is still a restricted resolution.
211   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
212   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
213   EXPECT_EQ(2, adapter_.adaptation_counters().resolution_adaptations);
214   int input_pixels = fake_stream.input_pixels();
215   // Go up once. The target is 5/3 and the max is 12/5 of the target.
216   const int target = (input_pixels * 5) / 3;
217   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
218   EXPECT_EQ(static_cast<size_t>((target * 12) / 5),
219             adapter_.source_restrictions().max_pixels_per_frame());
220   EXPECT_EQ(static_cast<size_t>(target),
221             adapter_.source_restrictions().target_pixels_per_frame());
222   EXPECT_EQ(absl::nullopt, adapter_.source_restrictions().max_frame_rate());
223   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
224 }
225 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_IncreasePixelsToUnrestricted)226 TEST_F(VideoStreamAdapterTest, MaintainFramerate_IncreasePixelsToUnrestricted) {
227   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
228   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
229                               kDefaultMinPixelsPerFrame);
230   // We are unrestricted by default and should not be able to adapt up.
231   EXPECT_EQ(Adaptation::Status::kLimitReached,
232             adapter_.GetAdaptationUp().status());
233   // If we go down once and then back up we should not have any restrictions.
234   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
235   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
236   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
237   EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
238   EXPECT_EQ(0, adapter_.adaptation_counters().Total());
239 }
240 
TEST_F(VideoStreamAdapterTest,MaintainResolution_DecreasesFpsToTwoThirds)241 TEST_F(VideoStreamAdapterTest, MaintainResolution_DecreasesFpsToTwoThirds) {
242   const int kInputFps = 30;
243 
244   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
245   input_state_provider_.SetInputState(1280 * 720, kInputFps,
246                                       kDefaultMinPixelsPerFrame);
247   Adaptation adaptation = adapter_.GetAdaptationDown();
248   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
249   adapter_.ApplyAdaptation(adaptation, nullptr);
250   EXPECT_EQ(absl::nullopt,
251             adapter_.source_restrictions().max_pixels_per_frame());
252   EXPECT_EQ(absl::nullopt,
253             adapter_.source_restrictions().target_pixels_per_frame());
254   EXPECT_EQ(static_cast<double>((kInputFps * 2) / 3),
255             adapter_.source_restrictions().max_frame_rate());
256   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
257 }
258 
TEST_F(VideoStreamAdapterTest,MaintainResolution_DecreasesFpsToLimitReached)259 TEST_F(VideoStreamAdapterTest, MaintainResolution_DecreasesFpsToLimitReached) {
260   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
261   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720,
262                               kMinFrameRateFps + 1, kDefaultMinPixelsPerFrame);
263   // If we are not yet at the limit and the next step would exceed it, the step
264   // is clamped such that we end up exactly on the limit.
265   Adaptation adaptation = adapter_.GetAdaptationDown();
266   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
267   fake_stream.ApplyAdaptation(adaptation);
268   EXPECT_EQ(static_cast<double>(kMinFrameRateFps),
269             adapter_.source_restrictions().max_frame_rate());
270   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
271   // Having reached the limit, the next adaptation down is not valid.
272   EXPECT_EQ(Adaptation::Status::kLimitReached,
273             adapter_.GetAdaptationDown().status());
274 }
275 
TEST_F(VideoStreamAdapterTest,MaintainResolution_IncreaseFpsToThreeHalves)276 TEST_F(VideoStreamAdapterTest, MaintainResolution_IncreaseFpsToThreeHalves) {
277   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
278   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
279                               kDefaultMinPixelsPerFrame);
280   // Go down twice, ensuring going back up is still a restricted frame rate.
281   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
282   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
283   EXPECT_EQ(2, adapter_.adaptation_counters().fps_adaptations);
284   int input_fps = fake_stream.input_fps();
285   // Go up once. The target is 3/2 of the input.
286   Adaptation adaptation = adapter_.GetAdaptationUp();
287   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
288   fake_stream.ApplyAdaptation(adaptation);
289   EXPECT_EQ(absl::nullopt,
290             adapter_.source_restrictions().max_pixels_per_frame());
291   EXPECT_EQ(absl::nullopt,
292             adapter_.source_restrictions().target_pixels_per_frame());
293   EXPECT_EQ(static_cast<double>((input_fps * 3) / 2),
294             adapter_.source_restrictions().max_frame_rate());
295   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
296 }
297 
TEST_F(VideoStreamAdapterTest,MaintainResolution_IncreaseFpsToUnrestricted)298 TEST_F(VideoStreamAdapterTest, MaintainResolution_IncreaseFpsToUnrestricted) {
299   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
300   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
301                               kDefaultMinPixelsPerFrame);
302   // We are unrestricted by default and should not be able to adapt up.
303   EXPECT_EQ(Adaptation::Status::kLimitReached,
304             adapter_.GetAdaptationUp().status());
305   // If we go down once and then back up we should not have any restrictions.
306   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
307   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
308   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
309   EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
310   EXPECT_EQ(0, adapter_.adaptation_counters().Total());
311 }
312 
TEST_F(VideoStreamAdapterTest,Balanced_DecreaseFrameRate)313 TEST_F(VideoStreamAdapterTest, Balanced_DecreaseFrameRate) {
314   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
315   input_state_provider_.SetInputState(kBalancedMediumResolutionPixels,
316                                       kBalancedHighFrameRateFps,
317                                       kDefaultMinPixelsPerFrame);
318   // If our frame rate is higher than the frame rate associated with our
319   // resolution we should try to adapt to the frame rate associated with our
320   // resolution: kBalancedMediumFrameRateFps.
321   Adaptation adaptation = adapter_.GetAdaptationDown();
322   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
323   adapter_.ApplyAdaptation(adaptation, nullptr);
324   EXPECT_EQ(absl::nullopt,
325             adapter_.source_restrictions().max_pixels_per_frame());
326   EXPECT_EQ(absl::nullopt,
327             adapter_.source_restrictions().target_pixels_per_frame());
328   EXPECT_EQ(static_cast<double>(kBalancedMediumFrameRateFps),
329             adapter_.source_restrictions().max_frame_rate());
330   EXPECT_EQ(0, adapter_.adaptation_counters().resolution_adaptations);
331   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
332 }
333 
TEST_F(VideoStreamAdapterTest,Balanced_DecreaseResolution)334 TEST_F(VideoStreamAdapterTest, Balanced_DecreaseResolution) {
335   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
336   FakeVideoStream fake_stream(
337       &adapter_, &input_state_provider_, kBalancedHighResolutionPixels,
338       kBalancedHighFrameRateFps, kDefaultMinPixelsPerFrame);
339   // If we are not below the current resolution's frame rate limit, we should
340   // adapt resolution according to "maintain-framerate" logic (three fifths).
341   //
342   // However, since we are unlimited at the start and input frame rate is not
343   // below kBalancedHighFrameRateFps, we first restrict the frame rate to
344   // kBalancedHighFrameRateFps even though that is our current frame rate. This
345   // does prevent the source from going higher, though, so it's technically not
346   // a NO-OP.
347   {
348     Adaptation adaptation = adapter_.GetAdaptationDown();
349     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
350     fake_stream.ApplyAdaptation(adaptation);
351   }
352   EXPECT_EQ(absl::nullopt,
353             adapter_.source_restrictions().max_pixels_per_frame());
354   EXPECT_EQ(absl::nullopt,
355             adapter_.source_restrictions().target_pixels_per_frame());
356   EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
357             adapter_.source_restrictions().max_frame_rate());
358   EXPECT_EQ(0, adapter_.adaptation_counters().resolution_adaptations);
359   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
360   // Verify "maintain-framerate" logic the second time we adapt: Frame rate
361   // restrictions remains the same and resolution goes down.
362   {
363     Adaptation adaptation = adapter_.GetAdaptationDown();
364     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
365     fake_stream.ApplyAdaptation(adaptation);
366   }
367   constexpr size_t kReducedPixelsFirstStep =
368       static_cast<size_t>((kBalancedHighResolutionPixels * 3) / 5);
369   EXPECT_EQ(kReducedPixelsFirstStep,
370             adapter_.source_restrictions().max_pixels_per_frame());
371   EXPECT_EQ(absl::nullopt,
372             adapter_.source_restrictions().target_pixels_per_frame());
373   EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
374             adapter_.source_restrictions().max_frame_rate());
375   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
376   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
377   // If we adapt again, because the balanced settings' proposed frame rate is
378   // still kBalancedHighFrameRateFps, "maintain-framerate" will trigger again.
379   static_assert(kReducedPixelsFirstStep > kBalancedMediumResolutionPixels,
380                 "The reduced resolution is still greater than the next lower "
381                 "balanced setting resolution");
382   constexpr size_t kReducedPixelsSecondStep = (kReducedPixelsFirstStep * 3) / 5;
383   {
384     Adaptation adaptation = adapter_.GetAdaptationDown();
385     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
386     fake_stream.ApplyAdaptation(adaptation);
387   }
388   EXPECT_EQ(kReducedPixelsSecondStep,
389             adapter_.source_restrictions().max_pixels_per_frame());
390   EXPECT_EQ(absl::nullopt,
391             adapter_.source_restrictions().target_pixels_per_frame());
392   EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
393             adapter_.source_restrictions().max_frame_rate());
394   EXPECT_EQ(2, adapter_.adaptation_counters().resolution_adaptations);
395   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
396 }
397 
398 // Testing when to adapt frame rate and when to adapt resolution is quite
399 // entangled, so this test covers both cases.
400 //
401 // There is an asymmetry: When we adapt down we do it in one order, but when we
402 // adapt up we don't do it in the reverse order. Instead we always try to adapt
403 // frame rate first according to balanced settings' configs and only when the
404 // frame rate is already achieved do we adjust the resolution.
TEST_F(VideoStreamAdapterTest,Balanced_IncreaseFrameRateAndResolution)405 TEST_F(VideoStreamAdapterTest, Balanced_IncreaseFrameRateAndResolution) {
406   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
407   FakeVideoStream fake_stream(
408       &adapter_, &input_state_provider_, kBalancedHighResolutionPixels,
409       kBalancedHighFrameRateFps, kDefaultMinPixelsPerFrame);
410   // The desired starting point of this test is having adapted frame rate twice.
411   // This requires performing a number of adaptations.
412   constexpr size_t kReducedPixelsFirstStep =
413       static_cast<size_t>((kBalancedHighResolutionPixels * 3) / 5);
414   constexpr size_t kReducedPixelsSecondStep = (kReducedPixelsFirstStep * 3) / 5;
415   constexpr size_t kReducedPixelsThirdStep = (kReducedPixelsSecondStep * 3) / 5;
416   static_assert(kReducedPixelsFirstStep > kBalancedMediumResolutionPixels,
417                 "The first pixel reduction is greater than the balanced "
418                 "settings' medium pixel configuration");
419   static_assert(kReducedPixelsSecondStep > kBalancedMediumResolutionPixels,
420                 "The second pixel reduction is greater than the balanced "
421                 "settings' medium pixel configuration");
422   static_assert(kReducedPixelsThirdStep <= kBalancedMediumResolutionPixels,
423                 "The third pixel reduction is NOT greater than the balanced "
424                 "settings' medium pixel configuration");
425   // The first adaptation should affect the frame rate: See
426   // Balanced_DecreaseResolution for explanation why.
427   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
428   EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
429             adapter_.source_restrictions().max_frame_rate());
430   // The next three adaptations affects the resolution, because we have to reach
431   // kBalancedMediumResolutionPixels before a lower frame rate is considered by
432   // BalancedDegradationSettings. The number three is derived from the
433   // static_asserts above.
434   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
435   EXPECT_EQ(kReducedPixelsFirstStep,
436             adapter_.source_restrictions().max_pixels_per_frame());
437   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
438   EXPECT_EQ(kReducedPixelsSecondStep,
439             adapter_.source_restrictions().max_pixels_per_frame());
440   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
441   EXPECT_EQ(kReducedPixelsThirdStep,
442             adapter_.source_restrictions().max_pixels_per_frame());
443   // Thus, the next adaptation will reduce frame rate to
444   // kBalancedMediumFrameRateFps.
445   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
446   EXPECT_EQ(static_cast<double>(kBalancedMediumFrameRateFps),
447             adapter_.source_restrictions().max_frame_rate());
448   EXPECT_EQ(3, adapter_.adaptation_counters().resolution_adaptations);
449   EXPECT_EQ(2, adapter_.adaptation_counters().fps_adaptations);
450   // Adapt up!
451   // While our resolution is in the medium-range, the frame rate associated with
452   // the next resolution configuration up ("high") is kBalancedHighFrameRateFps
453   // and "balanced" prefers adapting frame rate if not already applied.
454   {
455     Adaptation adaptation = adapter_.GetAdaptationUp();
456     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
457     fake_stream.ApplyAdaptation(adaptation);
458     EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
459               adapter_.source_restrictions().max_frame_rate());
460     EXPECT_EQ(3, adapter_.adaptation_counters().resolution_adaptations);
461     EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
462   }
463   // Now that we have already achieved the next frame rate up, we act according
464   // to "maintain-framerate". We go back up in resolution. Due to rounding
465   // errors we don't end up back at kReducedPixelsSecondStep. Rather we get to
466   // kReducedPixelsSecondStepUp, which is off by one compared to
467   // kReducedPixelsSecondStep.
468   constexpr size_t kReducedPixelsSecondStepUp =
469       (kReducedPixelsThirdStep * 5) / 3;
470   {
471     Adaptation adaptation = adapter_.GetAdaptationUp();
472     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
473     fake_stream.ApplyAdaptation(adaptation);
474     EXPECT_EQ(kReducedPixelsSecondStepUp,
475               adapter_.source_restrictions().target_pixels_per_frame());
476     EXPECT_EQ(2, adapter_.adaptation_counters().resolution_adaptations);
477     EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
478   }
479   // Now that our resolution is back in the high-range, the next frame rate to
480   // try out is "unlimited".
481   {
482     Adaptation adaptation = adapter_.GetAdaptationUp();
483     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
484     fake_stream.ApplyAdaptation(adaptation);
485     EXPECT_EQ(absl::nullopt, adapter_.source_restrictions().max_frame_rate());
486     EXPECT_EQ(2, adapter_.adaptation_counters().resolution_adaptations);
487     EXPECT_EQ(0, adapter_.adaptation_counters().fps_adaptations);
488   }
489   // Now only adapting resolution remains.
490   constexpr size_t kReducedPixelsFirstStepUp =
491       (kReducedPixelsSecondStepUp * 5) / 3;
492   {
493     Adaptation adaptation = adapter_.GetAdaptationUp();
494     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
495     fake_stream.ApplyAdaptation(adaptation);
496     EXPECT_EQ(kReducedPixelsFirstStepUp,
497               adapter_.source_restrictions().target_pixels_per_frame());
498     EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
499     EXPECT_EQ(0, adapter_.adaptation_counters().fps_adaptations);
500   }
501   // The last step up should make us entirely unrestricted.
502   {
503     Adaptation adaptation = adapter_.GetAdaptationUp();
504     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
505     fake_stream.ApplyAdaptation(adaptation);
506     EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
507     EXPECT_EQ(0, adapter_.adaptation_counters().Total());
508   }
509 }
510 
TEST_F(VideoStreamAdapterTest,Balanced_LimitReached)511 TEST_F(VideoStreamAdapterTest, Balanced_LimitReached) {
512   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
513   FakeVideoStream fake_stream(
514       &adapter_, &input_state_provider_, kBalancedLowResolutionPixels,
515       kBalancedLowFrameRateFps, kDefaultMinPixelsPerFrame);
516   // Attempting to adapt up while unrestricted should result in kLimitReached.
517   EXPECT_EQ(Adaptation::Status::kLimitReached,
518             adapter_.GetAdaptationUp().status());
519   // Adapting down once result in restricted frame rate, in this case we reach
520   // the lowest possible frame rate immediately: kBalancedLowFrameRateFps.
521   EXPECT_CALL(encoder_stats_observer_, OnMinPixelLimitReached()).Times(2);
522   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
523   EXPECT_EQ(static_cast<double>(kBalancedLowFrameRateFps),
524             adapter_.source_restrictions().max_frame_rate());
525   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
526   // Any further adaptation must follow "maintain-framerate" rules (these are
527   // covered in more depth by the MaintainFramerate tests). This test does not
528   // assert exactly how resolution is adjusted, only that resolution always
529   // decreases and that we eventually reach kLimitReached.
530   size_t previous_resolution = kBalancedLowResolutionPixels;
531   bool did_reach_limit = false;
532   // If we have not reached the limit within 5 adaptations something is wrong...
533   for (int i = 0; i < 5; i++) {
534     Adaptation adaptation = adapter_.GetAdaptationDown();
535     if (adaptation.status() == Adaptation::Status::kLimitReached) {
536       did_reach_limit = true;
537       break;
538     }
539     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
540     fake_stream.ApplyAdaptation(adaptation);
541     EXPECT_LT(adapter_.source_restrictions().max_pixels_per_frame().value(),
542               previous_resolution);
543     previous_resolution =
544         adapter_.source_restrictions().max_pixels_per_frame().value();
545   }
546   EXPECT_TRUE(did_reach_limit);
547   // Frame rate restrictions are the same as before.
548   EXPECT_EQ(static_cast<double>(kBalancedLowFrameRateFps),
549             adapter_.source_restrictions().max_frame_rate());
550   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
551 }
552 
553 // kAwaitingPreviousAdaptation is only supported in "maintain-framerate".
TEST_F(VideoStreamAdapterTest,MaintainFramerate_AwaitingPreviousAdaptationDown)554 TEST_F(VideoStreamAdapterTest,
555        MaintainFramerate_AwaitingPreviousAdaptationDown) {
556   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
557   input_state_provider_.SetInputState(1280 * 720, 30,
558                                       kDefaultMinPixelsPerFrame);
559   // Adapt down once, but don't update the input.
560   adapter_.ApplyAdaptation(adapter_.GetAdaptationDown(), nullptr);
561   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
562   {
563     // Having performed the adaptation, but not updated the input based on the
564     // new restrictions, adapting again in the same direction will not work.
565     Adaptation adaptation = adapter_.GetAdaptationDown();
566     EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
567               adaptation.status());
568   }
569 }
570 
571 // kAwaitingPreviousAdaptation is only supported in "maintain-framerate".
TEST_F(VideoStreamAdapterTest,MaintainFramerate_AwaitingPreviousAdaptationUp)572 TEST_F(VideoStreamAdapterTest, MaintainFramerate_AwaitingPreviousAdaptationUp) {
573   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
574   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
575                               kDefaultMinPixelsPerFrame);
576   // Perform two adaptation down so that adapting up twice is possible.
577   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
578   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
579   EXPECT_EQ(2, adapter_.adaptation_counters().resolution_adaptations);
580   // Adapt up once, but don't update the input.
581   adapter_.ApplyAdaptation(adapter_.GetAdaptationUp(), nullptr);
582   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
583   {
584     // Having performed the adaptation, but not updated the input based on the
585     // new restrictions, adapting again in the same direction will not work.
586     Adaptation adaptation = adapter_.GetAdaptationUp();
587     EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
588               adaptation.status());
589   }
590 }
591 
TEST_F(VideoStreamAdapterTest,MaintainResolution_AdaptsUpAfterSwitchingDegradationPreference)592 TEST_F(VideoStreamAdapterTest,
593        MaintainResolution_AdaptsUpAfterSwitchingDegradationPreference) {
594   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
595   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
596                               kDefaultMinPixelsPerFrame);
597   // Adapt down in fps for later.
598   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
599   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
600 
601   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
602   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
603   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
604   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
605   EXPECT_EQ(0, adapter_.adaptation_counters().resolution_adaptations);
606 
607   // We should be able to adapt in framerate one last time after the change of
608   // degradation preference.
609   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
610   Adaptation adaptation = adapter_.GetAdaptationUp();
611   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
612   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
613   EXPECT_EQ(0, adapter_.adaptation_counters().fps_adaptations);
614 }
615 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_AdaptsUpAfterSwitchingDegradationPreference)616 TEST_F(VideoStreamAdapterTest,
617        MaintainFramerate_AdaptsUpAfterSwitchingDegradationPreference) {
618   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
619   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
620                               kDefaultMinPixelsPerFrame);
621   // Adapt down in resolution for later.
622   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
623   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
624 
625   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
626   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
627   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
628   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
629   EXPECT_EQ(0, adapter_.adaptation_counters().fps_adaptations);
630 
631   // We should be able to adapt in framerate one last time after the change of
632   // degradation preference.
633   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
634   Adaptation adaptation = adapter_.GetAdaptationUp();
635   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
636   fake_stream.ApplyAdaptation(adapter_.GetAdaptationUp());
637   EXPECT_EQ(0, adapter_.adaptation_counters().resolution_adaptations);
638 }
639 
TEST_F(VideoStreamAdapterTest,PendingResolutionIncreaseAllowsAdaptUpAfterSwitchToMaintainResolution)640 TEST_F(VideoStreamAdapterTest,
641        PendingResolutionIncreaseAllowsAdaptUpAfterSwitchToMaintainResolution) {
642   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
643   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
644                               kDefaultMinPixelsPerFrame);
645   // Adapt fps down so we can adapt up later in the test.
646   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
647 
648   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
649   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
650   // Apply adaptation up but don't update input.
651   adapter_.ApplyAdaptation(adapter_.GetAdaptationUp(), nullptr);
652   EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
653             adapter_.GetAdaptationUp().status());
654 
655   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
656   Adaptation adaptation = adapter_.GetAdaptationUp();
657   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
658 }
659 
TEST_F(VideoStreamAdapterTest,MaintainFramerate_AdaptsDownAfterSwitchingDegradationPreference)660 TEST_F(VideoStreamAdapterTest,
661        MaintainFramerate_AdaptsDownAfterSwitchingDegradationPreference) {
662   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
663   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
664                               kDefaultMinPixelsPerFrame);
665   // Adapt down once, should change FPS.
666   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
667   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
668 
669   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
670   // Adaptation down should apply after the degradation prefs change.
671   Adaptation adaptation = adapter_.GetAdaptationDown();
672   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
673   fake_stream.ApplyAdaptation(adaptation);
674   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
675   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
676 }
677 
TEST_F(VideoStreamAdapterTest,MaintainResolution_AdaptsDownAfterSwitchingDegradationPreference)678 TEST_F(VideoStreamAdapterTest,
679        MaintainResolution_AdaptsDownAfterSwitchingDegradationPreference) {
680   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
681   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
682                               kDefaultMinPixelsPerFrame);
683   // Adapt down once, should change FPS.
684   fake_stream.ApplyAdaptation(adapter_.GetAdaptationDown());
685   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
686 
687   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
688   Adaptation adaptation = adapter_.GetAdaptationDown();
689   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
690   fake_stream.ApplyAdaptation(adaptation);
691 
692   EXPECT_EQ(1, adapter_.adaptation_counters().fps_adaptations);
693   EXPECT_EQ(1, adapter_.adaptation_counters().resolution_adaptations);
694 }
695 
TEST_F(VideoStreamAdapterTest,PendingResolutionDecreaseAllowsAdaptDownAfterSwitchToMaintainResolution)696 TEST_F(
697     VideoStreamAdapterTest,
698     PendingResolutionDecreaseAllowsAdaptDownAfterSwitchToMaintainResolution) {
699   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
700   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
701                               kDefaultMinPixelsPerFrame);
702   // Apply adaptation but don't update the input.
703   adapter_.ApplyAdaptation(adapter_.GetAdaptationDown(), nullptr);
704   EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
705             adapter_.GetAdaptationDown().status());
706   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
707   Adaptation adaptation = adapter_.GetAdaptationDown();
708   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
709 }
710 
TEST_F(VideoStreamAdapterTest,RestrictionBroadcasted)711 TEST_F(VideoStreamAdapterTest, RestrictionBroadcasted) {
712   FakeVideoStreamAdapterListner listener;
713   adapter_.AddRestrictionsListener(&listener);
714   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
715   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
716                               kDefaultMinPixelsPerFrame);
717   // Not broadcast on invalid ApplyAdaptation.
718   {
719     Adaptation adaptation = adapter_.GetAdaptationUp();
720     adapter_.ApplyAdaptation(adaptation, nullptr);
721     EXPECT_EQ(0, listener.calls());
722   }
723 
724   // Broadcast on ApplyAdaptation.
725   {
726     Adaptation adaptation = adapter_.GetAdaptationDown();
727     fake_stream.ApplyAdaptation(adaptation);
728     EXPECT_EQ(1, listener.calls());
729     EXPECT_EQ(adaptation.restrictions(), listener.last_restrictions());
730   }
731 
732   // Broadcast on ClearRestrictions().
733   adapter_.ClearRestrictions();
734   EXPECT_EQ(2, listener.calls());
735   EXPECT_EQ(VideoSourceRestrictions(), listener.last_restrictions());
736 }
737 
TEST_F(VideoStreamAdapterTest,AdaptationHasNextRestrcitions)738 TEST_F(VideoStreamAdapterTest, AdaptationHasNextRestrcitions) {
739   // Any non-disabled DegradationPreference will do.
740   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
741   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
742                               kDefaultMinPixelsPerFrame);
743   // When adaptation is not possible.
744   {
745     Adaptation adaptation = adapter_.GetAdaptationUp();
746     EXPECT_EQ(Adaptation::Status::kLimitReached, adaptation.status());
747     EXPECT_EQ(adaptation.restrictions(), adapter_.source_restrictions());
748     EXPECT_EQ(0, adaptation.counters().Total());
749   }
750   // When we adapt down.
751   {
752     Adaptation adaptation = adapter_.GetAdaptationDown();
753     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
754     fake_stream.ApplyAdaptation(adaptation);
755     EXPECT_EQ(adaptation.restrictions(), adapter_.source_restrictions());
756     EXPECT_EQ(adaptation.counters(), adapter_.adaptation_counters());
757   }
758   // When we adapt up.
759   {
760     Adaptation adaptation = adapter_.GetAdaptationUp();
761     EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
762     fake_stream.ApplyAdaptation(adaptation);
763     EXPECT_EQ(adaptation.restrictions(), adapter_.source_restrictions());
764     EXPECT_EQ(adaptation.counters(), adapter_.adaptation_counters());
765   }
766 }
767 
TEST_F(VideoStreamAdapterTest,SetDegradationPreferenceToOrFromBalancedClearsRestrictions)768 TEST_F(VideoStreamAdapterTest,
769        SetDegradationPreferenceToOrFromBalancedClearsRestrictions) {
770   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
771   input_state_provider_.SetInputState(1280 * 720, 30,
772                                       kDefaultMinPixelsPerFrame);
773   adapter_.ApplyAdaptation(adapter_.GetAdaptationDown(), nullptr);
774   EXPECT_NE(VideoSourceRestrictions(), adapter_.source_restrictions());
775   EXPECT_NE(0, adapter_.adaptation_counters().Total());
776   // Changing from non-balanced to balanced clears the restrictions.
777   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
778   EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
779   EXPECT_EQ(0, adapter_.adaptation_counters().Total());
780   // Apply adaptation again.
781   adapter_.ApplyAdaptation(adapter_.GetAdaptationDown(), nullptr);
782   EXPECT_NE(VideoSourceRestrictions(), adapter_.source_restrictions());
783   EXPECT_NE(0, adapter_.adaptation_counters().Total());
784   // Changing from balanced to non-balanced clears the restrictions.
785   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
786   EXPECT_EQ(VideoSourceRestrictions(), adapter_.source_restrictions());
787   EXPECT_EQ(0, adapter_.adaptation_counters().Total());
788 }
789 
TEST_F(VideoStreamAdapterTest,GetAdaptDownResolutionAdaptsResolutionInMaintainFramerate)790 TEST_F(VideoStreamAdapterTest,
791        GetAdaptDownResolutionAdaptsResolutionInMaintainFramerate) {
792   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
793   input_state_provider_.SetInputState(1280 * 720, 30,
794                                       kDefaultMinPixelsPerFrame);
795 
796   auto adaptation = adapter_.GetAdaptDownResolution();
797   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
798   EXPECT_EQ(1, adaptation.counters().resolution_adaptations);
799   EXPECT_EQ(0, adaptation.counters().fps_adaptations);
800 }
801 
TEST_F(VideoStreamAdapterTest,GetAdaptDownResolutionReturnsWithStatusInDisabledAndMaintainResolution)802 TEST_F(VideoStreamAdapterTest,
803        GetAdaptDownResolutionReturnsWithStatusInDisabledAndMaintainResolution) {
804   adapter_.SetDegradationPreference(DegradationPreference::DISABLED);
805   input_state_provider_.SetInputState(1280 * 720, 30,
806                                       kDefaultMinPixelsPerFrame);
807   EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
808             adapter_.GetAdaptDownResolution().status());
809   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
810   EXPECT_EQ(Adaptation::Status::kLimitReached,
811             adapter_.GetAdaptDownResolution().status());
812 }
813 
TEST_F(VideoStreamAdapterTest,GetAdaptDownResolutionAdaptsFpsAndResolutionInBalanced)814 TEST_F(VideoStreamAdapterTest,
815        GetAdaptDownResolutionAdaptsFpsAndResolutionInBalanced) {
816   // Note: This test depends on BALANCED implementation, but with current
817   // implementation and input state settings, BALANCED will adapt resolution and
818   // frame rate once.
819   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
820   input_state_provider_.SetInputState(1280 * 720, 30,
821                                       kDefaultMinPixelsPerFrame);
822 
823   auto adaptation = adapter_.GetAdaptDownResolution();
824   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
825   EXPECT_EQ(1, adaptation.counters().resolution_adaptations);
826   EXPECT_EQ(1, adaptation.counters().fps_adaptations);
827 }
828 
TEST_F(VideoStreamAdapterTest,GetAdaptDownResolutionAdaptsOnlyResolutionIfFpsAlreadyAdapterInBalanced)829 TEST_F(
830     VideoStreamAdapterTest,
831     GetAdaptDownResolutionAdaptsOnlyResolutionIfFpsAlreadyAdapterInBalanced) {
832   // Note: This test depends on BALANCED implementation, but with current
833   // implementation and input state settings, BALANCED will adapt resolution
834   // only.
835   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
836   input_state_provider_.SetInputState(1280 * 720, 5, kDefaultMinPixelsPerFrame);
837   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
838                               kDefaultMinPixelsPerFrame);
839 
840   auto first_adaptation = adapter_.GetAdaptationDown();
841   fake_stream.ApplyAdaptation(first_adaptation);
842 
843   auto adaptation = adapter_.GetAdaptDownResolution();
844   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
845   EXPECT_EQ(1, adaptation.counters().resolution_adaptations);
846   EXPECT_EQ(first_adaptation.counters().fps_adaptations,
847             adaptation.counters().fps_adaptations);
848 }
849 
TEST_F(VideoStreamAdapterTest,GetAdaptDownResolutionAdaptsOnlyFpsIfResolutionLowInBalanced)850 TEST_F(VideoStreamAdapterTest,
851        GetAdaptDownResolutionAdaptsOnlyFpsIfResolutionLowInBalanced) {
852   // Note: This test depends on BALANCED implementation, but with current
853   // implementation and input state settings, BALANCED will adapt resolution
854   // only.
855   adapter_.SetDegradationPreference(DegradationPreference::BALANCED);
856   input_state_provider_.SetInputState(kDefaultMinPixelsPerFrame, 30,
857                                       kDefaultMinPixelsPerFrame);
858 
859   auto adaptation = adapter_.GetAdaptDownResolution();
860   EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
861   EXPECT_EQ(0, adaptation.counters().resolution_adaptations);
862   EXPECT_EQ(1, adaptation.counters().fps_adaptations);
863 }
864 
TEST_F(VideoStreamAdapterTest,AdaptationDisabledStatusAlwaysWhenDegradationPreferenceDisabled)865 TEST_F(VideoStreamAdapterTest,
866        AdaptationDisabledStatusAlwaysWhenDegradationPreferenceDisabled) {
867   adapter_.SetDegradationPreference(DegradationPreference::DISABLED);
868   input_state_provider_.SetInputState(1280 * 720, 30,
869                                       kDefaultMinPixelsPerFrame);
870   EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
871             adapter_.GetAdaptationDown().status());
872   EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
873             adapter_.GetAdaptationUp().status());
874   EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
875             adapter_.GetAdaptDownResolution().status());
876 }
877 
TEST_F(VideoStreamAdapterTest,AdaptationConstraintAllowsAdaptationsUp)878 TEST_F(VideoStreamAdapterTest, AdaptationConstraintAllowsAdaptationsUp) {
879   testing::StrictMock<MockAdaptationConstraint> adaptation_constraint;
880   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
881   adapter_.AddAdaptationConstraint(&adaptation_constraint);
882   input_state_provider_.SetInputState(1280 * 720, 30,
883                                       kDefaultMinPixelsPerFrame);
884   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
885                               kDefaultMinPixelsPerFrame);
886   // Adapt down once so we can adapt up later.
887   auto first_adaptation = adapter_.GetAdaptationDown();
888   fake_stream.ApplyAdaptation(first_adaptation);
889 
890   EXPECT_CALL(adaptation_constraint,
891               IsAdaptationUpAllowed(_, first_adaptation.restrictions(), _))
892       .WillOnce(Return(true));
893   EXPECT_EQ(Adaptation::Status::kValid, adapter_.GetAdaptationUp().status());
894   adapter_.RemoveAdaptationConstraint(&adaptation_constraint);
895 }
896 
TEST_F(VideoStreamAdapterTest,AdaptationConstraintDisallowsAdaptationsUp)897 TEST_F(VideoStreamAdapterTest, AdaptationConstraintDisallowsAdaptationsUp) {
898   testing::StrictMock<MockAdaptationConstraint> adaptation_constraint;
899   adapter_.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
900   adapter_.AddAdaptationConstraint(&adaptation_constraint);
901   input_state_provider_.SetInputState(1280 * 720, 30,
902                                       kDefaultMinPixelsPerFrame);
903   FakeVideoStream fake_stream(&adapter_, &input_state_provider_, 1280 * 720, 30,
904                               kDefaultMinPixelsPerFrame);
905   // Adapt down once so we can adapt up later.
906   auto first_adaptation = adapter_.GetAdaptationDown();
907   fake_stream.ApplyAdaptation(first_adaptation);
908 
909   EXPECT_CALL(adaptation_constraint,
910               IsAdaptationUpAllowed(_, first_adaptation.restrictions(), _))
911       .WillOnce(Return(false));
912   EXPECT_EQ(Adaptation::Status::kRejectedByConstraint,
913             adapter_.GetAdaptationUp().status());
914   adapter_.RemoveAdaptationConstraint(&adaptation_constraint);
915 }
916 
917 // Death tests.
918 // Disabled on Android because death tests misbehave on Android, see
919 // base/test/gtest_util.h.
920 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
921 
TEST(VideoStreamAdapterDeathTest,SetDegradationPreferenceInvalidatesAdaptations)922 TEST(VideoStreamAdapterDeathTest,
923      SetDegradationPreferenceInvalidatesAdaptations) {
924   webrtc::test::ScopedKeyValueConfig field_trials;
925   FakeVideoStreamInputStateProvider input_state_provider;
926   testing::StrictMock<MockVideoStreamEncoderObserver> encoder_stats_observer_;
927   VideoStreamAdapter adapter(&input_state_provider, &encoder_stats_observer_,
928                              field_trials);
929   adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
930   input_state_provider.SetInputState(1280 * 720, 30, kDefaultMinPixelsPerFrame);
931   Adaptation adaptation = adapter.GetAdaptationDown();
932   adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
933   EXPECT_DEATH(adapter.ApplyAdaptation(adaptation, nullptr), "");
934 }
935 
TEST(VideoStreamAdapterDeathTest,AdaptDownInvalidatesAdaptations)936 TEST(VideoStreamAdapterDeathTest, AdaptDownInvalidatesAdaptations) {
937   webrtc::test::ScopedKeyValueConfig field_trials;
938   FakeVideoStreamInputStateProvider input_state_provider;
939   testing::StrictMock<MockVideoStreamEncoderObserver> encoder_stats_observer_;
940   VideoStreamAdapter adapter(&input_state_provider, &encoder_stats_observer_,
941                              field_trials);
942   adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
943   input_state_provider.SetInputState(1280 * 720, 30, kDefaultMinPixelsPerFrame);
944   Adaptation adaptation = adapter.GetAdaptationDown();
945   adapter.GetAdaptationDown();
946   EXPECT_DEATH(adapter.ApplyAdaptation(adaptation, nullptr), "");
947 }
948 
949 #endif  // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
950 
951 }  // namespace webrtc
952