[Overuse] Implement Resource and ResourceUsageListener.

The Resource interface (previously a skeleton not used outside of
testing) is updated to inform listeners of changes to resource
usage. Debugging methods are removed (Name, UsageUnitsOfMeasurements,
CurrentUsage). The interface is implemented by
OveruseFrameDetectorResourceAdaptationModule's inner classes
EncodeUsageResource and QualityScalerResource.

The new ResourceUsageListener interface is implemented by
OveruseFrameDetectorResourceAdaptationModule. In order to avoid adding
AdaptationObserverInterface::AdaptReason to the ResourceUsageListener
interface, the module figures out if the reason is "kCpu" or "kQuality"
by looking which Resource object triggered
OnResourceUsageStateMeasured(). These resources no longer need an
explicit reference to OveruseFrameDetectorResourceAdaptationModule and
could potentially be used by a different module.

In this CL, AdaptationObserverInterface::AdaptDown()'s return value is
still needed by QualityScaler. This is mirrored in the return value of
ResourceUsageListener::OnResourceUsageStateMeasured(). A TODO is added
to remove it and a comment explains how the current implementation
seems to break the contract of the method (as was the case prior to
this CL).

Follow-up work include:
- Move EncodeUsageResource and QualityScalerResource to separate files.
- Make resources injectable, allowing fake resources in testing and
  removing OnResourceOveruseForTesting() methods.
  (Investigate adding the necessary input signals to the Resource
  interface or relevant sub-interfaces so that the module does not need
  to know which Resource implementation is used.)
- And more! See whiteboard :)

Bug: webrtc:11222
Change-Id: I0a46ace4a2e617874e3ee97e67e3a199fef420a2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168180
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#30469}
diff --git a/call/adaptation/resource.cc b/call/adaptation/resource.cc
index e6974b1..d599207 100644
--- a/call/adaptation/resource.cc
+++ b/call/adaptation/resource.cc
@@ -10,32 +10,36 @@
 
 #include "call/adaptation/resource.h"
 
-#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/checks.h"
 
 namespace webrtc {
 
-namespace {
+ResourceListener::~ResourceListener() {}
 
-const char* ResourceUsageStateToString(ResourceUsageState usage_state) {
-  switch (usage_state) {
-    case ResourceUsageState::kOveruse:
-      return "overuse";
-    case ResourceUsageState::kStable:
-      return "stable";
-    case ResourceUsageState::kUnderuse:
-      return "underuse";
-  }
-}
-
-}  // namespace
+Resource::Resource() : usage_state_(ResourceUsageState::kStable) {}
 
 Resource::~Resource() {}
 
-std::string Resource::ToString() const {
-  rtc::StringBuilder sb;
-  sb << Name() << ": " << CurrentUsage() << " " << UsageUnitsOfMeasurement();
-  sb << " (" << ResourceUsageStateToString(CurrentUsageState()) << ")";
-  return sb.str();
+void Resource::RegisterListener(ResourceListener* listener) {
+  RTC_DCHECK(listener);
+  listeners_.push_back(listener);
+}
+
+ResourceUsageState Resource::usage_state() const {
+  return usage_state_;
+}
+
+ResourceListenerResponse Resource::OnResourceUsageStateMeasured(
+    ResourceUsageState usage_state) {
+  ResourceListenerResponse response = ResourceListenerResponse::kNothing;
+  usage_state_ = usage_state;
+  for (auto* listener : listeners_) {
+    ResourceListenerResponse listener_response =
+        listener->OnResourceUsageStateMeasured(*this);
+    if (listener_response != ResourceListenerResponse::kNothing)
+      response = listener_response;
+  }
+  return response;
 }
 
 }  // namespace webrtc
diff --git a/call/adaptation/resource.h b/call/adaptation/resource.h
index 0bd1421..7e6855f 100644
--- a/call/adaptation/resource.h
+++ b/call/adaptation/resource.h
@@ -11,10 +11,14 @@
 #ifndef CALL_ADAPTATION_RESOURCE_H_
 #define CALL_ADAPTATION_RESOURCE_H_
 
-#include <string>
+#include <vector>
+
+#include "absl/types/optional.h"
 
 namespace webrtc {
 
+class Resource;
+
 enum class ResourceUsageState {
   // Action is needed to minimze the load on this resource.
   kOveruse,
@@ -25,32 +29,71 @@
   kUnderuse,
 };
 
+enum class ResourceListenerResponse {
+  kNothing,
+  // This response is only applicable to QualityScaler-based resources.
+  // It tells the QualityScaler to increase its QP measurement frequency.
+  //
+  // This is modelled after AdaptationObserverInterface::AdaptDown()'s return
+  // value. The method comment says "Returns false if a downgrade was requested
+  // but the request did not result in a new limiting resolution or fps."
+  // However the actual implementation seems to be: Return false if
+  // !has_input_video_ or if we use balanced degradation preference and we DID
+  // adapt frame rate but the difference between input frame rate and balanced
+  // settings' min fps is less than the balanced settings' min fps diff - in all
+  // other cases, return true whether or not adaptation happened.
+  //
+  // For QualityScaler-based resources, kQualityScalerShouldIncreaseFrequency
+  // maps to "return false" and kNothing maps to "return true".
+  //
+  // TODO(https://crbug.com/webrtc/11222): Remove this enum. Resource
+  // measurements and adaptation decisions need to be separated in order to
+  // support injectable adaptation modules, multi-stream aware adaptation and
+  // decision-making logic based on multiple resources.
+  kQualityScalerShouldIncreaseFrequency,
+};
+
+class ResourceListener {
+ public:
+  virtual ~ResourceListener();
+
+  // Informs the listener of a new measurement of resource usage. This means
+  // that |resource.usage_state()| is now up-to-date.
+  //
+  // The listener may influence the resource that signaled the measurement
+  // according to the returned ResourceListenerResponse enum.
+  virtual ResourceListenerResponse OnResourceUsageStateMeasured(
+      const Resource& resource) = 0;
+};
+
 // A Resource is something which can be measured as "overused", "stable" or
-// "underused". For example, if we are overusing CPU we may need to lower the
-// resolution of one of the streams. In other words, one of the ResourceConumers
-// - representing an encoder - needs to be reconfigured with a different
-// ResourceConsumerConfiguration - representing a different encoder setting.
+// "underused". When the resource usage changes, listeners of the resource are
+// informed.
 //
-// This is an abstract class used by the ResourceAdaptationProcessor to make
-// decisions about which configurations to use. How a resource is measured or
-// what measurements map to different ResourceUsageState values is
-// implementation-specific.
+// Implementations of this interface are responsible for performing resource
+// usage measurements and invoking OnResourceUsageStateMeasured().
 class Resource {
  public:
+  // By default, usage_state() is kStable until a measurement is made.
+  Resource();
   virtual ~Resource();
 
-  // Informational, not formally part of the decision-making process.
-  virtual std::string Name() const = 0;
-  virtual std::string UsageUnitsOfMeasurement() const = 0;
-  // Valid ranges are implementation-specific.
-  virtual double CurrentUsage() const = 0;
+  // TODO(https://crbug.com/webrtc/11222): Make it possible to unregister
+  // listeners and DCHECK that they're all unregistered in the destructor.
+  void RegisterListener(ResourceListener* listener);
 
-  // The current usage state of this resource. Used by the
-  // ResourceAdaptationProcessor to calculate the desired consumer
-  // configurations.
-  virtual ResourceUsageState CurrentUsageState() const = 0;
+  ResourceUsageState usage_state() const;
 
-  std::string ToString() const;
+ protected:
+  // Updates the usage state and informs all registered listeners.
+  // Returns the result of the last listener's OnResourceUsageStateMeasured()
+  // call that was not kNothing, else kNothing.
+  ResourceListenerResponse OnResourceUsageStateMeasured(
+      ResourceUsageState usage_state);
+
+ private:
+  ResourceUsageState usage_state_;
+  std::vector<ResourceListener*> listeners_;
 };
 
 }  // namespace webrtc
diff --git a/call/adaptation/resource_adaptation_processor.cc b/call/adaptation/resource_adaptation_processor.cc
index e4f209f..151480c 100644
--- a/call/adaptation/resource_adaptation_processor.cc
+++ b/call/adaptation/resource_adaptation_processor.cc
@@ -51,12 +51,11 @@
 ResourceAdaptationProcessor::FindNextConfiguration() {
   ResourceUsageState overall_usage = ResourceUsageState::kUnderuse;
   for (auto& resource : resources_) {
-    ResourceUsageState resource_usage = resource->CurrentUsageState();
-    if (resource_usage == ResourceUsageState::kStable) {
+    if (resource->usage_state() == ResourceUsageState::kStable) {
       // If any resource is "stable", we are not underusing.
       if (overall_usage == ResourceUsageState::kUnderuse)
         overall_usage = ResourceUsageState::kStable;
-    } else if (resource_usage == ResourceUsageState::kOveruse) {
+    } else if (resource->usage_state() == ResourceUsageState::kOveruse) {
       // If any resource is "overuse", we are overusing.
       overall_usage = ResourceUsageState::kOveruse;
       break;
diff --git a/call/adaptation/resource_adaptation_processor_unittest.cc b/call/adaptation/resource_adaptation_processor_unittest.cc
index 38f9fa1..df99aed 100644
--- a/call/adaptation/resource_adaptation_processor_unittest.cc
+++ b/call/adaptation/resource_adaptation_processor_unittest.cc
@@ -189,8 +189,8 @@
   // When the first resource is overused.
   EXPECT_TRUE(processor.FindNextConfiguration().has_value());
   // When the second resource is overused.
-  first_resource->set_usage(ResourceUsageState::kStable);
-  second_resource->set_usage(ResourceUsageState::kOveruse);
+  first_resource->set_usage_state(ResourceUsageState::kStable);
+  second_resource->set_usage_state(ResourceUsageState::kOveruse);
   EXPECT_TRUE(processor.FindNextConfiguration().has_value());
 }
 
@@ -207,7 +207,7 @@
   // When only the first resource is underused.
   EXPECT_EQ(absl::nullopt, processor.FindNextConfiguration());
   // When all resources are underused.
-  second_resource->set_usage(ResourceUsageState::kUnderuse);
+  second_resource->set_usage_state(ResourceUsageState::kUnderuse);
   EXPECT_TRUE(processor.FindNextConfiguration().has_value());
 }
 
@@ -250,7 +250,7 @@
   consumer->SetConfiguration(d);
 
   // We should expect to adapt up: d -> b -> c -> a
-  resource->set_usage(ResourceUsageState::kUnderuse);
+  resource->set_usage_state(ResourceUsageState::kUnderuse);
   EXPECT_EQ(b, processor.FindNextConfiguration()->configuration);
   consumer->SetConfiguration(b);
   EXPECT_EQ(c, processor.FindNextConfiguration()->configuration);
diff --git a/call/adaptation/test/fake_resource.cc b/call/adaptation/test/fake_resource.cc
index 363fc26..b3fe764 100644
--- a/call/adaptation/test/fake_resource.cc
+++ b/call/adaptation/test/fake_resource.cc
@@ -14,39 +14,14 @@
 
 namespace webrtc {
 
-FakeResource::FakeResource(std::string name, ResourceUsageState usage)
-    : name_(std::move(name)), usage_(usage) {}
-
-FakeResource::FakeResource(ResourceUsageState usage)
-    : FakeResource("UnnamedResource", usage) {}
+FakeResource::FakeResource(ResourceUsageState usage_state) : Resource() {
+  set_usage_state(usage_state);
+}
 
 FakeResource::~FakeResource() {}
 
-void FakeResource::set_usage(ResourceUsageState usage) {
-  usage_ = usage;
-}
-
-std::string FakeResource::Name() const {
-  return name_;
-}
-
-std::string FakeResource::UsageUnitsOfMeasurement() const {
-  return "%";
-}
-
-double FakeResource::CurrentUsage() const {
-  switch (usage_) {
-    case ResourceUsageState::kOveruse:
-      return 1.2;
-    case ResourceUsageState::kStable:
-      return 0.8;
-    case ResourceUsageState::kUnderuse:
-      return 0.4;
-  }
-}
-
-ResourceUsageState FakeResource::CurrentUsageState() const {
-  return usage_;
+void FakeResource::set_usage_state(ResourceUsageState usage_state) {
+  OnResourceUsageStateMeasured(usage_state);
 }
 
 }  // namespace webrtc
diff --git a/call/adaptation/test/fake_resource.h b/call/adaptation/test/fake_resource.h
index 60291af..62825c4 100644
--- a/call/adaptation/test/fake_resource.h
+++ b/call/adaptation/test/fake_resource.h
@@ -17,26 +17,13 @@
 
 namespace webrtc {
 
-// Fake resource used for testing. ResourceUsageState is controlled with a
-// setter. The arbitrarily chosen unit of measurement is percentage, with the
-// following current usage reported based on the current usage: kOveruse = 120%,
-// kStable = 80% and kUnderuse = 40%.
+// Fake resource used for testing.
 class FakeResource : public Resource {
  public:
-  FakeResource(std::string name, ResourceUsageState usage);
-  explicit FakeResource(ResourceUsageState usage);
+  explicit FakeResource(ResourceUsageState usage_state);
   ~FakeResource() override;
 
-  void set_usage(ResourceUsageState usage);
-
-  std::string Name() const override;
-  std::string UsageUnitsOfMeasurement() const override;
-  double CurrentUsage() const override;
-  ResourceUsageState CurrentUsageState() const override;
-
- private:
-  std::string name_;
-  ResourceUsageState usage_;
+  void set_usage_state(ResourceUsageState usage_state);
 };
 
 }  // namespace webrtc
diff --git a/modules/video_coding/utility/quality_scaler.h b/modules/video_coding/utility/quality_scaler.h
index 9556a58..29d7ad7 100644
--- a/modules/video_coding/utility/quality_scaler.h
+++ b/modules/video_coding/utility/quality_scaler.h
@@ -28,6 +28,11 @@
 
 // An interface for signaling requests to limit or increase the resolution or
 // framerate of the captured video stream.
+// TODO(hbos): Can we remove AdaptationObserverInterface in favor of
+// ResourceUsageListener? If we need to adapt that is because of resource usage.
+// A multi-stream and multi-resource aware solution needs to sparate the notion
+// of being resource constrained from the decision to downgrade a specific
+// stream.
 class AdaptationObserverInterface {
  public:
   // Indicates if the adaptation is due to overuse of the CPU resources, or if
diff --git a/video/overuse_frame_detector_resource_adaptation_module.cc b/video/overuse_frame_detector_resource_adaptation_module.cc
index 5671607..7f70416 100644
--- a/video/overuse_frame_detector_resource_adaptation_module.cc
+++ b/video/overuse_frame_detector_resource_adaptation_module.cc
@@ -20,6 +20,7 @@
 #include "absl/base/macros.h"
 #include "api/task_queue/task_queue_base.h"
 #include "api/video/video_source_interface.h"
+#include "call/adaptation/resource.h"
 #include "call/adaptation/video_source_restrictions.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_conversions.h"
@@ -74,15 +75,14 @@
 
 // Handles interaction with the OveruseDetector.
 class OveruseFrameDetectorResourceAdaptationModule::EncodeUsageResource
-    : public AdaptationObserverInterface {
+    : public Resource,
+      public AdaptationObserverInterface {
  public:
-  EncodeUsageResource(OveruseFrameDetectorResourceAdaptationModule* module,
-                      std::unique_ptr<OveruseFrameDetector> overuse_detector)
-      : module_(module),
-        overuse_detector_(std::move(overuse_detector)),
+  explicit EncodeUsageResource(
+      std::unique_ptr<OveruseFrameDetector> overuse_detector)
+      : overuse_detector_(std::move(overuse_detector)),
         is_started_(false),
         target_frame_rate_(absl::nullopt) {
-    RTC_DCHECK(module_);
     RTC_DCHECK(overuse_detector_);
   }
 
@@ -125,13 +125,16 @@
   }
 
   // AdaptationObserverInterface implementation.
+  // TODO(https://crbug.com/webrtc/11222, 11172): This resource also needs to
+  // signal when its stable to support multi-stream aware modules.
   void AdaptUp(AdaptReason reason) override {
     RTC_DCHECK_EQ(reason, AdaptReason::kCpu);
-    module_->OnResourceUnderuse(reason);
+    OnResourceUsageStateMeasured(ResourceUsageState::kUnderuse);
   }
   bool AdaptDown(AdaptReason reason) override {
     RTC_DCHECK_EQ(reason, AdaptReason::kCpu);
-    return module_->OnResourceOveruse(reason);
+    return OnResourceUsageStateMeasured(ResourceUsageState::kOveruse) !=
+           ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency;
   }
 
  private:
@@ -141,7 +144,6 @@
                : std::numeric_limits<int>::max();
   }
 
-  OveruseFrameDetectorResourceAdaptationModule* const module_;
   const std::unique_ptr<OveruseFrameDetector> overuse_detector_;
   bool is_started_;
   absl::optional<double> target_frame_rate_;
@@ -149,13 +151,10 @@
 
 // Handles interaction with the QualityScaler.
 class OveruseFrameDetectorResourceAdaptationModule::QualityScalerResource
-    : public AdaptationObserverInterface {
+    : public Resource,
+      public AdaptationObserverInterface {
  public:
-  explicit QualityScalerResource(
-      OveruseFrameDetectorResourceAdaptationModule* module)
-      : module_(module), quality_scaler_(nullptr) {
-    RTC_DCHECK(module_);
-  }
+  QualityScalerResource() : quality_scaler_(nullptr) {}
 
   bool is_started() const { return quality_scaler_.get(); }
   // TODO(https://crbug.com/webrtc/11222): Don't expose the quality scaler.
@@ -199,17 +198,19 @@
   }
 
   // AdaptationObserverInterface implementation.
+  // TODO(https://crbug.com/webrtc/11222, 11172): This resource also needs to
+  // signal when its stable to support multi-stream aware modules.
   void AdaptUp(AdaptReason reason) override {
     RTC_DCHECK_EQ(reason, AdaptReason::kQuality);
-    module_->OnResourceUnderuse(reason);
+    OnResourceUsageStateMeasured(ResourceUsageState::kUnderuse);
   }
   bool AdaptDown(AdaptReason reason) override {
     RTC_DCHECK_EQ(reason, AdaptReason::kQuality);
-    return module_->OnResourceOveruse(reason);
+    return OnResourceUsageStateMeasured(ResourceUsageState::kOveruse) !=
+           ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency;
   }
 
  private:
-  OveruseFrameDetectorResourceAdaptationModule* const module_;
   std::unique_ptr<QualityScaler> quality_scaler_;
 };
 
@@ -483,9 +484,8 @@
       last_adaptation_request_(absl::nullopt),
       source_restrictor_(std::make_unique<VideoSourceRestrictor>()),
       encode_usage_resource_(
-          std::make_unique<EncodeUsageResource>(this,
-                                                std::move(overuse_detector))),
-      quality_scaler_resource_(std::make_unique<QualityScalerResource>(this)),
+          std::make_unique<EncodeUsageResource>(std::move(overuse_detector))),
+      quality_scaler_resource_(std::make_unique<QualityScalerResource>()),
       quality_scaling_experiment_enabled_(QualityScalingExperiment::Enabled()),
       last_input_frame_size_(absl::nullopt),
       target_frame_rate_(absl::nullopt),
@@ -498,6 +498,8 @@
       initial_framedrop_(0) {
   RTC_DCHECK(adaptation_listener_);
   RTC_DCHECK(encoder_stats_observer_);
+  encode_usage_resource_->RegisterListener(this);
+  quality_scaler_resource_->RegisterListener(this);
 }
 
 OveruseFrameDetectorResourceAdaptationModule::
@@ -718,6 +720,46 @@
       GetActiveCounts(AdaptationObserverInterface::AdaptReason::kQuality));
 }
 
+ResourceListenerResponse
+OveruseFrameDetectorResourceAdaptationModule::OnResourceUsageStateMeasured(
+    const Resource& resource) {
+  // If we didn't have this dependency on AdaptReason the module could be
+  // listening to other types of Resources.
+  RTC_DCHECK(&resource == encode_usage_resource_.get() ||
+             &resource == quality_scaler_resource_.get());
+  AdaptationObserverInterface::AdaptReason reason =
+      &resource == encode_usage_resource_.get()
+          ? AdaptationObserverInterface::AdaptReason::kCpu
+          : AdaptationObserverInterface::AdaptReason::kQuality;
+  switch (resource.usage_state()) {
+    case ResourceUsageState::kOveruse:
+      return OnResourceOveruse(reason);
+    case ResourceUsageState::kStable:
+      // Do nothing.
+      //
+      // This module has two resources: |encoude_usage_resource_| and
+      // |quality_scaler_resource_|. A smarter adaptation module might not
+      // attempt to adapt up unless ALL resources were underused, but this
+      // module acts on each resource's measurement in isolation - without
+      // taking the current usage of any other resource into account.
+      return ResourceListenerResponse::kNothing;
+    case ResourceUsageState::kUnderuse:
+      OnResourceUnderuse(reason);
+      return ResourceListenerResponse::kNothing;
+  }
+}
+
+void OveruseFrameDetectorResourceAdaptationModule::OnResourceUnderuseForTesting(
+    AdaptationObserverInterface::AdaptReason reason) {
+  OnResourceUnderuse(reason);
+}
+
+bool OveruseFrameDetectorResourceAdaptationModule::OnResourceOveruseForTesting(
+    AdaptationObserverInterface::AdaptReason reason) {
+  return OnResourceOveruse(reason) !=
+         ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency;
+}
+
 void OveruseFrameDetectorResourceAdaptationModule::OnResourceUnderuse(
     AdaptationObserverInterface::AdaptReason reason) {
   if (!has_input_video_)
@@ -832,10 +874,11 @@
   RTC_LOG(LS_INFO) << adapt_counter.ToString();
 }
 
-bool OveruseFrameDetectorResourceAdaptationModule::OnResourceOveruse(
+ResourceListenerResponse
+OveruseFrameDetectorResourceAdaptationModule::OnResourceOveruse(
     AdaptationObserverInterface::AdaptReason reason) {
   if (!has_input_video_)
-    return false;
+    return ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency;
   AdaptationRequest adaptation_request = {
       LastInputFrameSizeOrDefault(),
       encoder_stats_observer_->GetInputFrameRate(),
@@ -845,8 +888,6 @@
       last_adaptation_request_ &&
       last_adaptation_request_->mode_ == AdaptationRequest::Mode::kAdaptDown;
 
-  bool did_adapt = true;
-
   switch (EffectiveDegradataionPreference()) {
     case DegradationPreference::BALANCED:
       break;
@@ -856,7 +897,7 @@
               last_adaptation_request_->input_pixel_count_) {
         // Don't request lower resolution if the current resolution is not
         // lower than the last time we asked for the resolution to be lowered.
-        return true;
+        return ResourceListenerResponse::kNothing;
       }
       break;
     case DegradationPreference::MAINTAIN_RESOLUTION:
@@ -869,13 +910,15 @@
         // we have to estimate, and can fluctuate naturally over time, don't
         // make the same kind of limitations as for resolution, but trust the
         // overuse detector to not trigger too often.
-        return true;
+        return ResourceListenerResponse::kNothing;
       }
       break;
     case DegradationPreference::DISABLED:
-      return true;
+      return ResourceListenerResponse::kNothing;
   }
 
+  ResourceListenerResponse response = ResourceListenerResponse::kNothing;
+
   switch (EffectiveDegradataionPreference()) {
     case DegradationPreference::BALANCED: {
       // Try scale down framerate, if lower.
@@ -889,7 +932,8 @@
         if (min_diff && adaptation_request.framerate_fps_ > 0) {
           int fps_diff = adaptation_request.framerate_fps_ - fps;
           if (fps_diff < min_diff.value()) {
-            did_adapt = false;
+            response =
+                ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency;
           }
         }
         break;
@@ -909,7 +953,7 @@
               &min_pixels_reached)) {
         if (min_pixels_reached)
           encoder_stats_observer_->OnMinPixelLimitReached();
-        return true;
+        return ResourceListenerResponse::kNothing;
       }
       GetAdaptCounter().IncrementResolution(reason);
       break;
@@ -920,7 +964,7 @@
           source_restrictor_->RequestFramerateLowerThan(
               adaptation_request.framerate_fps_);
       if (requested_framerate == -1)
-        return true;
+        return ResourceListenerResponse::kNothing;
       GetAdaptCounter().IncrementFramerate(reason);
       break;
     }
@@ -937,7 +981,7 @@
   UpdateAdaptationStats(reason);
 
   RTC_LOG(LS_INFO) << GetConstAdaptCounter().ToString();
-  return did_adapt;
+  return response;
 }
 
 // TODO(pbos): Lower these thresholds (to closer to 100%) when we handle
diff --git a/video/overuse_frame_detector_resource_adaptation_module.h b/video/overuse_frame_detector_resource_adaptation_module.h
index 437510b..3deb2f7 100644
--- a/video/overuse_frame_detector_resource_adaptation_module.h
+++ b/video/overuse_frame_detector_resource_adaptation_module.h
@@ -25,6 +25,7 @@
 #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/resource.h"
 #include "call/adaptation/resource_adaptation_module_interface.h"
 #include "rtc_base/experiments/balanced_degradation_settings.h"
 #include "rtc_base/experiments/quality_rampup_experiment.h"
@@ -51,7 +52,8 @@
 // generic interface in VideoStreamEncoder, unblocking other modules from being
 // implemented and used.
 class OveruseFrameDetectorResourceAdaptationModule
-    : public ResourceAdaptationModuleInterface {
+    : public ResourceAdaptationModuleInterface,
+      public ResourceListener {
  public:
   // The module can be constructed on any sequence, but must be initialized and
   // used on a single sequence, e.g. the encoder queue.
@@ -102,14 +104,23 @@
   // (https://crbug.com/webrtc/11338)
   void ConfigureQualityScaler(const VideoEncoder::EncoderInfo& encoder_info);
 
-  // Signal that a resource (kCpu or kQuality) is overused or underused. This is
-  // currently used by EncodeUsageResource, QualityScalerResource and testing.
-  // TODO(https://crbug.com/webrtc/11222): Make use of ResourceUsageState and
-  // implement resources per call/adaptation/resource.h. When adaptation happens
-  // because a resource is in specific usage state, get rid of these explicit
-  // triggers.
-  void OnResourceUnderuse(AdaptationObserverInterface::AdaptReason reason);
-  bool OnResourceOveruse(AdaptationObserverInterface::AdaptReason reason);
+  // ResourceUsageListener implementation.
+  ResourceListenerResponse OnResourceUsageStateMeasured(
+      const Resource& resource) override;
+
+  // Public versions of OnResourceUnderuse/OnResourceOveruse only used for
+  // testing.
+  // TODO(https://crbug.com/webrtc/11222): Control overuse/underuse from testing
+  // by injecting fake resources and remove these methods.
+  void OnResourceUnderuseForTesting(
+      AdaptationObserverInterface::AdaptReason reason);
+  // Returns false if OnResourceOveruse() returns
+  // ResourceListenerResponse::kQualityScalerShouldIncreaseFrequency.
+  // TODO(https://crbug.com/webrtc/11222): Get rid of the
+  // ResourceListenerResponse enum and the boolean return value of
+  // AdaptationObserverInterface::AdaptDown() that this method mimics.
+  bool OnResourceOveruseForTesting(
+      AdaptationObserverInterface::AdaptReason reason);
 
  private:
   class EncodeUsageResource;
@@ -132,6 +143,10 @@
     int64_t set_start_bitrate_time_ms_ = 0;
   };
 
+  void OnResourceUnderuse(AdaptationObserverInterface::AdaptReason reason);
+  ResourceListenerResponse OnResourceOveruse(
+      AdaptationObserverInterface::AdaptReason reason);
+
   CpuOveruseOptions GetCpuOveruseOptions() const;
   VideoCodecType GetVideoCodecTypeOrGeneric() const;
   int LastInputFrameSizeOrDefault() const;
diff --git a/video/overuse_frame_detector_unittest.cc b/video/overuse_frame_detector_unittest.cc
index 432cc27..ad61190 100644
--- a/video/overuse_frame_detector_unittest.cc
+++ b/video/overuse_frame_detector_unittest.cc
@@ -49,11 +49,11 @@
   CpuOveruseObserverImpl() : overuse_(0), normaluse_(0) {}
   virtual ~CpuOveruseObserverImpl() {}
 
-  bool AdaptDown(AdaptReason) {
+  bool AdaptDown(AdaptReason) override {
     ++overuse_;
     return true;
   }
-  void AdaptUp(AdaptReason) { ++normaluse_; }
+  void AdaptUp(AdaptReason) override { ++normaluse_; }
 
   int overuse_;
   int normaluse_;
diff --git a/video/video_stream_encoder.cc b/video/video_stream_encoder.cc
index a8fbac9..1ae4856 100644
--- a/video/video_stream_encoder.cc
+++ b/video/video_stream_encoder.cc
@@ -1580,13 +1580,13 @@
 void VideoStreamEncoder::OnResourceUnderuseForTesting(
     AdaptationObserverInterface::AdaptReason reason) {
   RTC_DCHECK_RUN_ON(&encoder_queue_);
-  resource_adaptation_module_->OnResourceUnderuse(reason);
+  resource_adaptation_module_->OnResourceUnderuseForTesting(reason);
 }
 
 bool VideoStreamEncoder::OnResourceOveruseForTesting(
     AdaptationObserverInterface::AdaptReason reason) {
   RTC_DCHECK_RUN_ON(&encoder_queue_);
-  return resource_adaptation_module_->OnResourceOveruse(reason);
+  return resource_adaptation_module_->OnResourceOveruseForTesting(reason);
 }
 
 void VideoStreamEncoder::OnVideoSourceRestrictionsUpdated(