Handle BW drop in ALR region and initiate probing

Original change by isheriff@chromium.org: http://crrev.com/2387463002#ps40001

BUG=webrtc:6332
TBR=philipel@webrtc.org, stefan@webrtc.org

Review URL: https://codereview.webrtc.org/2432633002 .

Patch from Irfan Sheriff <isheriff@chromium.org>.

Cr-Commit-Position: refs/heads/master@{#14673}
diff --git a/webrtc/modules/congestion_controller/probe_controller.cc b/webrtc/modules/congestion_controller/probe_controller.cc
index 2e253f1..e7bf1fc 100644
--- a/webrtc/modules/congestion_controller/probe_controller.cc
+++ b/webrtc/modules/congestion_controller/probe_controller.cc
@@ -14,6 +14,7 @@
 #include <initializer_list>
 
 #include "webrtc/base/logging.h"
+#include "webrtc/system_wrappers/include/metrics.h"
 
 namespace webrtc {
 
@@ -35,6 +36,10 @@
 // A limit to prevent probing at excessive bitrates.
 constexpr int kMaxProbingBitrateBps = 10000000;
 
+// This is a limit on how often probing can be done when there is a BW
+// drop detected in ALR region.
+constexpr int kAlrProbingIntervalLimitMs = 5000;
+
 }  // namespace
 
 ProbeController::ProbeController(PacedSender* pacer, Clock* clock)
@@ -44,7 +49,8 @@
       min_bitrate_to_probe_further_bps_(kExponentialProbingDisabled),
       time_last_probing_initiated_ms_(0),
       estimated_bitrate_bps_(0),
-      max_bitrate_bps_(0) {}
+      max_bitrate_bps_(0),
+      last_alr_probing_time_(clock_->TimeInMilliseconds()) {}
 
 void ProbeController::SetBitrates(int min_bitrate_bps,
                                   int start_bitrate_bps,
@@ -92,6 +98,30 @@
         InitiateProbing({2 * bitrate_bps}, 1.25 * bitrate_bps);
       }
     }
+  } else {
+    // A drop in estimated BW when operating in ALR and not already probing.
+    // The current response is to initiate a single probe session at the
+    // previous bitrate and immediately use the reported bitrate as the new
+    // bitrate.
+    //
+    // If the probe session fails, the assumption is that this drop was a
+    // real one from a competing flow or something else on the network and
+    // it ramps up from bitrate_bps.
+    if (pacer_->InApplicationLimitedRegion() &&
+        bitrate_bps < 0.5 * estimated_bitrate_bps_) {
+      int64_t now_ms = clock_->TimeInMilliseconds();
+      if ((now_ms - last_alr_probing_time_) > kAlrProbingIntervalLimitMs) {
+        LOG(LS_INFO) << "Detected big BW drop in ALR, start probe.";
+        // Track how often we probe in response to BW drop in ALR.
+        RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.AlrProbingIntervalInS",
+                                   (now_ms - last_alr_probing_time_) / 1000);
+        InitiateProbing({estimated_bitrate_bps_}, kExponentialProbingDisabled);
+        last_alr_probing_time_ = now_ms;
+      }
+    }
+    // TODO(isheriff): May want to track when we did ALR probing in order
+    // to reset |last_alr_probing_time_| if we validate that it was a
+    // drop due to exogenous event.
   }
   estimated_bitrate_bps_ = bitrate_bps;
 }
diff --git a/webrtc/modules/congestion_controller/probe_controller.h b/webrtc/modules/congestion_controller/probe_controller.h
index 4cf34c3..efcc2a1 100644
--- a/webrtc/modules/congestion_controller/probe_controller.h
+++ b/webrtc/modules/congestion_controller/probe_controller.h
@@ -53,6 +53,7 @@
   int64_t time_last_probing_initiated_ms_ GUARDED_BY(critsect_);
   int estimated_bitrate_bps_ GUARDED_BY(critsect_);
   int max_bitrate_bps_ GUARDED_BY(critsect_);
+  int64_t last_alr_probing_time_ GUARDED_BY(critsect_);
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
 };
diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc
index 6c5e183..d38154a 100644
--- a/webrtc/modules/pacing/paced_sender.cc
+++ b/webrtc/modules/pacing/paced_sender.cc
@@ -343,6 +343,11 @@
                               pacing_bitrate_kbps_);
 }
 
+bool PacedSender::InApplicationLimitedRegion() const {
+  CriticalSectionScoped cs(critsect_.get());
+  return alr_detector_->InApplicationLimitedRegion();
+}
+
 size_t PacedSender::QueueSizePackets() const {
   CriticalSectionScoped cs(critsect_.get());
   return packets_->SizeInPackets();
diff --git a/webrtc/modules/pacing/paced_sender.h b/webrtc/modules/pacing/paced_sender.h
index b11ae17..ee50f2e 100644
--- a/webrtc/modules/pacing/paced_sender.h
+++ b/webrtc/modules/pacing/paced_sender.h
@@ -120,6 +120,13 @@
   // packets in the queue, given the current size and bitrate, ignoring prio.
   virtual int64_t ExpectedQueueTimeMs() const;
 
+  // Application Limited Region refers to operating in a state where the
+  // traffic on network is limited due to application not having enough
+  // traffic to meet the current channel capacity.
+  //
+  // Returns true if network is currently application-limited.
+  bool InApplicationLimitedRegion() const;
+
   // Returns the average time since being enqueued, in milliseconds, for all
   // packets currently in the pacer queue, or 0 if queue is empty.
   virtual int64_t AverageQueueTimeMs();