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