[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/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