[Adaptation] VideoStreamAdapter unit tests added.

This code was previously only exercised by
video_stream_adapter_unittest.cc and other tests, acting more like
integration tests than unit tests. Now that the VideoStreamAdapter is
in a good state, more extensive test coverage is added.

Testing includes:
- Default restrictions.
- Adapting up or down in "maintain-framerate", "maintain-resolution"
  and "balanced", including...
- expecting how frame rate and/or resolution is affected,
- reaching kLimitReached,
- and reaching unrestricted.
- That "disabled" does not adapt.
- When adaptation is not possible, including...
- kInsufficientInput
- kAwaitingPreviousAdaptation
- kIsBitrateConstrained
- PeekNextRestrictions()
- "balanced" + "screenshare" = "maintain-resolution"
- Change degradation preference to/from "balanced" clears restrictions.
- That using invalidated adaptations triggers DCHECKs.

Bug: webrtc:11393
Change-Id: I28e2cf227bc1fd8871ee0d18d9570d4063449160
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/170625
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30816}
diff --git a/video/adaptation/BUILD.gn b/video/adaptation/BUILD.gn
index f8bb6d8..fd611e2 100644
--- a/video/adaptation/BUILD.gn
+++ b/video/adaptation/BUILD.gn
@@ -62,11 +62,14 @@
       "adaptation_counters_unittest.cc",
       "overuse_frame_detector_unittest.cc",
       "resource_adaptation_processor_unittest.cc",
+      "video_stream_adapter_unittest.cc",
     ]
     deps = [
       ":video_adaptation",
       "../../api/video:encoded_image",
       "../../api/video:video_frame_i420",
+      "../../api/video_codecs:video_codecs_api",
+      "../../call/adaptation:resource_adaptation",
       "../../modules/video_coding:video_coding_utility",
       "../../rtc_base:checks",
       "../../rtc_base:logging",
@@ -75,6 +78,8 @@
       "../../rtc_base:rtc_event",
       "../../rtc_base:rtc_numerics",
       "../../rtc_base:task_queue_for_test",
+      "../../test:field_trial",
+      "//test:rtc_expect_death",
       "//test:test_support",
       "//testing/gtest",
       "//third_party/abseil-cpp/absl/types:optional",
diff --git a/video/adaptation/video_stream_adapter.cc b/video/adaptation/video_stream_adapter.cc
index 653f3a7..7a35b64 100644
--- a/video/adaptation/video_stream_adapter.cc
+++ b/video/adaptation/video_stream_adapter.cc
@@ -22,9 +22,9 @@
 
 namespace webrtc {
 
-namespace {
+const int kMinFrameRateFps = 2;
 
-const int kMinFramerateFps = 2;
+namespace {
 
 int MinPixelsPerFrame(const absl::optional<EncoderSettings>& encoder_settings) {
   return encoder_settings.has_value()
@@ -179,7 +179,7 @@
   }
 
   bool CanDecreaseFrameRateTo(int max_frame_rate) {
-    const int fps_wanted = std::max(kMinFramerateFps, max_frame_rate);
+    const int fps_wanted = std::max(kMinFrameRateFps, max_frame_rate);
     return fps_wanted < rtc::dchecked_cast<int>(
                             source_restrictions_.max_frame_rate().value_or(
                                 std::numeric_limits<int>::max()));
@@ -270,7 +270,7 @@
 
   void DecreaseFrameRateTo(int max_frame_rate) {
     RTC_DCHECK(CanDecreaseFrameRateTo(max_frame_rate));
-    max_frame_rate = std::max(kMinFramerateFps, max_frame_rate);
+    max_frame_rate = std::max(kMinFrameRateFps, max_frame_rate);
     RTC_LOG(LS_INFO) << "Scaling down framerate: " << max_frame_rate;
     source_restrictions_.set_max_frame_rate(
         max_frame_rate != std::numeric_limits<int>::max()
@@ -501,7 +501,7 @@
     // TODO(hbos): This usage of |last_adaptation_was_down| looks like a mistake
     // - delete it.
     if (input_fps_ <= 0 ||
-        (last_adaptation_was_down && input_fps_ < kMinFramerateFps)) {
+        (last_adaptation_was_down && input_fps_ < kMinFrameRateFps)) {
       return Adaptation(adaptation_validation_id_,
                         Adaptation::Status::kInsufficientInput);
     }
@@ -565,6 +565,7 @@
 
 VideoSourceRestrictions VideoStreamAdapter::PeekNextRestrictions(
     const Adaptation& adaptation) const {
+  RTC_DCHECK_EQ(adaptation.validation_id_, adaptation_validation_id_);
   if (adaptation.status() != Adaptation::Status::kValid)
     return source_restrictor_->source_restrictions();
   VideoSourceRestrictor restrictor_copy = *source_restrictor_;
diff --git a/video/adaptation/video_stream_adapter.h b/video/adaptation/video_stream_adapter.h
index 3f12d15..9e0a255 100644
--- a/video/adaptation/video_stream_adapter.h
+++ b/video/adaptation/video_stream_adapter.h
@@ -24,6 +24,8 @@
 
 namespace webrtc {
 
+extern const int kMinFrameRateFps;
+
 class VideoStreamAdapter;
 
 // Represents one step that the VideoStreamAdapter can take when adapting the
diff --git a/video/adaptation/video_stream_adapter_unittest.cc b/video/adaptation/video_stream_adapter_unittest.cc
new file mode 100644
index 0000000..46f662b
--- /dev/null
+++ b/video/adaptation/video_stream_adapter_unittest.cc
@@ -0,0 +1,766 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "video/adaptation/video_stream_adapter.h"
+
+#include <string>
+#include <utility>
+
+#include "absl/types/optional.h"
+#include "api/video_codecs/video_codec.h"
+#include "api/video_codecs/video_encoder.h"
+#include "api/video_codecs/video_encoder_config.h"
+#include "call/adaptation/encoder_settings.h"
+#include "call/adaptation/video_source_restrictions.h"
+#include "rtc_base/string_encode.h"
+#include "test/field_trial.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+#include "test/testsupport/rtc_expect_death.h"
+
+namespace webrtc {
+
+namespace {
+
+// GetAdaptationUp() requires an AdaptReason. This is only used in edge cases,
+// so most tests don't care what reason is used.
+const auto kReasonDontCare = AdaptationObserverInterface::AdaptReason::kQuality;
+
+const int kBalancedHighResolutionPixels = 1280 * 720;
+const int kBalancedHighFrameRateFps = 30;
+
+const int kBalancedMediumResolutionPixels = 640 * 480;
+const int kBalancedMediumFrameRateFps = 20;
+
+const int kBalancedLowResolutionPixels = 320 * 240;
+const int kBalancedLowFrameRateFps = 10;
+
+std::string BalancedFieldTrialConfig() {
+  return "WebRTC-Video-BalancedDegradationSettings/pixels:" +
+         rtc::ToString(kBalancedLowResolutionPixels) + "|" +
+         rtc::ToString(kBalancedMediumResolutionPixels) + "|" +
+         rtc::ToString(kBalancedHighResolutionPixels) +
+         ",fps:" + rtc::ToString(kBalancedLowFrameRateFps) + "|" +
+         rtc::ToString(kBalancedMediumFrameRateFps) + "|" +
+         rtc::ToString(kBalancedHighFrameRateFps) + "/";
+}
+
+// Responsible for adjusting the inputs to VideoStreamAdapter (SetInput), such
+// as pixels and frame rate, according to the most recent source restrictions.
+// This helps tests that apply adaptations multiple times: if the input is not
+// adjusted between adaptations, the subsequent adaptations fail with
+// kAwaitingPreviousAdaptation.
+class FakeVideoStream {
+ public:
+  FakeVideoStream(VideoStreamAdapter* adapter,
+                  VideoStreamAdapter::VideoInputMode input_mode,
+                  int input_pixels,
+                  int input_fps,
+                  absl::optional<EncoderSettings> encoder_settings,
+                  absl::optional<uint32_t> encoder_target_bitrate_bps)
+      : adapter_(adapter),
+        input_mode_(std::move(input_mode)),
+        input_pixels_(input_pixels),
+        input_fps_(input_fps),
+        encoder_settings_(std::move(encoder_settings)),
+        encoder_target_bitrate_bps_(std::move(encoder_target_bitrate_bps)) {
+    adapter_->SetInput(input_mode_, input_pixels_, input_fps_,
+                       encoder_settings_, encoder_target_bitrate_bps_);
+  }
+
+  int input_pixels() const { return input_pixels_; }
+  int input_fps() const { return input_fps_; }
+
+  // Performs ApplyAdaptation() followed by SetInput() with input pixels and
+  // frame rate adjusted according to the resulting restrictions.
+  void ApplyAdaptation(Adaptation adaptation) {
+    adapter_->ApplyAdaptation(adaptation);
+    // Update input pixels and fps according to the resulting restrictions.
+    auto restrictions = adapter_->source_restrictions();
+    if (restrictions.target_pixels_per_frame().has_value()) {
+      RTC_DCHECK(!restrictions.max_pixels_per_frame().has_value() ||
+                 restrictions.max_pixels_per_frame().value() >=
+                     restrictions.target_pixels_per_frame().value());
+      input_pixels_ = restrictions.target_pixels_per_frame().value();
+    } else if (restrictions.max_pixels_per_frame().has_value()) {
+      input_pixels_ = restrictions.max_pixels_per_frame().value();
+    }
+    if (restrictions.max_frame_rate().has_value()) {
+      input_fps_ = restrictions.max_frame_rate().value();
+    }
+    adapter_->SetInput(input_mode_, input_pixels_, input_fps_,
+                       encoder_settings_, encoder_target_bitrate_bps_);
+  }
+
+ private:
+  VideoStreamAdapter* adapter_;
+  VideoStreamAdapter::VideoInputMode input_mode_;
+  int input_pixels_;
+  int input_fps_;
+  absl::optional<EncoderSettings> encoder_settings_;
+  absl::optional<uint32_t> encoder_target_bitrate_bps_;
+};
+
+EncoderSettings EncoderSettingsWithMinPixelsPerFrame(int min_pixels_per_frame) {
+  VideoEncoder::EncoderInfo encoder_info;
+  encoder_info.scaling_settings.min_pixels_per_frame = min_pixels_per_frame;
+  return EncoderSettings(std::move(encoder_info), VideoEncoderConfig(),
+                         VideoCodec());
+}
+
+EncoderSettings EncoderSettingsWithBitrateLimits(int resolution_pixels,
+                                                 int min_start_bitrate_bps) {
+  VideoEncoder::EncoderInfo encoder_info;
+  // For bitrate limits, we only care about the next resolution up's
+  // min_start_bitrate_bps. (...Why do we look at start bitrate and not min
+  // bitrate?)
+  encoder_info.resolution_bitrate_limits.emplace_back(
+      resolution_pixels,
+      /* min_start_bitrate_bps */ min_start_bitrate_bps,
+      /* min_bitrate_bps */ 0,
+      /* max_bitrate_bps */ 0);
+  return EncoderSettings(std::move(encoder_info), VideoEncoderConfig(),
+                         VideoCodec());
+}
+
+}  // namespace
+
+TEST(VideoStreamAdapterTest, NoRestrictionsByDefault) {
+  VideoStreamAdapter adapter;
+  EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_EQ(0, adapter.adaptation_counters().Total());
+}
+
+TEST(VideoStreamAdapterTest, MaintainFramerate_DecreasesPixelsToThreeFifths) {
+  const int kInputPixels = 1280 * 720;
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                   kInputPixels, 30, absl::nullopt, absl::nullopt);
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+  EXPECT_FALSE(adaptation.min_pixel_limit_reached());
+  adapter.ApplyAdaptation(adaptation);
+  EXPECT_EQ(static_cast<size_t>((kInputPixels * 3) / 5),
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt, adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, MaintainFramerate_DecreasesPixelsToLimitReached) {
+  const int kMinPixelsPerFrame = 640 * 480;
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                   kMinPixelsPerFrame + 1, 30,
+                   EncoderSettingsWithMinPixelsPerFrame(kMinPixelsPerFrame),
+                   absl::nullopt);
+  // Even though we are above kMinPixelsPerFrame, because adapting down would
+  // have exceeded the limit, we are said to have reached the limit already.
+  // This differs from the frame rate adaptation logic, which would have clamped
+  // to the limit in the first step and reported kLimitReached in the second
+  // step.
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  EXPECT_EQ(Adaptation::Status::kLimitReached, adaptation.status());
+  EXPECT_TRUE(adaptation.min_pixel_limit_reached());
+}
+
+TEST(VideoStreamAdapterTest, MaintainFramerate_IncreasePixelsToFiveThirds) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // Go down twice, ensuring going back up is still a restricted resolution.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(2, adapter.adaptation_counters().resolution_adaptations);
+  int input_pixels = fake_stream.input_pixels();
+  // Go up once. The target is 5/3 and the max is 12/5 of the target.
+  const int target = (input_pixels * 5) / 3;
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationUp(kReasonDontCare));
+  EXPECT_EQ(static_cast<size_t>((target * 12) / 5),
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(static_cast<size_t>(target),
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt, adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, MaintainFramerate_IncreasePixelsToUnrestricted) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // We are unrestricted by default and should not be able to adapt up.
+  EXPECT_EQ(Adaptation::Status::kLimitReached,
+            adapter.GetAdaptationUp(kReasonDontCare).status());
+  // If we go down once and then back up we should not have any restrictions.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationUp(kReasonDontCare));
+  EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_EQ(0, adapter.adaptation_counters().Total());
+}
+
+TEST(VideoStreamAdapterTest, MaintainResolution_DecreasesFpsToTwoThirds) {
+  const int kInputFps = 30;
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   kInputFps, absl::nullopt, absl::nullopt);
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+  adapter.ApplyAdaptation(adaptation);
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>((kInputFps * 2) / 3),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, MaintainResolution_DecreasesFpsToLimitReached) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  FakeVideoStream fake_stream(
+      &adapter, VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+      kMinFrameRateFps + 1, absl::nullopt, absl::nullopt);
+  // If we are not yet at the limit and the next step would exceed it, the step
+  // is clamped such that we end up exactly on the limit.
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+  fake_stream.ApplyAdaptation(adaptation);
+  EXPECT_EQ(static_cast<double>(kMinFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  // Having reached the limit, the next adaptation down is not valid.
+  EXPECT_EQ(Adaptation::Status::kLimitReached,
+            adapter.GetAdaptationDown().status());
+}
+
+TEST(VideoStreamAdapterTest, MaintainResolution_IncreaseFpsToThreeHalves) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // Go down twice, ensuring going back up is still a restricted frame rate.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(2, adapter.adaptation_counters().fps_adaptations);
+  int input_fps = fake_stream.input_fps();
+  // Go up once. The target is 3/2 of the input.
+  Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+  EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+  fake_stream.ApplyAdaptation(adaptation);
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>((input_fps * 3) / 2),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, MaintainResolution_IncreaseFpsToUnrestricted) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // We are unrestricted by default and should not be able to adapt up.
+  EXPECT_EQ(Adaptation::Status::kLimitReached,
+            adapter.GetAdaptationUp(kReasonDontCare).status());
+  // If we go down once and then back up we should not have any restrictions.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationUp(kReasonDontCare));
+  EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_EQ(0, adapter.adaptation_counters().Total());
+}
+
+TEST(VideoStreamAdapterTest, Balanced_DecreaseFrameRate) {
+  webrtc::test::ScopedFieldTrials balanced_field_trials(
+      BalancedFieldTrialConfig());
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::BALANCED);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                   kBalancedMediumResolutionPixels, kBalancedHighFrameRateFps,
+                   absl::nullopt, absl::nullopt);
+  // If our frame rate is higher than the frame rate associated with our
+  // resolution we should try to adapt to the frame rate associated with our
+  // resolution: kBalancedMediumFrameRateFps.
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+  adapter.ApplyAdaptation(adaptation);
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>(kBalancedMediumFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(0, adapter.adaptation_counters().resolution_adaptations);
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, Balanced_DecreaseResolution) {
+  webrtc::test::ScopedFieldTrials balanced_field_trials(
+      BalancedFieldTrialConfig());
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::BALANCED);
+  FakeVideoStream fake_stream(
+      &adapter, VideoStreamAdapter::VideoInputMode::kNormalVideo,
+      kBalancedHighResolutionPixels, kBalancedHighFrameRateFps, absl::nullopt,
+      absl::nullopt);
+  // If we are not below the current resolution's frame rate limit, we should
+  // adapt resolution according to "maintain-framerate" logic (three fifths).
+  //
+  // However, since we are unlimited at the start and input frame rate is not
+  // below kBalancedHighFrameRateFps, we first restrict the frame rate to
+  // kBalancedHighFrameRateFps even though that is our current frame rate. This
+  // does prevent the source from going higher, though, so it's technically not
+  // a NO-OP.
+  {
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+  }
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(0, adapter.adaptation_counters().resolution_adaptations);
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  // Verify "maintain-framerate" logic the second time we adapt: Frame rate
+  // restrictions remains the same and resolution goes down.
+  {
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+  }
+  constexpr size_t kReducedPixelsFirstStep =
+      static_cast<size_t>((kBalancedHighResolutionPixels * 3) / 5);
+  EXPECT_EQ(kReducedPixelsFirstStep,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  // If we adapt again, because the balanced settings' proposed frame rate is
+  // still kBalancedHighFrameRateFps, "maintain-framerate" will trigger again.
+  static_assert(kReducedPixelsFirstStep > kBalancedMediumResolutionPixels,
+                "The reduced resolution is still greater than the next lower "
+                "balanced setting resolution");
+  constexpr size_t kReducedPixelsSecondStep = (kReducedPixelsFirstStep * 3) / 5;
+  {
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+  }
+  EXPECT_EQ(kReducedPixelsSecondStep,
+            adapter.source_restrictions().max_pixels_per_frame());
+  EXPECT_EQ(absl::nullopt,
+            adapter.source_restrictions().target_pixels_per_frame());
+  EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(2, adapter.adaptation_counters().resolution_adaptations);
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+}
+
+// Testing when to adapt frame rate and when to adapt resolution is quite
+// entangled, so this test covers both cases.
+//
+// There is an asymmetry: When we adapt down we do it in one order, but when we
+// adapt up we don't do it in the reverse order. Instead we always try to adapt
+// frame rate first according to balanced settings' configs and only when the
+// frame rate is already achieved do we adjust the resolution.
+TEST(VideoStreamAdapterTest, Balanced_IncreaseFrameRateAndResolution) {
+  webrtc::test::ScopedFieldTrials balanced_field_trials(
+      BalancedFieldTrialConfig());
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::BALANCED);
+  FakeVideoStream fake_stream(
+      &adapter, VideoStreamAdapter::VideoInputMode::kNormalVideo,
+      kBalancedHighResolutionPixels, kBalancedHighFrameRateFps, absl::nullopt,
+      absl::nullopt);
+  // The desired starting point of this test is having adapted frame rate twice.
+  // This requires performing a number of adaptations.
+  constexpr size_t kReducedPixelsFirstStep =
+      static_cast<size_t>((kBalancedHighResolutionPixels * 3) / 5);
+  constexpr size_t kReducedPixelsSecondStep = (kReducedPixelsFirstStep * 3) / 5;
+  constexpr size_t kReducedPixelsThirdStep = (kReducedPixelsSecondStep * 3) / 5;
+  static_assert(kReducedPixelsFirstStep > kBalancedMediumResolutionPixels,
+                "The first pixel reduction is greater than the balanced "
+                "settings' medium pixel configuration");
+  static_assert(kReducedPixelsSecondStep > kBalancedMediumResolutionPixels,
+                "The second pixel reduction is greater than the balanced "
+                "settings' medium pixel configuration");
+  static_assert(kReducedPixelsThirdStep <= kBalancedMediumResolutionPixels,
+                "The third pixel reduction is NOT greater than the balanced "
+                "settings' medium pixel configuration");
+  // The first adaptation should affect the frame rate: See
+  // Balanced_DecreaseResolution for explanation why.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  // The next three adaptations affects the resolution, because we have to reach
+  // kBalancedMediumResolutionPixels before a lower frame rate is considered by
+  // BalancedDegradationSettings. The number three is derived from the
+  // static_asserts above.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(kReducedPixelsFirstStep,
+            adapter.source_restrictions().max_pixels_per_frame());
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(kReducedPixelsSecondStep,
+            adapter.source_restrictions().max_pixels_per_frame());
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(kReducedPixelsThirdStep,
+            adapter.source_restrictions().max_pixels_per_frame());
+  // Thus, the next adaptation will reduce frame rate to
+  // kBalancedMediumFrameRateFps.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(static_cast<double>(kBalancedMediumFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(3, adapter.adaptation_counters().resolution_adaptations);
+  EXPECT_EQ(2, adapter.adaptation_counters().fps_adaptations);
+  // Adapt up!
+  // While our resolution is in the medium-range, the frame rate associated with
+  // the next resolution configuration up ("high") is kBalancedHighFrameRateFps
+  // and "balanced" prefers adapting frame rate if not already applied.
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(static_cast<double>(kBalancedHighFrameRateFps),
+              adapter.source_restrictions().max_frame_rate());
+    EXPECT_EQ(3, adapter.adaptation_counters().resolution_adaptations);
+    EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  }
+  // Now that we have already achieved the next frame rate up, we act according
+  // to "maintain-framerate". We go back up in resolution. Due to rounding
+  // errors we don't end up back at kReducedPixelsSecondStep. Rather we get to
+  // kReducedPixelsSecondStepUp, which is off by one compared to
+  // kReducedPixelsSecondStep.
+  constexpr size_t kReducedPixelsSecondStepUp =
+      (kReducedPixelsThirdStep * 5) / 3;
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(kReducedPixelsSecondStepUp,
+              adapter.source_restrictions().target_pixels_per_frame());
+    EXPECT_EQ(2, adapter.adaptation_counters().resolution_adaptations);
+    EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  }
+  // Now that our resolution is back in the high-range, the next frame rate to
+  // try out is "unlimited".
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(absl::nullopt, adapter.source_restrictions().max_frame_rate());
+    EXPECT_EQ(2, adapter.adaptation_counters().resolution_adaptations);
+    EXPECT_EQ(0, adapter.adaptation_counters().fps_adaptations);
+  }
+  // Now only adapting resolution remains.
+  constexpr size_t kReducedPixelsFirstStepUp =
+      (kReducedPixelsSecondStepUp * 5) / 3;
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(kReducedPixelsFirstStepUp,
+              adapter.source_restrictions().target_pixels_per_frame());
+    EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+    EXPECT_EQ(0, adapter.adaptation_counters().fps_adaptations);
+  }
+  // The last step up should make us entirely unrestricted.
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+    EXPECT_EQ(0, adapter.adaptation_counters().Total());
+  }
+}
+
+TEST(VideoStreamAdapterTest, Balanced_LimitReached) {
+  webrtc::test::ScopedFieldTrials balanced_field_trials(
+      BalancedFieldTrialConfig());
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::BALANCED);
+  FakeVideoStream fake_stream(
+      &adapter, VideoStreamAdapter::VideoInputMode::kNormalVideo,
+      kBalancedLowResolutionPixels, kBalancedLowFrameRateFps, absl::nullopt,
+      absl::nullopt);
+  // Attempting to adapt up while unrestricted should result in kLimitReached.
+  EXPECT_EQ(Adaptation::Status::kLimitReached,
+            adapter.GetAdaptationUp(kReasonDontCare).status());
+  // Adapting down once result in restricted frame rate, in this case we reach
+  // the lowest possible frame rate immediately: kBalancedLowFrameRateFps.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(static_cast<double>(kBalancedLowFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+  // Any further adaptation must follow "maintain-framerate" rules (these are
+  // covered in more depth by the MaintainFramerate tests). This test does not
+  // assert exactly how resolution is adjusted, only that resolution always
+  // decreases and that we eventually reach kLimitReached.
+  size_t previous_resolution = kBalancedLowResolutionPixels;
+  bool did_reach_limit = false;
+  // If we have not reached the limit within 5 adaptations something is wrong...
+  for (int i = 0; i < 5; i++) {
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    if (adaptation.status() == Adaptation::Status::kLimitReached) {
+      did_reach_limit = true;
+      break;
+    }
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_LT(adapter.source_restrictions().max_pixels_per_frame().value(),
+              previous_resolution);
+    previous_resolution =
+        adapter.source_restrictions().max_pixels_per_frame().value();
+  }
+  EXPECT_TRUE(did_reach_limit);
+  // Frame rate restrictions are the same as before.
+  EXPECT_EQ(static_cast<double>(kBalancedLowFrameRateFps),
+            adapter.source_restrictions().max_frame_rate());
+  EXPECT_EQ(1, adapter.adaptation_counters().fps_adaptations);
+}
+
+TEST(VideoStreamAdapterTest, AdaptationDisabled) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::DISABLED);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   30, absl::nullopt, absl::nullopt);
+  EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
+            adapter.GetAdaptationDown().status());
+  EXPECT_EQ(Adaptation::Status::kAdaptationDisabled,
+            adapter.GetAdaptationUp(kReasonDontCare).status());
+}
+
+TEST(VideoStreamAdapterTest, InsufficientInput) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  // No vido is insufficient in either direction.
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNoVideo, 1280 * 720, 30,
+                   absl::nullopt, absl::nullopt);
+  EXPECT_EQ(Adaptation::Status::kInsufficientInput,
+            adapter.GetAdaptationDown().status());
+  EXPECT_EQ(Adaptation::Status::kInsufficientInput,
+            adapter.GetAdaptationUp(kReasonDontCare).status());
+  // No frame rate is insufficient when going down.
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   0, absl::nullopt, absl::nullopt);
+  EXPECT_EQ(Adaptation::Status::kInsufficientInput,
+            adapter.GetAdaptationDown().status());
+}
+
+// kAwaitingPreviousAdaptation is only supported in "maintain-framerate".
+TEST(VideoStreamAdapterTest, MaintainFramerate_AwaitingPreviousAdaptationDown) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   30, absl::nullopt, absl::nullopt);
+  // Adapt down once, but don't update the input.
+  adapter.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+  {
+    // Having performed the adaptation, but not updated the input based on the
+    // new restrictions, adapting again in the same direction will not work.
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
+              adaptation.status());
+  }
+}
+
+// kAwaitingPreviousAdaptation is only supported in "maintain-framerate".
+TEST(VideoStreamAdapterTest, MaintainFramerate_AwaitingPreviousAdaptationUp) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // Perform two adaptation down so that adapting up twice is possible.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(2, adapter.adaptation_counters().resolution_adaptations);
+  // Adapt up once, but don't update the input.
+  adapter.ApplyAdaptation(adapter.GetAdaptationUp(kReasonDontCare));
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+  {
+    // Having performed the adaptation, but not updated the input based on the
+    // new restrictions, adapting again in the same direction will not work.
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kAwaitingPreviousAdaptation,
+              adaptation.status());
+  }
+}
+
+// TODO(hbos): Also add BitrateConstrained test coverage for the BALANCED
+// degradation preference.
+TEST(VideoStreamAdapterTest, BitrateConstrained_MaintainFramerate) {
+  const int kInputPixels = 1280 * 720;
+  const int kBitrateLimit = 1000;
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  FakeVideoStream fake_stream(
+      &adapter, VideoStreamAdapter::VideoInputMode::kNormalVideo, kInputPixels,
+      30, EncoderSettingsWithBitrateLimits(kInputPixels, kBitrateLimit),
+      // The target bitrate is one less than necessary
+      // to adapt up.
+      kBitrateLimit - 1);
+  // Adapt down so that it would be possible to adapt up if we weren't bitrate
+  // constrainted.
+  fake_stream.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_EQ(1, adapter.adaptation_counters().resolution_adaptations);
+  // Adapting up for reason kQuality should not work because this exceeds the
+  // bitrate limit.
+  // TODO(hbos): Why would the reason matter? If the signal was kCpu then the
+  // current code allows us to violate this bitrate constraint. This does not
+  // make any sense: either we are limited or we are not, end of story.
+  EXPECT_EQ(
+      Adaptation::Status::kIsBitrateConstrained,
+      adapter
+          .GetAdaptationUp(AdaptationObserverInterface::AdaptReason::kQuality)
+          .status());
+}
+
+TEST(VideoStreamAdapterTest, PeekNextRestrictions) {
+  VideoStreamAdapter adapter;
+  // Any non-disabled DegradationPreference will do.
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  FakeVideoStream fake_stream(&adapter,
+                              VideoStreamAdapter::VideoInputMode::kNormalVideo,
+                              1280 * 720, 30, absl::nullopt, absl::nullopt);
+  // When adaptation is not possible.
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kLimitReached, adaptation.status());
+    EXPECT_EQ(adapter.PeekNextRestrictions(adaptation),
+              adapter.source_restrictions());
+  }
+  // When we adapt down.
+  {
+    Adaptation adaptation = adapter.GetAdaptationDown();
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    VideoSourceRestrictions next_restrictions =
+        adapter.PeekNextRestrictions(adaptation);
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(next_restrictions, adapter.source_restrictions());
+  }
+  // When we adapt up.
+  {
+    Adaptation adaptation = adapter.GetAdaptationUp(kReasonDontCare);
+    EXPECT_EQ(Adaptation::Status::kValid, adaptation.status());
+    VideoSourceRestrictions next_restrictions =
+        adapter.PeekNextRestrictions(adaptation);
+    fake_stream.ApplyAdaptation(adaptation);
+    EXPECT_EQ(next_restrictions, adapter.source_restrictions());
+  }
+}
+
+// This test covers non-standard behavior. If the application desires
+// "maintain-resolution" it should ask for it rather than relying on this
+// behavior, which should become unsupported.
+TEST(VideoStreamAdapterTest, BalancedScreenshareBehavesLikeMaintainResolution) {
+  const int kInputPixels = 1280 * 720;
+  const int kInputFps = 30;
+  VideoStreamAdapter balanced_adapter;
+  balanced_adapter.SetDegradationPreference(DegradationPreference::BALANCED);
+  balanced_adapter.SetInput(
+      VideoStreamAdapter::VideoInputMode::kScreenshareVideo, kInputPixels,
+      kInputFps, absl::nullopt, absl::nullopt);
+  VideoStreamAdapter maintain_resolution_adapter;
+  maintain_resolution_adapter.SetDegradationPreference(
+      DegradationPreference::MAINTAIN_RESOLUTION);
+  maintain_resolution_adapter.SetInput(
+      VideoStreamAdapter::VideoInputMode::kNormalVideo, kInputPixels, kInputFps,
+      absl::nullopt, absl::nullopt);
+  EXPECT_EQ(balanced_adapter.source_restrictions(),
+            maintain_resolution_adapter.source_restrictions());
+  balanced_adapter.ApplyAdaptation(balanced_adapter.GetAdaptationDown());
+  maintain_resolution_adapter.ApplyAdaptation(
+      maintain_resolution_adapter.GetAdaptationDown());
+  EXPECT_EQ(balanced_adapter.source_restrictions(),
+            maintain_resolution_adapter.source_restrictions());
+}
+
+TEST(VideoStreamAdapterTest,
+     SetDegradationPreferenceToOrFromBalancedClearsRestrictions) {
+  VideoStreamAdapter adapter;
+  EXPECT_EQ(VideoStreamAdapter::SetDegradationPreferenceResult::
+                kRestrictionsNotCleared,
+            adapter.SetDegradationPreference(
+                DegradationPreference::MAINTAIN_FRAMERATE));
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   30, absl::nullopt, absl::nullopt);
+  adapter.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_NE(0, adapter.adaptation_counters().Total());
+  // Changing from non-balanced to balanced clears the restrictions.
+  EXPECT_EQ(
+      VideoStreamAdapter::SetDegradationPreferenceResult::kRestrictionsCleared,
+      adapter.SetDegradationPreference(DegradationPreference::BALANCED));
+  EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_EQ(0, adapter.adaptation_counters().Total());
+  // Apply adaptation again.
+  adapter.ApplyAdaptation(adapter.GetAdaptationDown());
+  EXPECT_NE(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_NE(0, adapter.adaptation_counters().Total());
+  // Changing from balanced to non-balanced clears the restrictions.
+  EXPECT_EQ(
+      VideoStreamAdapter::SetDegradationPreferenceResult::kRestrictionsCleared,
+      adapter.SetDegradationPreference(
+          DegradationPreference::MAINTAIN_RESOLUTION));
+  EXPECT_EQ(VideoSourceRestrictions(), adapter.source_restrictions());
+  EXPECT_EQ(0, adapter.adaptation_counters().Total());
+}
+
+// Death tests.
+// Disabled on Android because death tests misbehave on Android, see
+// base/test/gtest_util.h.
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+TEST(VideoStreamAdapterDeathTest,
+     SetDegradationPreferenceInvalidatesAdaptations) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_FRAMERATE);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   30, absl::nullopt, absl::nullopt);
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  EXPECT_DEATH(adapter.ApplyAdaptation(adaptation), "");
+}
+
+TEST(VideoStreamAdapterDeathTest, SetInputInvalidatesAdaptations) {
+  VideoStreamAdapter adapter;
+  adapter.SetDegradationPreference(DegradationPreference::MAINTAIN_RESOLUTION);
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   30, absl::nullopt, absl::nullopt);
+  Adaptation adaptation = adapter.GetAdaptationDown();
+  adapter.SetInput(VideoStreamAdapter::VideoInputMode::kNormalVideo, 1280 * 720,
+                   31, absl::nullopt, absl::nullopt);
+  EXPECT_DEATH(adapter.PeekNextRestrictions(adaptation), "");
+}
+
+#endif  // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+}  // namespace webrtc