Revert "Revert "Reland "Moved congestion controller to task queue."""

This reverts commit 4e849f6925b2ac44b0957a228d7131fc391fca54.

Reason for revert: <INSERT REASONING HERE>

Original change's description:
> Revert "Reland "Moved congestion controller to task queue.""
> 
> This reverts commit 57daeb7ac7f3d80992905b53fea500953fcfd793.
> 
> Reason for revert: Cause increased congestion and deadlocks in downstream project
> 
> Original change's description:
> > Reland "Moved congestion controller to task queue."
> > 
> > This is a reland of 0cbcba7ea0dced1a7f353c64d6cf91d46ccb29f9.
> > 
> > Original change's description:
> > > Moved congestion controller to task queue.
> > > 
> > > The goal of this work is to make it easier to experiment with the
> > > bandwidth estimation implementation. For this reason network control
> > > functionality is moved from SendSideCongestionController(SSCC),
> > > PacedSender and BitrateController to the newly created
> > > GoogCcNetworkController which implements the newly created
> > > NetworkControllerInterface. This allows the implementation to be
> > > replaced at runtime in the future.
> > > 
> > > This is the first part of a split of a larger CL, see:
> > > https://webrtc-review.googlesource.com/c/src/+/39788/8
> > > For further explanations.
> > > 
> > > Bug: webrtc:8415
> > > Change-Id: I770189c04cc31b313bd4e57821acff55fbcb1ad3
> > > Reviewed-on: https://webrtc-review.googlesource.com/43840
> > > Commit-Queue: Sebastian Jansson <srte@webrtc.org>
> > > Reviewed-by: Björn Terelius <terelius@webrtc.org>
> > > Reviewed-by: Stefan Holmer <stefan@webrtc.org>
> > > Cr-Commit-Position: refs/heads/master@{#21868}
> > 
> > Bug: webrtc:8415
> > Change-Id: I1d1756a30deed5b421b1c91c1918a13b6bb455da
> > Reviewed-on: https://webrtc-review.googlesource.com/48000
> > Reviewed-by: Stefan Holmer <stefan@webrtc.org>
> > Commit-Queue: Sebastian Jansson <srte@webrtc.org>
> > Cr-Commit-Position: refs/heads/master@{#21899}
> 
> TBR=terelius@webrtc.org,stefan@webrtc.org,srte@webrtc.org
> 
> # Not skipping CQ checks because original CL landed > 1 day ago.
> 
> Bug: webrtc:8415
> Change-Id: Ida8074dcac2cc28b3629228eb22846d8a8e81b83
> Reviewed-on: https://webrtc-review.googlesource.com/52980
> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#22017}

TBR=danilchap@webrtc.org,terelius@webrtc.org,stefan@webrtc.org,srte@webrtc.org

Change-Id: I3393b74370c4f4d0955f50728005b2b925be169b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:8415
Reviewed-on: https://webrtc-review.googlesource.com/53262
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22023}
diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc
index 090c261..abb3ad0 100644
--- a/call/rtp_transport_controller_send.cc
+++ b/call/rtp_transport_controller_send.cc
@@ -46,7 +46,8 @@
 void RtpTransportControllerSend::SetAllocatedSendBitrateLimits(
     int min_send_bitrate_bps,
     int max_padding_bitrate_bps) {
-  pacer_.SetSendBitrateLimits(min_send_bitrate_bps, max_padding_bitrate_bps);
+  send_side_cc_.SetSendBitrateLimits(min_send_bitrate_bps,
+                                     max_padding_bitrate_bps);
 }
 
 void RtpTransportControllerSend::SetKeepAliveConfig(
diff --git a/modules/bitrate_controller/bitrate_controller_unittest.cc b/modules/bitrate_controller/bitrate_controller_unittest.cc
index 66ca5b9..8bd7800 100644
--- a/modules/bitrate_controller/bitrate_controller_unittest.cc
+++ b/modules/bitrate_controller/bitrate_controller_unittest.cc
@@ -340,11 +340,11 @@
   report_blocks.clear();
 
   // All packets lost on stream with few packets, no back-off.
-  report_blocks.push_back(CreateReportBlock(1, 2, 1, sequence_number[0]));
+  report_blocks.push_back(CreateReportBlock(1, 2, 0, sequence_number[0]));
   report_blocks.push_back(CreateReportBlock(1, 3, 255, sequence_number[1]));
   bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
   EXPECT_EQ(bitrate_observer_.last_bitrate_, last_bitrate);
-  EXPECT_EQ(WeightedLoss(20, 1, 1, 255), bitrate_observer_.last_fraction_loss_);
+  EXPECT_EQ(WeightedLoss(20, 0, 1, 255), bitrate_observer_.last_fraction_loss_);
   EXPECT_EQ(50, bitrate_observer_.last_rtt_);
   last_bitrate = bitrate_observer_.last_bitrate_;
   sequence_number[0] += 20;
diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/modules/bitrate_controller/send_side_bandwidth_estimation.cc
index d3bce59..323c210 100644
--- a/modules/bitrate_controller/send_side_bandwidth_estimation.cc
+++ b/modules/bitrate_controller/send_side_bandwidth_estimation.cc
@@ -105,7 +105,7 @@
 }  // namespace
 
 SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log)
-    : lost_packets_since_last_loss_update_Q8_(0),
+    : lost_packets_since_last_loss_update_(0),
       expected_packets_since_last_loss_update_(0),
       current_bitrate_bps_(0),
       min_bitrate_configured_(congestion_controller::GetMinBitrateBps()),
@@ -125,6 +125,7 @@
       initially_lost_packets_(0),
       bitrate_at_2_seconds_kbps_(0),
       uma_update_state_(kNoUpdate),
+      uma_rtt_state_(kNoUpdate),
       rampup_uma_stats_updated_(kNumUmaRampupMetrics, false),
       event_log_(event_log),
       last_rtc_event_log_ms_(-1),
@@ -206,24 +207,28 @@
 }
 
 void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
-                                                      int64_t rtt,
+                                                      int64_t rtt_ms,
                                                       int number_of_packets,
                                                       int64_t now_ms) {
+  const int kRoundingConstant = 128;
+  int packets_lost = (static_cast<int>(fraction_loss) * number_of_packets +
+                      kRoundingConstant) >>
+                     8;
+  UpdatePacketsLost(packets_lost, number_of_packets, now_ms);
+  UpdateRtt(rtt_ms, now_ms);
+}
+
+void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost,
+                                                    int number_of_packets,
+                                                    int64_t now_ms) {
   last_feedback_ms_ = now_ms;
   if (first_report_time_ms_ == -1)
     first_report_time_ms_ = now_ms;
 
-  // Update RTT if we were able to compute an RTT based on this RTCP.
-  // FlexFEC doesn't send RTCP SR, which means we won't be able to compute RTT.
-  if (rtt > 0)
-    last_round_trip_time_ms_ = rtt;
-
   // Check sequence number diff and weight loss report
   if (number_of_packets > 0) {
-    // Calculate number of lost packets.
-    const int num_lost_packets_Q8 = fraction_loss * number_of_packets;
     // Accumulate reports.
-    lost_packets_since_last_loss_update_Q8_ += num_lost_packets_Q8;
+    lost_packets_since_last_loss_update_ += packets_lost;
     expected_packets_since_last_loss_update_ += number_of_packets;
 
     // Don't generate a loss rate until it can be based on enough packets.
@@ -231,21 +236,22 @@
       return;
 
     has_decreased_since_last_fraction_loss_ = false;
-    last_fraction_loss_ = lost_packets_since_last_loss_update_Q8_ /
-                          expected_packets_since_last_loss_update_;
+    int64_t lost_q8 = lost_packets_since_last_loss_update_ << 8;
+    int64_t expected = expected_packets_since_last_loss_update_;
+    last_fraction_loss_ = std::min<int>(lost_q8 / expected, 255);
 
     // Reset accumulators.
-    lost_packets_since_last_loss_update_Q8_ = 0;
+
+    lost_packets_since_last_loss_update_ = 0;
     expected_packets_since_last_loss_update_ = 0;
     last_packet_report_ms_ = now_ms;
     UpdateEstimate(now_ms);
   }
-  UpdateUmaStats(now_ms, rtt, (fraction_loss * number_of_packets) >> 8);
+  UpdateUmaStatsPacketsLost(now_ms, packets_lost);
 }
 
-void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms,
-                                                 int64_t rtt,
-                                                 int lost_packets) {
+void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(int64_t now_ms,
+                                                            int packets_lost) {
   int bitrate_kbps = static_cast<int>((current_bitrate_bps_ + 500) / 1000);
   for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) {
     if (!rampup_uma_stats_updated_[i] &&
@@ -256,14 +262,12 @@
     }
   }
   if (IsInStartPhase(now_ms)) {
-    initially_lost_packets_ += lost_packets;
+    initially_lost_packets_ += packets_lost;
   } else if (uma_update_state_ == kNoUpdate) {
     uma_update_state_ = kFirstDone;
     bitrate_at_2_seconds_kbps_ = bitrate_kbps;
     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitiallyLostPackets",
                          initially_lost_packets_, 0, 100, 50);
-    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", static_cast<int>(rtt), 0,
-                         2000, 50);
     RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate",
                          bitrate_at_2_seconds_kbps_, 0, 2000, 50);
   } else if (uma_update_state_ == kFirstDone &&
@@ -276,6 +280,19 @@
   }
 }
 
+void SendSideBandwidthEstimation::UpdateRtt(int64_t rtt_ms, int64_t now_ms) {
+  // Update RTT if we were able to compute an RTT based on this RTCP.
+  // FlexFEC doesn't send RTCP SR, which means we won't be able to compute RTT.
+  if (rtt_ms > 0)
+    last_round_trip_time_ms_ = rtt_ms;
+
+  if (!IsInStartPhase(now_ms) && uma_rtt_state_ == kNoUpdate) {
+    uma_rtt_state_ = kDone;
+    RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", static_cast<int>(rtt_ms), 0,
+                         2000, 50);
+  }
+}
+
 void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
   uint32_t new_bitrate = current_bitrate_bps_;
   // We trust the REMB and/or delay-based estimate during the first 2 seconds if
@@ -357,7 +374,7 @@
       new_bitrate *= 0.8;
       // Reset accumulators since we've already acted on missing feedback and
       // shouldn't to act again on these old lost packets.
-      lost_packets_since_last_loss_update_Q8_ = 0;
+      lost_packets_since_last_loss_update_ = 0;
       expected_packets_since_last_loss_update_ = 0;
       last_timeout_ms_ = now_ms;
     }
diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.h b/modules/bitrate_controller/send_side_bandwidth_estimation.h
index 59d1c32..d09184c0 100644
--- a/modules/bitrate_controller/send_side_bandwidth_estimation.h
+++ b/modules/bitrate_controller/send_side_bandwidth_estimation.h
@@ -42,10 +42,18 @@
 
   // Call when we receive a RTCP message with a ReceiveBlock.
   void UpdateReceiverBlock(uint8_t fraction_loss,
-                           int64_t rtt,
+                           int64_t rtt_ms,
                            int number_of_packets,
                            int64_t now_ms);
 
+  // Call when we receive a RTCP message with a ReceiveBlock.
+  void UpdatePacketsLost(int packets_lost,
+                         int number_of_packets,
+                         int64_t now_ms);
+
+  // Call when we receive a RTCP message with a ReceiveBlock.
+  void UpdateRtt(int64_t rtt, int64_t now_ms);
+
   void SetBitrates(int send_bitrate,
                    int min_bitrate,
                    int max_bitrate);
@@ -58,7 +66,7 @@
 
   bool IsInStartPhase(int64_t now_ms) const;
 
-  void UpdateUmaStats(int64_t now_ms, int64_t rtt, int lost_packets);
+  void UpdateUmaStatsPacketsLost(int64_t now_ms, int packets_lost);
 
   // Updates history of min bitrates.
   // After this method returns min_bitrate_history_.front().second contains the
@@ -72,7 +80,7 @@
   std::deque<std::pair<int64_t, uint32_t> > min_bitrate_history_;
 
   // incoming filters
-  int lost_packets_since_last_loss_update_Q8_;
+  int lost_packets_since_last_loss_update_;
   int expected_packets_since_last_loss_update_;
 
   uint32_t current_bitrate_bps_;
@@ -95,6 +103,7 @@
   int initially_lost_packets_;
   int bitrate_at_2_seconds_kbps_;
   UmaState uma_update_state_;
+  UmaState uma_rtt_state_;
   std::vector<bool> rampup_uma_stats_updated_;
   RtcEventLog* event_log_;
   int64_t last_rtc_event_log_ms_;
diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn
index 23f5333..eee190d 100644
--- a/modules/congestion_controller/BUILD.gn
+++ b/modules/congestion_controller/BUILD.gn
@@ -22,8 +22,8 @@
   sources = [
     "include/receive_side_congestion_controller.h",
     "include/send_side_congestion_controller.h",
-    "probe_controller.cc",
-    "probe_controller.h",
+    "pacer_controller.cc",
+    "pacer_controller.h",
     "receive_side_congestion_controller.cc",
     "send_side_congestion_controller.cc",
   ]
@@ -37,13 +37,14 @@
   }
 
   deps = [
-    ":delay_based_bwe",
-    ":estimators",
+    ":goog_cc",
     ":transport_feedback",
     "..:module_api",
     "../..:webrtc_common",
     "../../rtc_base:checks",
     "../../rtc_base:rate_limiter",
+    "../../rtc_base:rtc_task_queue_api",
+    "../../rtc_base:sequenced_task_checker",
     "../../system_wrappers",
     "../../system_wrappers:field_trial_api",
     "../../system_wrappers:metrics_api",
@@ -52,6 +53,7 @@
     "../pacing",
     "../remote_bitrate_estimator",
     "../rtp_rtcp:rtp_rtcp_format",
+    "./network_control",
   ]
 
   if (!build_with_mozilla) {
@@ -69,14 +71,57 @@
   ]
 
   deps = [
-    "../../modules:module_api",
+    "..:module_api",
     "../../rtc_base:checks",
     "../../rtc_base:rtc_base_approved",
-    "../../system_wrappers:system_wrappers",
+    "../../system_wrappers",
     "../rtp_rtcp:rtp_rtcp_format",
   ]
 }
 
+rtc_static_library("goog_cc") {
+  configs += [ ":bwe_test_logging" ]
+  sources = [
+    "alr_detector.cc",
+    "alr_detector.h",
+    "goog_cc_network_control.cc",
+    "goog_cc_network_control.h",
+    "include/goog_cc_factory.h",
+    "probe_controller.cc",
+    "probe_controller.h",
+  ]
+
+  # TODO(jschuh): Bug 1348: fix this warning.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  if (!build_with_chromium && is_clang) {
+    # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+    suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+  }
+
+  deps = [
+    ":delay_based_bwe",
+    ":estimators",
+    "..:module_api",
+    "../..:webrtc_common",
+    "../../:typedefs",
+    "../../api:optional",
+    "../../logging:rtc_event_log_api",
+    "../../logging:rtc_event_pacing",
+    "../../rtc_base:checks",
+    "../../rtc_base:rtc_base_approved",
+    "../../rtc_base/experiments:alr_experiment",
+    "../../system_wrappers",
+    "../../system_wrappers:field_trial_api",
+    "../../system_wrappers:metrics_api",
+    "../bitrate_controller",
+    "../pacing",
+    "../remote_bitrate_estimator",
+    "../rtp_rtcp:rtp_rtcp_format",
+    "./network_control",
+  ]
+}
+
 rtc_source_set("estimators") {
   configs += [ ":bwe_test_logging" ]
   sources = [
@@ -110,7 +155,7 @@
     "../../rtc_base:rtc_numerics",
     "../../system_wrappers:field_trial_api",
     "../../system_wrappers:metrics_api",
-    "../remote_bitrate_estimator:remote_bitrate_estimator",
+    "../remote_bitrate_estimator",
     "../rtp_rtcp:rtp_rtcp_format",
   ]
 }
@@ -145,25 +190,16 @@
     testonly = true
 
     sources = [
-      "acknowledged_bitrate_estimator_unittest.cc",
       "congestion_controller_unittests_helper.cc",
       "congestion_controller_unittests_helper.h",
-      "delay_based_bwe_unittest.cc",
-      "delay_based_bwe_unittest_helper.cc",
-      "delay_based_bwe_unittest_helper.h",
-      "median_slope_estimator_unittest.cc",
-      "probe_bitrate_estimator_unittest.cc",
-      "probe_controller_unittest.cc",
       "receive_side_congestion_controller_unittest.cc",
       "send_side_congestion_controller_unittest.cc",
       "send_time_history_unittest.cc",
       "transport_feedback_adapter_unittest.cc",
-      "trendline_estimator_unittest.cc",
     ]
     deps = [
       ":congestion_controller",
-      ":delay_based_bwe",
-      ":estimators",
+      ":goog_cc_unittests",
       ":mock_congestion_controller",
       ":transport_feedback",
       "../../logging:mocks",
@@ -174,12 +210,51 @@
       "../../system_wrappers",
       "../../test:field_trial",
       "../../test:test_support",
-      "../bitrate_controller:bitrate_controller",
       "../bitrate_controller:mocks",
       "../pacing:mock_paced_sender",
       "../pacing:pacing",
       "../remote_bitrate_estimator:remote_bitrate_estimator",
       "../rtp_rtcp:rtp_rtcp_format",
+      "./network_control",
+      "//testing/gmock",
+    ]
+    if (!build_with_chromium && is_clang) {
+      # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
+      suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
+    }
+  }
+
+  rtc_source_set("goog_cc_unittests") {
+    testonly = true
+
+    sources = [
+      "acknowledged_bitrate_estimator_unittest.cc",
+      "alr_detector_unittest.cc",
+      "delay_based_bwe_unittest.cc",
+      "delay_based_bwe_unittest_helper.cc",
+      "delay_based_bwe_unittest_helper.h",
+      "median_slope_estimator_unittest.cc",
+      "probe_bitrate_estimator_unittest.cc",
+      "probe_controller_unittest.cc",
+      "trendline_estimator_unittest.cc",
+    ]
+    deps = [
+      ":delay_based_bwe",
+      ":estimators",
+      ":goog_cc",
+      "../../rtc_base:checks",
+      "../../rtc_base:rtc_base_approved",
+      "../../rtc_base:rtc_base_tests_utils",
+      "../../rtc_base/experiments:alr_experiment",
+      "../../system_wrappers",
+      "../../test:field_trial",
+      "../../test:test_support",
+      "../pacing",
+      "../remote_bitrate_estimator",
+      "../rtp_rtcp:rtp_rtcp_format",
+      "./network_control",
+      "./network_control:network_control_unittests",
+      "//testing/gmock",
     ]
     if (!build_with_chromium && is_clang) {
       # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
diff --git a/modules/congestion_controller/acknowledged_bitrate_estimator.cc b/modules/congestion_controller/acknowledged_bitrate_estimator.cc
index 1e75ee6..ec1a6f2 100644
--- a/modules/congestion_controller/acknowledged_bitrate_estimator.cc
+++ b/modules/congestion_controller/acknowledged_bitrate_estimator.cc
@@ -27,6 +27,8 @@
 AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator()
     : AcknowledgedBitrateEstimator(rtc::MakeUnique<BitrateEstimator>()) {}
 
+AcknowledgedBitrateEstimator::~AcknowledgedBitrateEstimator() {}
+
 AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator(
     std::unique_ptr<BitrateEstimator> bitrate_estimator)
     : bitrate_estimator_(std::move(bitrate_estimator)) {}
diff --git a/modules/congestion_controller/acknowledged_bitrate_estimator.h b/modules/congestion_controller/acknowledged_bitrate_estimator.h
index 72c1023..c009e86 100644
--- a/modules/congestion_controller/acknowledged_bitrate_estimator.h
+++ b/modules/congestion_controller/acknowledged_bitrate_estimator.h
@@ -27,6 +27,7 @@
       std::unique_ptr<BitrateEstimator> bitrate_estimator);
 
   AcknowledgedBitrateEstimator();
+  ~AcknowledgedBitrateEstimator();
 
   void IncomingPacketFeedbackVector(
       const std::vector<PacketFeedback>& packet_feedback_vector);
diff --git a/modules/pacing/alr_detector.cc b/modules/congestion_controller/alr_detector.cc
similarity index 87%
rename from modules/pacing/alr_detector.cc
rename to modules/congestion_controller/alr_detector.cc
index 9ba6e32..249aa18 100644
--- a/modules/pacing/alr_detector.cc
+++ b/modules/congestion_controller/alr_detector.cc
@@ -8,11 +8,11 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/pacing/alr_detector.h"
+#include "modules/congestion_controller/alr_detector.h"
 
 #include <algorithm>
-#include <string>
 #include <cstdio>
+#include <string>
 
 #include "logging/rtc_event_log/events/rtc_event_alr_state.h"
 #include "logging/rtc_event_log/rtc_event_log.h"
@@ -52,7 +52,16 @@
 
 AlrDetector::~AlrDetector() {}
 
-void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t delta_time_ms) {
+void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) {
+  if (!last_send_time_ms_.has_value()) {
+    last_send_time_ms_ = send_time_ms;
+    // Since the duration for sending the bytes is unknwon, return without
+    // updating alr state.
+    return;
+  }
+  int64_t delta_time_ms = send_time_ms - *last_send_time_ms_;
+  last_send_time_ms_ = send_time_ms;
+
   alr_budget_.UseBudget(bytes_sent);
   alr_budget_.IncreaseBudget(delta_time_ms);
   bool state_changed = false;
diff --git a/modules/pacing/alr_detector.h b/modules/congestion_controller/alr_detector.h
similarity index 89%
rename from modules/pacing/alr_detector.h
rename to modules/congestion_controller/alr_detector.h
index f73bc17..5cb9043 100644
--- a/modules/pacing/alr_detector.h
+++ b/modules/congestion_controller/alr_detector.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_PACING_ALR_DETECTOR_H_
-#define MODULES_PACING_ALR_DETECTOR_H_
+#ifndef MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
+#define MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
 
 #include "api/optional.h"
 #include "common_types.h"  // NOLINT(build/include)
@@ -35,7 +35,7 @@
   explicit AlrDetector(RtcEventLog* event_log);
   ~AlrDetector();
 
-  void OnBytesSent(size_t bytes_sent, int64_t delta_time_ms);
+  void OnBytesSent(size_t bytes_sent, int64_t send_time_ms);
 
   // Set current estimated bandwidth.
   void SetEstimatedBitrate(int bitrate_bps);
@@ -61,6 +61,8 @@
   int alr_start_budget_level_percent_;
   int alr_stop_budget_level_percent_;
 
+  rtc::Optional<int64_t> last_send_time_ms_;
+
   IntervalBudget alr_budget_;
   rtc::Optional<int64_t> alr_started_time_ms_;
 
@@ -69,4 +71,4 @@
 
 }  // namespace webrtc
 
-#endif  // MODULES_PACING_ALR_DETECTOR_H_
+#endif  // MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
diff --git a/modules/pacing/alr_detector_unittest.cc b/modules/congestion_controller/alr_detector_unittest.cc
similarity index 84%
rename from modules/pacing/alr_detector_unittest.cc
rename to modules/congestion_controller/alr_detector_unittest.cc
index 356e14e..a7f5541 100644
--- a/modules/pacing/alr_detector_unittest.cc
+++ b/modules/congestion_controller/alr_detector_unittest.cc
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/pacing/alr_detector.h"
+#include "modules/congestion_controller/alr_detector.h"
 
 #include "rtc_base/experiments/alr_experiment.h"
 #include "test/field_trial.h"
@@ -25,8 +25,9 @@
 namespace {
 class SimulateOutgoingTrafficIn {
  public:
-  explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector)
-      : alr_detector_(alr_detector) {
+  explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector,
+                                     int64_t* timestamp_ms)
+      : alr_detector_(alr_detector), timestamp_ms_(timestamp_ms) {
     RTC_CHECK(alr_detector_);
   }
 
@@ -48,18 +49,21 @@
       return;
     const int kTimeStepMs = 10;
     for (int t = 0; t < *interval_ms_; t += kTimeStepMs) {
+      *timestamp_ms_ += kTimeStepMs;
       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
                                      kTimeStepMs / (8 * 100 * 1000),
-                                 kTimeStepMs);
+                                 *timestamp_ms_);
     }
     int remainder_ms = *interval_ms_ % kTimeStepMs;
     if (remainder_ms > 0) {
+      *timestamp_ms_ += kTimeStepMs;
       alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
                                      remainder_ms / (8 * 100 * 1000),
-                                 kTimeStepMs);
+                                 *timestamp_ms_);
     }
   }
   AlrDetector* const alr_detector_;
+  int64_t* timestamp_ms_;
   rtc::Optional<int> interval_ms_;
   rtc::Optional<int> usage_percentage_;
 };
@@ -73,6 +77,7 @@
 
  protected:
   AlrDetector alr_detector_;
+  int64_t timestamp_ms_ = 1000;
 };
 
 TEST_F(AlrDetectorTest, AlrDetection) {
@@ -80,19 +85,19 @@
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // Stay in non-ALR state when usage is close to 100%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(1000)
       .AtPercentOfEstimatedBitrate(90);
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // Verify that we ALR starts when bitrate drops below 20%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(1500)
       .AtPercentOfEstimatedBitrate(20);
   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // Verify that ALR ends when usage is above 65%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(4000)
       .AtPercentOfEstimatedBitrate(100);
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
@@ -103,19 +108,19 @@
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // Verify that we ALR starts when bitrate drops below 20%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(1000)
       .AtPercentOfEstimatedBitrate(20);
   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // Verify that we stay in ALR region even after a short bitrate spike.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(100)
       .AtPercentOfEstimatedBitrate(150);
   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // ALR ends when usage is above 65%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(3000)
       .AtPercentOfEstimatedBitrate(100);
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
@@ -126,7 +131,7 @@
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
 
   // ALR starts when bitrate drops below 20%.
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(1000)
       .AtPercentOfEstimatedBitrate(20);
   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
@@ -137,7 +142,7 @@
   // to the BWE drop by initiating a new probe.
   alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5);
   EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
-  SimulateOutgoingTrafficIn(&alr_detector_)
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
       .ForTimeMs(1000)
       .AtPercentOfEstimatedBitrate(50);
   EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
diff --git a/modules/congestion_controller/delay_based_bwe.cc b/modules/congestion_controller/delay_based_bwe.cc
index 9f0e01d..b053ef4 100644
--- a/modules/congestion_controller/delay_based_bwe.cc
+++ b/modules/congestion_controller/delay_based_bwe.cc
@@ -85,9 +85,8 @@
 
 DelayBasedBwe::Result::~Result() {}
 
-DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log, const Clock* clock)
+DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log)
     : event_log_(event_log),
-      clock_(clock),
       inter_arrival_(),
       delay_detector_(),
       last_seen_packet_ms_(-1),
@@ -114,7 +113,8 @@
 
 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
     const std::vector<PacketFeedback>& packet_feedback_vector,
-    rtc::Optional<uint32_t> acked_bitrate_bps) {
+    rtc::Optional<uint32_t> acked_bitrate_bps,
+    int64_t at_time_ms) {
   RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
                             packet_feedback_vector.end(),
                             PacketFeedbackComparator()));
@@ -141,7 +141,7 @@
     if (packet_feedback.send_time_ms < 0)
       continue;
     delayed_feedback = false;
-    IncomingPacketFeedback(packet_feedback);
+    IncomingPacketFeedback(packet_feedback, at_time_ms);
     if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
         delay_detector_->State() == BandwidthUsage::kBwNormal) {
       recovered_from_overuse = true;
@@ -157,7 +157,8 @@
     }
   } else {
     consecutive_delayed_feedbacks_ = 0;
-    return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse);
+    return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse,
+                               at_time_ms);
   }
   return Result();
 }
@@ -180,8 +181,9 @@
 }
 
 void DelayBasedBwe::IncomingPacketFeedback(
-    const PacketFeedback& packet_feedback) {
-  int64_t now_ms = clock_->TimeInMilliseconds();
+    const PacketFeedback& packet_feedback,
+    int64_t at_time_ms) {
+  int64_t now_ms = at_time_ms;
   // Reset if the stream has timed out.
   if (last_seen_packet_ms_ == -1 ||
       now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
@@ -223,9 +225,10 @@
 
 DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
     rtc::Optional<uint32_t> acked_bitrate_bps,
-    bool recovered_from_overuse) {
+    bool recovered_from_overuse,
+    int64_t at_time_ms) {
   Result result;
-  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t now_ms = at_time_ms;
 
   rtc::Optional<int> probe_bitrate_bps =
       probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
@@ -289,7 +292,7 @@
   return rate_control_.ValidEstimate();
 }
 
-void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
+void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms) {
   rate_control_.SetRtt(avg_rtt_ms);
 }
 
diff --git a/modules/congestion_controller/delay_based_bwe.h b/modules/congestion_controller/delay_based_bwe.h
index dbe759e..654fe54 100644
--- a/modules/congestion_controller/delay_based_bwe.h
+++ b/modules/congestion_controller/delay_based_bwe.h
@@ -42,13 +42,14 @@
     bool recovered_from_overuse;
   };
 
-  DelayBasedBwe(RtcEventLog* event_log, const Clock* clock);
+  explicit DelayBasedBwe(RtcEventLog* event_log);
   virtual ~DelayBasedBwe();
 
   Result IncomingPacketFeedbackVector(
       const std::vector<PacketFeedback>& packet_feedback_vector,
-      rtc::Optional<uint32_t> acked_bitrate_bps);
-  void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms);
+      rtc::Optional<uint32_t> acked_bitrate_bps,
+      int64_t at_time_ms);
+  void OnRttUpdate(int64_t avg_rtt_ms);
   bool LatestEstimate(std::vector<uint32_t>* ssrcs,
                       uint32_t* bitrate_bps) const;
   void SetStartBitrate(int start_bitrate_bps);
@@ -56,10 +57,12 @@
   int64_t GetExpectedBwePeriodMs() const;
 
  private:
-  void IncomingPacketFeedback(const PacketFeedback& packet_feedback);
+  void IncomingPacketFeedback(const PacketFeedback& packet_feedback,
+                              int64_t at_time_ms);
   Result OnLongFeedbackDelay(int64_t arrival_time_ms);
   Result MaybeUpdateEstimate(rtc::Optional<uint32_t> acked_bitrate_bps,
-                             bool request_probe);
+                             bool request_probe,
+                             int64_t at_time_ms);
   // Updates the current remote rate estimate and returns true if a valid
   // estimate exists.
   bool UpdateEstimate(int64_t now_ms,
@@ -68,7 +71,6 @@
 
   rtc::RaceChecker network_race_;
   RtcEventLog* const event_log_;
-  const Clock* const clock_;
   std::unique_ptr<InterArrival> inter_arrival_;
   std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_;
   int64_t last_seen_packet_ms_;
diff --git a/modules/congestion_controller/delay_based_bwe_unittest.cc b/modules/congestion_controller/delay_based_bwe_unittest.cc
index 250cb03..d5fb8bf 100644
--- a/modules/congestion_controller/delay_based_bwe_unittest.cc
+++ b/modules/congestion_controller/delay_based_bwe_unittest.cc
@@ -24,12 +24,13 @@
 const PacedPacketInfo kPacingInfo0(0, kNumProbesCluster0, 2000);
 const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000);
 constexpr float kTargetUtilizationFraction = 0.95f;
+constexpr int64_t kDummyTimestamp = 1000;
 }  // namespace
 
 TEST_F(DelayBasedBweTest, NoCrashEmptyFeedback) {
   std::vector<PacketFeedback> packet_feedback_vector;
-  bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
-                                                   rtc::nullopt);
+  bitrate_estimator_->IncomingPacketFeedbackVector(
+      packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
 }
 
 TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
@@ -40,8 +41,8 @@
   packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
                                                   PacketFeedback::kNoSendTime,
                                                   1, 1500, PacedPacketInfo()));
-  bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
-                                                   rtc::nullopt);
+  bitrate_estimator_->IncomingPacketFeedbackVector(
+      packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
 }
 
 TEST_F(DelayBasedBweTest, ProbeDetection) {
diff --git a/modules/congestion_controller/delay_based_bwe_unittest_helper.cc b/modules/congestion_controller/delay_based_bwe_unittest_helper.cc
index b441e99..0b005b5 100644
--- a/modules/congestion_controller/delay_based_bwe_unittest_helper.cc
+++ b/modules/congestion_controller/delay_based_bwe_unittest_helper.cc
@@ -152,7 +152,7 @@
     : clock_(100000000),
       acknowledged_bitrate_estimator_(
           rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
-      bitrate_estimator_(new DelayBasedBwe(nullptr, &clock_)),
+      bitrate_estimator_(new DelayBasedBwe(nullptr)),
       stream_generator_(new test::StreamGenerator(1e6,  // Capacity.
                                                   clock_.TimeInMicroseconds())),
       arrival_time_offset_ms_(0),
@@ -187,7 +187,8 @@
   acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
   DelayBasedBwe::Result result =
       bitrate_estimator_->IncomingPacketFeedbackVector(
-          packets, acknowledged_bitrate_estimator_->bitrate_bps());
+          packets, acknowledged_bitrate_estimator_->bitrate_bps(),
+          clock_.TimeInMilliseconds());
   const uint32_t kDummySsrc = 0;
   if (result.updated) {
     bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
@@ -222,7 +223,8 @@
   acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
   DelayBasedBwe::Result result =
       bitrate_estimator_->IncomingPacketFeedbackVector(
-          packets, acknowledged_bitrate_estimator_->bitrate_bps());
+          packets, acknowledged_bitrate_estimator_->bitrate_bps(),
+          clock_.TimeInMilliseconds());
   const uint32_t kDummySsrc = 0;
   if (result.updated) {
     bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
diff --git a/modules/congestion_controller/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc_network_control.cc
new file mode 100644
index 0000000..b6e473d
--- /dev/null
+++ b/modules/congestion_controller/goog_cc_network_control.cc
@@ -0,0 +1,425 @@
+/*
+ *  Copyright (c) 2018 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 "modules/congestion_controller/goog_cc_network_control.h"
+
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
+#include "modules/congestion_controller/alr_detector.h"
+#include "modules/congestion_controller/include/goog_cc_factory.h"
+#include "modules/congestion_controller/probe_controller.h"
+#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/format_macros.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/ptr_util.h"
+#include "rtc_base/timeutils.h"
+#include "system_wrappers/include/field_trial.h"
+
+namespace webrtc {
+namespace {
+
+const char kCwndExperiment[] = "WebRTC-CwndExperiment";
+const int64_t kDefaultAcceptedQueueMs = 250;
+
+// Pacing-rate relative to our target send rate.
+// Multiplicative factor that is applied to the target bitrate to calculate
+// the number of bytes that can be transmitted per interval.
+// Increasing this factor will result in lower delays in cases of bitrate
+// overshoots from the encoder.
+const float kDefaultPaceMultiplier = 2.5f;
+
+bool CwndExperimentEnabled() {
+  std::string experiment_string =
+      webrtc::field_trial::FindFullName(kCwndExperiment);
+  // The experiment is enabled iff the field trial string begins with "Enabled".
+  return experiment_string.find("Enabled") == 0;
+}
+
+bool ReadCwndExperimentParameter(int64_t* accepted_queue_ms) {
+  RTC_DCHECK(accepted_queue_ms);
+  std::string experiment_string =
+      webrtc::field_trial::FindFullName(kCwndExperiment);
+  int parsed_values =
+      sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
+  if (parsed_values == 1) {
+    RTC_CHECK_GE(*accepted_queue_ms, 0)
+        << "Accepted must be greater than or equal to 0.";
+    return true;
+  }
+  return false;
+}
+
+// Makes sure that the bitrate and the min, max values are in valid range.
+static void ClampBitrates(int64_t* bitrate_bps,
+                          int64_t* min_bitrate_bps,
+                          int64_t* max_bitrate_bps) {
+  // TODO(holmer): We should make sure the default bitrates are set to 10 kbps,
+  // and that we don't try to set the min bitrate to 0 from any applications.
+  // The congestion controller should allow a min bitrate of 0.
+  if (*min_bitrate_bps < congestion_controller::GetMinBitrateBps())
+    *min_bitrate_bps = congestion_controller::GetMinBitrateBps();
+  if (*max_bitrate_bps > 0)
+    *max_bitrate_bps = std::max(*min_bitrate_bps, *max_bitrate_bps);
+  if (*bitrate_bps > 0)
+    *bitrate_bps = std::max(*min_bitrate_bps, *bitrate_bps);
+}
+
+std::vector<PacketFeedback> ReceivedPacketsFeedbackAsRtp(
+    const TransportPacketsFeedback report) {
+  std::vector<PacketFeedback> packet_feedback_vector;
+  for (auto& fb : report.PacketsWithFeedback()) {
+    if (fb.receive_time.IsFinite()) {
+      PacketFeedback pf(fb.receive_time.ms(), 0);
+      pf.creation_time_ms = report.feedback_time.ms();
+      if (fb.sent_packet.has_value()) {
+        pf.payload_size = fb.sent_packet->size.bytes();
+        pf.pacing_info = fb.sent_packet->pacing_info;
+        pf.send_time_ms = fb.sent_packet->send_time.ms();
+      } else {
+        pf.send_time_ms = PacketFeedback::kNoSendTime;
+      }
+      packet_feedback_vector.push_back(pf);
+    }
+  }
+  return packet_feedback_vector;
+}
+
+}  // namespace
+
+GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
+    RtcEventLog* event_log)
+    : event_log_(event_log) {}
+
+NetworkControllerInterface::uptr GoogCcNetworkControllerFactory::Create(
+    NetworkControllerObserver* observer) {
+  return rtc::MakeUnique<GoogCcNetworkController>(event_log_, observer);
+}
+
+TimeDelta GoogCcNetworkControllerFactory::GetProcessInterval() const {
+  const int64_t kUpdateIntervalMs = 25;
+  return TimeDelta::ms(kUpdateIntervalMs);
+}
+
+GoogCcNetworkController::GoogCcNetworkController(
+    RtcEventLog* event_log,
+    NetworkControllerObserver* observer)
+    : event_log_(event_log),
+      observer_(observer),
+      probe_controller_(new ProbeController(observer_)),
+      bandwidth_estimation_(
+          rtc::MakeUnique<SendSideBandwidthEstimation>(event_log_)),
+      alr_detector_(rtc::MakeUnique<AlrDetector>()),
+      delay_based_bwe_(new DelayBasedBwe(event_log_)),
+      acknowledged_bitrate_estimator_(
+          rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
+      pacing_factor_(kDefaultPaceMultiplier),
+      min_pacing_rate_(DataRate::Zero()),
+      max_padding_rate_(DataRate::Zero()),
+      in_cwnd_experiment_(CwndExperimentEnabled()),
+      accepted_queue_ms_(kDefaultAcceptedQueueMs) {
+  delay_based_bwe_->SetMinBitrate(congestion_controller::GetMinBitrateBps());
+  if (in_cwnd_experiment_ &&
+      !ReadCwndExperimentParameter(&accepted_queue_ms_)) {
+    RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
+                           "from field trial string. Experiment disabled.";
+    in_cwnd_experiment_ = false;
+  }
+}
+
+GoogCcNetworkController::~GoogCcNetworkController() {}
+
+void GoogCcNetworkController::OnNetworkAvailability(NetworkAvailability msg) {
+  probe_controller_->OnNetworkAvailability(msg);
+}
+
+void GoogCcNetworkController::OnNetworkRouteChange(NetworkRouteChange msg) {
+  int64_t min_bitrate_bps = msg.constraints.min_data_rate.bps();
+  int64_t max_bitrate_bps = -1;
+  int64_t start_bitrate_bps = -1;
+
+  if (msg.constraints.max_data_rate.IsFinite())
+    max_bitrate_bps = msg.constraints.max_data_rate.bps();
+  if (msg.constraints.starting_rate.IsFinite())
+    start_bitrate_bps = msg.constraints.starting_rate.bps();
+
+  ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
+
+  bandwidth_estimation_ =
+      rtc::MakeUnique<SendSideBandwidthEstimation>(event_log_);
+  bandwidth_estimation_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
+                                     max_bitrate_bps);
+  delay_based_bwe_.reset(new DelayBasedBwe(event_log_));
+  acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
+  delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
+  delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
+
+  probe_controller_->Reset(msg.at_time.ms());
+  probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
+                                 max_bitrate_bps, msg.at_time.ms());
+
+  MaybeTriggerOnNetworkChanged(msg.at_time);
+}
+
+void GoogCcNetworkController::OnProcessInterval(ProcessInterval msg) {
+  bandwidth_estimation_->UpdateEstimate(msg.at_time.ms());
+  rtc::Optional<int64_t> start_time_ms =
+      alr_detector_->GetApplicationLimitedRegionStartTime();
+  probe_controller_->SetAlrStartTimeMs(start_time_ms);
+  probe_controller_->Process(msg.at_time.ms());
+  MaybeTriggerOnNetworkChanged(msg.at_time);
+}
+
+void GoogCcNetworkController::OnRemoteBitrateReport(RemoteBitrateReport msg) {
+  bandwidth_estimation_->UpdateReceiverEstimate(msg.receive_time.ms(),
+                                                msg.bandwidth.bps());
+  BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", msg.receive_time.ms(),
+                        msg.bandwidth.bps() / 1000);
+}
+
+void GoogCcNetworkController::OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) {
+  if (msg.smoothed) {
+    delay_based_bwe_->OnRttUpdate(msg.round_trip_time.ms());
+  } else {
+    bandwidth_estimation_->UpdateRtt(msg.round_trip_time.ms(),
+                                     msg.receive_time.ms());
+  }
+}
+
+void GoogCcNetworkController::OnSentPacket(SentPacket sent_packet) {
+  alr_detector_->OnBytesSent(sent_packet.size.bytes(),
+                             sent_packet.send_time.ms());
+}
+
+void GoogCcNetworkController::OnStreamsConfig(StreamsConfig msg) {
+  probe_controller_->EnablePeriodicAlrProbing(msg.requests_alr_probing);
+
+  bool pacing_changed = false;
+  if (msg.pacing_factor && *msg.pacing_factor != pacing_factor_) {
+    pacing_factor_ = *msg.pacing_factor;
+    pacing_changed = true;
+  }
+  if (msg.min_pacing_rate && *msg.min_pacing_rate != min_pacing_rate_) {
+    min_pacing_rate_ = *msg.min_pacing_rate;
+    pacing_changed = true;
+  }
+  if (msg.max_padding_rate && *msg.max_padding_rate != max_padding_rate_) {
+    max_padding_rate_ = *msg.max_padding_rate;
+    pacing_changed = true;
+  }
+  if (pacing_changed)
+    UpdatePacingRates(msg.at_time);
+}
+
+void GoogCcNetworkController::OnTargetRateConstraints(
+    TargetRateConstraints constraints) {
+  int64_t min_bitrate_bps = constraints.min_data_rate.bps();
+  int64_t max_bitrate_bps = -1;
+  int64_t start_bitrate_bps = -1;
+
+  if (constraints.max_data_rate.IsFinite())
+    max_bitrate_bps = constraints.max_data_rate.bps();
+  if (constraints.starting_rate.IsFinite())
+    start_bitrate_bps = constraints.starting_rate.bps();
+
+  ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
+
+  probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
+                                 max_bitrate_bps, constraints.at_time.ms());
+
+  bandwidth_estimation_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
+                                     max_bitrate_bps);
+  if (start_bitrate_bps > 0)
+    delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
+  delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
+
+  MaybeTriggerOnNetworkChanged(constraints.at_time);
+}
+
+void GoogCcNetworkController::OnTransportLossReport(TransportLossReport msg) {
+  int64_t total_packets_delta =
+      msg.packets_received_delta + msg.packets_lost_delta;
+  bandwidth_estimation_->UpdatePacketsLost(
+      msg.packets_lost_delta, total_packets_delta, msg.receive_time.ms());
+}
+
+void GoogCcNetworkController::OnTransportPacketsFeedback(
+    TransportPacketsFeedback report) {
+  int64_t feedback_rtt = -1;
+  for (const auto& packet_feedback : report.PacketsWithFeedback()) {
+    if (packet_feedback.sent_packet.has_value() &&
+        packet_feedback.receive_time.IsFinite()) {
+      int64_t rtt = report.feedback_time.ms() -
+                    packet_feedback.sent_packet->send_time.ms();
+      // max() is used to account for feedback being delayed by the
+      // receiver.
+      feedback_rtt = std::max(rtt, feedback_rtt);
+    }
+  }
+  if (feedback_rtt > -1) {
+    feedback_rtts_.push_back(feedback_rtt);
+    const size_t kFeedbackRttWindow = 32;
+    if (feedback_rtts_.size() > kFeedbackRttWindow)
+      feedback_rtts_.pop_front();
+    min_feedback_rtt_ms_.emplace(
+        *std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
+  }
+
+  std::vector<PacketFeedback> received_feedback_vector =
+      ReceivedPacketsFeedbackAsRtp(report);
+
+  rtc::Optional<int64_t> alr_start_time =
+      alr_detector_->GetApplicationLimitedRegionStartTime();
+
+  if (previously_in_alr && !alr_start_time.has_value()) {
+    int64_t now_ms = report.feedback_time.ms();
+    acknowledged_bitrate_estimator_->SetAlrEndedTimeMs(now_ms);
+    probe_controller_->SetAlrEndedTimeMs(now_ms);
+  }
+  previously_in_alr = alr_start_time.has_value();
+  acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
+      received_feedback_vector);
+  DelayBasedBwe::Result result;
+  result = delay_based_bwe_->IncomingPacketFeedbackVector(
+      received_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
+      report.feedback_time.ms());
+  if (result.updated) {
+    if (result.probe) {
+      bandwidth_estimation_->SetSendBitrate(result.target_bitrate_bps);
+    }
+    // Since SetSendBitrate now resets the delay-based estimate, we have to call
+    // UpdateDelayBasedEstimate after SetSendBitrate.
+    bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time.ms(),
+                                                    result.target_bitrate_bps);
+    // Update the estimate in the ProbeController, in case we want to probe.
+    MaybeTriggerOnNetworkChanged(report.feedback_time);
+  }
+  if (result.recovered_from_overuse) {
+    probe_controller_->SetAlrStartTimeMs(alr_start_time);
+    probe_controller_->RequestProbe(report.feedback_time.ms());
+  }
+  MaybeUpdateCongestionWindow();
+}
+
+void GoogCcNetworkController::MaybeUpdateCongestionWindow() {
+  if (!in_cwnd_experiment_)
+    return;
+  // No valid RTT. Could be because send-side BWE isn't used, in which case
+  // we don't try to limit the outstanding packets.
+  if (!min_feedback_rtt_ms_)
+    return;
+  if (!last_estimate_.has_value())
+    return;
+  const DataSize kMinCwnd = DataSize::bytes(2 * 1500);
+  TimeDelta time_window =
+      TimeDelta::ms(*min_feedback_rtt_ms_ + accepted_queue_ms_);
+  DataSize data_window = last_estimate_->bandwidth * time_window;
+  CongestionWindow msg;
+  msg.enabled = true;
+  msg.data_window = std::max(kMinCwnd, data_window);
+  observer_->OnCongestionWindow(msg);
+  RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_rtt_ms_
+                   << " Bitrate: " << last_estimate_->bandwidth.bps();
+}
+
+void GoogCcNetworkController::MaybeTriggerOnNetworkChanged(Timestamp at_time) {
+  int32_t estimated_bitrate_bps;
+  uint8_t fraction_loss;
+  int64_t rtt_ms;
+
+  bool estimate_changed = GetNetworkParameters(
+      &estimated_bitrate_bps, &fraction_loss, &rtt_ms, at_time);
+  if (estimate_changed) {
+    TimeDelta bwe_period =
+        TimeDelta::ms(delay_based_bwe_->GetExpectedBwePeriodMs());
+
+    NetworkEstimate new_estimate;
+    new_estimate.at_time = at_time;
+    new_estimate.round_trip_time = TimeDelta::ms(rtt_ms);
+    new_estimate.bandwidth = DataRate::bps(estimated_bitrate_bps);
+    new_estimate.loss_rate_ratio = fraction_loss / 255.0f;
+    new_estimate.bwe_period = bwe_period;
+    new_estimate.changed = true;
+    last_estimate_ = new_estimate;
+    OnNetworkEstimate(new_estimate);
+  }
+}
+
+bool GoogCcNetworkController::GetNetworkParameters(
+    int32_t* estimated_bitrate_bps,
+    uint8_t* fraction_loss,
+    int64_t* rtt_ms,
+    Timestamp at_time) {
+  bandwidth_estimation_->CurrentEstimate(estimated_bitrate_bps, fraction_loss,
+                                         rtt_ms);
+  *estimated_bitrate_bps = std::max<int32_t>(
+      *estimated_bitrate_bps, bandwidth_estimation_->GetMinBitrate());
+
+  bool estimate_changed = false;
+  if ((*estimated_bitrate_bps != last_estimated_bitrate_bps_) ||
+      (*fraction_loss != last_estimated_fraction_loss_) ||
+      (*rtt_ms != last_estimated_rtt_ms_)) {
+    last_estimated_bitrate_bps_ = *estimated_bitrate_bps;
+    last_estimated_fraction_loss_ = *fraction_loss;
+    last_estimated_rtt_ms_ = *rtt_ms;
+    estimate_changed = true;
+  }
+
+  BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(),
+                        (*fraction_loss * 100) / 256);
+  BWE_TEST_LOGGING_PLOT(1, "rtt_ms", at_time.ms(), *rtt_ms);
+  BWE_TEST_LOGGING_PLOT(1, "Target_bitrate_kbps", at_time.ms(),
+                        *estimated_bitrate_bps / 1000);
+
+  return estimate_changed;
+}
+
+void GoogCcNetworkController::OnNetworkEstimate(NetworkEstimate estimate) {
+  if (!estimate.changed)
+    return;
+
+  UpdatePacingRates(estimate.at_time);
+  alr_detector_->SetEstimatedBitrate(estimate.bandwidth.bps());
+  probe_controller_->SetEstimatedBitrate(estimate.bandwidth.bps(),
+                                         estimate.at_time.ms());
+
+  TargetTransferRate target_rate;
+  target_rate.at_time = estimate.at_time;
+  // Set the target rate to the full estimated bandwidth since the estimation
+  // for legacy reasons includes target rate constraints.
+  target_rate.target_rate = estimate.bandwidth;
+  target_rate.network_estimate = estimate;
+  observer_->OnTargetTransferRate(target_rate);
+}
+
+void GoogCcNetworkController::UpdatePacingRates(Timestamp at_time) {
+  if (!last_estimate_)
+    return;
+  DataRate pacing_rate =
+      std::max(min_pacing_rate_, last_estimate_->bandwidth) * pacing_factor_;
+  DataRate padding_rate =
+      std::min(max_padding_rate_, last_estimate_->bandwidth);
+  PacerConfig msg;
+  msg.at_time = at_time;
+  msg.time_window = TimeDelta::s(1);
+  msg.data_window = pacing_rate * msg.time_window;
+  msg.pad_window = padding_rate * msg.time_window;
+  observer_->OnPacerConfig(msg);
+}
+
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc_network_control.h b/modules/congestion_controller/goog_cc_network_control.h
new file mode 100644
index 0000000..4360aac
--- /dev/null
+++ b/modules/congestion_controller/goog_cc_network_control.h
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_NETWORK_CONTROL_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_NETWORK_CONTROL_H_
+
+#include <stdint.h>
+#include <deque>
+#include <memory>
+#include <vector>
+
+#include "api/optional.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/bitrate_controller/send_side_bandwidth_estimation.h"
+#include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
+#include "modules/congestion_controller/alr_detector.h"
+#include "modules/congestion_controller/delay_based_bwe.h"
+#include "modules/congestion_controller/network_control/include/network_control.h"
+#include "modules/congestion_controller/probe_controller.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+
+class GoogCcNetworkController : public NetworkControllerInterface {
+ public:
+  GoogCcNetworkController(RtcEventLog* event_log,
+                          NetworkControllerObserver* observer);
+  ~GoogCcNetworkController() override;
+
+  // NetworkControllerInterface
+  void OnNetworkAvailability(NetworkAvailability msg) override;
+  void OnNetworkRouteChange(NetworkRouteChange msg) override;
+  void OnProcessInterval(ProcessInterval msg) override;
+  void OnRemoteBitrateReport(RemoteBitrateReport msg) override;
+  void OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) override;
+  void OnSentPacket(SentPacket msg) override;
+  void OnStreamsConfig(StreamsConfig msg) override;
+  void OnTargetRateConstraints(TargetRateConstraints msg) override;
+  void OnTransportLossReport(TransportLossReport msg) override;
+  void OnTransportPacketsFeedback(TransportPacketsFeedback msg) override;
+
+ private:
+  void MaybeUpdateCongestionWindow();
+  void MaybeTriggerOnNetworkChanged(Timestamp at_time);
+  bool GetNetworkParameters(int32_t* estimated_bitrate_bps,
+                            uint8_t* fraction_loss,
+                            int64_t* rtt_ms,
+                            Timestamp at_time);
+  void OnNetworkEstimate(NetworkEstimate msg);
+  void UpdatePacingRates(Timestamp at_time);
+
+  RtcEventLog* const event_log_;
+  NetworkControllerObserver* const observer_;
+
+  const std::unique_ptr<ProbeController> probe_controller_;
+
+  std::unique_ptr<SendSideBandwidthEstimation> bandwidth_estimation_;
+  std::unique_ptr<AlrDetector> alr_detector_;
+  std::unique_ptr<DelayBasedBwe> delay_based_bwe_;
+  std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
+
+  std::deque<int64_t> feedback_rtts_;
+  rtc::Optional<int64_t> min_feedback_rtt_ms_;
+
+  rtc::Optional<NetworkEstimate> last_estimate_;
+  rtc::Optional<TargetTransferRate> last_target_rate_;
+
+  int32_t last_estimated_bitrate_bps_ = 0;
+  uint8_t last_estimated_fraction_loss_ = 0;
+  int64_t last_estimated_rtt_ms_ = 0;
+
+  double pacing_factor_;
+  DataRate min_pacing_rate_;
+  DataRate max_padding_rate_;
+
+  bool in_cwnd_experiment_;
+  int64_t accepted_queue_ms_;
+  bool previously_in_alr = false;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GoogCcNetworkController);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_NETWORK_CONTROL_H_
diff --git a/modules/congestion_controller/include/goog_cc_factory.h b/modules/congestion_controller/include/goog_cc_factory.h
new file mode 100644
index 0000000..10dddd2
--- /dev/null
+++ b/modules/congestion_controller/include/goog_cc_factory.h
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_INCLUDE_GOOG_CC_FACTORY_H_
+#define MODULES_CONGESTION_CONTROLLER_INCLUDE_GOOG_CC_FACTORY_H_
+#include "modules/congestion_controller/network_control/include/network_control.h"
+
+namespace webrtc {
+class Clock;
+class RtcEventLog;
+
+class GoogCcNetworkControllerFactory
+    : public NetworkControllerFactoryInterface {
+ public:
+  explicit GoogCcNetworkControllerFactory(RtcEventLog*);
+  NetworkControllerInterface::uptr Create(
+      NetworkControllerObserver* observer) override;
+  TimeDelta GetProcessInterval() const override;
+
+ private:
+  RtcEventLog* const event_log_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_INCLUDE_GOOG_CC_FACTORY_H_
diff --git a/modules/congestion_controller/include/send_side_congestion_controller.h b/modules/congestion_controller/include/send_side_congestion_controller.h
index 2707cc3..86f59e5 100644
--- a/modules/congestion_controller/include/send_side_congestion_controller.h
+++ b/modules/congestion_controller/include/send_side_congestion_controller.h
@@ -11,19 +11,26 @@
 #ifndef MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_
 #define MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_
 
+#include <atomic>
+#include <functional>
+#include <map>
 #include <memory>
 #include <vector>
 
 #include "common_types.h"  // NOLINT(build/include)
-#include "modules/congestion_controller/delay_based_bwe.h"
+#include "modules/congestion_controller/network_control/include/network_control.h"
+#include "modules/congestion_controller/network_control/include/network_types.h"
+#include "modules/congestion_controller/pacer_controller.h"
 #include "modules/congestion_controller/transport_feedback_adapter.h"
 #include "modules/include/module.h"
 #include "modules/include/module_common_types.h"
 #include "modules/pacing/paced_sender.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/criticalsection.h"
 #include "rtc_base/networkroute.h"
 #include "rtc_base/race_checker.h"
+#include "rtc_base/task_queue.h"
 
 namespace rtc {
 struct SentPacket;
@@ -31,16 +38,23 @@
 
 namespace webrtc {
 
-class BitrateController;
 class Clock;
-class AcknowledgedBitrateEstimator;
-class ProbeController;
 class RateLimiter;
 class RtcEventLog;
 
+namespace send_side_cc_internal {
+// This is used to observe the network controller state and route calls to
+// the proper handler. It also keeps cached values for safe asynchronous use.
+// This makes sure that things running on the worker queue can't access state
+// in SendSideCongestionController, which would risk causing data race on
+// destruction unless members are properly ordered.
+class ControlHandler;
+}  // namespace send_side_cc_internal
+
 class SendSideCongestionController : public CallStatsObserver,
                                      public Module,
-                                     public TransportFeedbackObserver {
+                                     public TransportFeedbackObserver,
+                                     public RtcpBandwidthObserver {
  public:
   // Observer class for bitrate changes announced due to change in bandwidth
   // estimate or due to that the send pacer is full. Fraction loss and rtt is
@@ -86,10 +100,7 @@
   virtual void SignalNetworkState(NetworkState state);
   virtual void SetTransportOverhead(size_t transport_overhead_bytes_per_packet);
 
-  // Deprecated: Use GetBandwidthObserver instead.
-  RTC_DEPRECATED virtual BitrateController* GetBitrateController() const;
-
-  virtual RtcpBandwidthObserver* GetBandwidthObserver() const;
+  virtual RtcpBandwidthObserver* GetBandwidthObserver();
 
   virtual bool AvailableBandwidth(uint32_t* bandwidth) const;
   virtual int64_t GetPacerQueuingDelayMs() const;
@@ -102,6 +113,11 @@
 
   virtual void OnSentPacket(const rtc::SentPacket& sent_packet);
 
+  // Implements RtcpBandwidthObserver
+  void OnReceivedEstimatedBitrate(uint32_t bitrate) override;
+  void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
+                                    int64_t rtt,
+                                    int64_t now_ms) override;
   // Implements CallStatsObserver.
   void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
 
@@ -117,52 +133,64 @@
   void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;
   std::vector<PacketFeedback> GetTransportFeedbackVector() const override;
 
- private:
-  void MaybeTriggerOnNetworkChanged();
+  // Sets the minimum send bitrate and maximum padding bitrate requested by send
+  // streams.
+  // |min_send_bitrate_bps| might be higher that the estimated available network
+  // bitrate and if so, the pacer will send with |min_send_bitrate_bps|.
+  // |max_padding_bitrate_bps| might be higher than the estimate available
+  // network bitrate and if so, the pacer will send padding packets to reach
+  // the min of the estimated available bitrate and |max_padding_bitrate_bps|.
+  void SetSendBitrateLimits(int64_t min_send_bitrate_bps,
+                            int64_t max_padding_bitrate_bps);
+  void SetPacingFactor(float pacing_factor);
 
-  bool IsSendQueueFull() const;
-  bool IsNetworkDown() const;
-  bool HasNetworkParametersToReportChanged(uint32_t bitrate_bps,
-                                           uint8_t fraction_loss,
-                                           int64_t rtt);
-  void LimitOutstandingBytes(size_t num_outstanding_bytes);
+ protected:
+  // Waits long enough that any outstanding tasks should be finished.
+  void WaitOnTasks();
+
+ private:
+  SendSideCongestionController(
+      const Clock* clock,
+      RtcEventLog* event_log,
+      PacedSender* pacer,
+      NetworkControllerFactoryInterface::uptr controller_factory);
+
+  void UpdateStreamsConfig();
+  void WaitOnTask(std::function<void()> closure);
+  void MaybeUpdateOutstandingData();
+  void OnReceivedRtcpReceiverReportBlocks(const ReportBlockList& report_blocks,
+                                          int64_t now_ms);
+
   const Clock* const clock_;
-  rtc::CriticalSection observer_lock_;
-  Observer* observer_ RTC_GUARDED_BY(observer_lock_);
-  RtcEventLog* const event_log_;
   PacedSender* const pacer_;
-  const std::unique_ptr<BitrateController> bitrate_controller_;
-  std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
-  const std::unique_ptr<ProbeController> probe_controller_;
-  const std::unique_ptr<RateLimiter> retransmission_rate_limiter_;
   TransportFeedbackAdapter transport_feedback_adapter_;
-  rtc::CriticalSection network_state_lock_;
-  uint32_t last_reported_bitrate_bps_ RTC_GUARDED_BY(network_state_lock_);
-  uint8_t last_reported_fraction_loss_ RTC_GUARDED_BY(network_state_lock_);
-  int64_t last_reported_rtt_ RTC_GUARDED_BY(network_state_lock_);
-  NetworkState network_state_ RTC_GUARDED_BY(network_state_lock_);
-  bool pause_pacer_ RTC_GUARDED_BY(network_state_lock_);
-  // Duplicate the pacer paused state to avoid grabbing a lock when
-  // pausing the pacer. This can be removed when we move this class
-  // over to the task queue.
-  bool pacer_paused_;
-  rtc::CriticalSection bwe_lock_;
-  int min_bitrate_bps_ RTC_GUARDED_BY(bwe_lock_);
-  std::unique_ptr<DelayBasedBwe> delay_based_bwe_ RTC_GUARDED_BY(bwe_lock_);
-  bool in_cwnd_experiment_;
-  int64_t accepted_queue_ms_;
-  bool was_in_alr_;
+
+  const std::unique_ptr<PacerController> pacer_controller_;
+  const std::unique_ptr<send_side_cc_internal::ControlHandler> control_handler;
+  const std::unique_ptr<NetworkControllerInterface> controller_;
+
+  TimeDelta process_interval_;
+  int64_t last_process_update_ms_ = 0;
+
+  std::map<uint32_t, RTCPReportBlock> last_report_blocks_;
+  Timestamp last_report_block_time_;
+
+  StreamsConfig streams_config_;
   const bool send_side_bwe_with_overhead_;
-  size_t transport_overhead_bytes_per_packet_ RTC_GUARDED_BY(bwe_lock_);
+  std::atomic<size_t> transport_overhead_bytes_per_packet_;
+  std::atomic<bool> network_available_;
 
   rtc::RaceChecker worker_race_;
 
-  bool pacer_pushback_experiment_ = false;
-  float encoding_rate_ = 1.0;
+  // Note that moving ownership of the task queue makes it neccessary to make
+  // sure that there is no outstanding tasks on it using destructed objects.
+  // This is currently guranteed by using explicit reset in the destructor of
+  // this class. It is declared last to indicate that it's lifetime is shorter
+  // than all other members.
+  std::unique_ptr<rtc::TaskQueue> task_queue_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SendSideCongestionController);
 };
-
 }  // namespace webrtc
 
 #endif  // MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_
diff --git a/modules/congestion_controller/network_control/BUILD.gn b/modules/congestion_controller/network_control/BUILD.gn
new file mode 100644
index 0000000..369d9a3
--- /dev/null
+++ b/modules/congestion_controller/network_control/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright (c) 2018 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.
+
+import("../../../webrtc.gni")
+
+rtc_static_library("network_control") {
+  sources = [
+    "include/network_control.h",
+    "include/network_types.h",
+    "include/network_units.h",
+    "network_types.cc",
+    "network_units.cc",
+  ]
+
+  deps = [
+    "../../:module_api",
+    "../../../api:optional",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+  ]
+}
+
+if (rtc_include_tests) {
+  rtc_source_set("network_control_unittests") {
+    testonly = true
+    sources = [
+      "network_units_unittest.cc",
+    ]
+
+    deps = [
+      ":network_control",
+      "../../../test:test_support",
+    ]
+  }
+}
diff --git a/modules/congestion_controller/network_control/include/network_control.h b/modules/congestion_controller/network_control/include/network_control.h
new file mode 100644
index 0000000..d87acbf
--- /dev/null
+++ b/modules/congestion_controller/network_control/include/network_control.h
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_
+#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_
+#include <stdint.h>
+#include <memory>
+
+#include "modules/congestion_controller/network_control/include/network_types.h"
+#include "modules/congestion_controller/network_control/include/network_units.h"
+
+namespace webrtc {
+
+// NetworkControllerObserver is an interface implemented by observers of network
+// controllers. It contains declarations of the possible configuration messages
+// that can be sent from a network controller implementation.
+class NetworkControllerObserver {
+ public:
+  // Called when congestion window configutation is changed.
+  virtual void OnCongestionWindow(CongestionWindow) = 0;
+  // Called when pacer configuration has changed.
+  virtual void OnPacerConfig(PacerConfig) = 0;
+  // Called to indicate that a new probe should be sent.
+  virtual void OnProbeClusterConfig(ProbeClusterConfig) = 0;
+  // Called to indicate target transfer rate as well as giving information about
+  // the current estimate of network parameters.
+  virtual void OnTargetTransferRate(TargetTransferRate) = 0;
+
+ protected:
+  virtual ~NetworkControllerObserver() = default;
+};
+
+// NetworkControllerInterface is implemented by network controllers. A network
+// controller is a class that uses information about network state and traffic
+// to estimate network parameters such as round trip time and bandwidth. Network
+// controllers does not guarantee thread safety, the interface must be used in a
+// non-concurrent fashion.
+class NetworkControllerInterface {
+ public:
+  using uptr = std::unique_ptr<NetworkControllerInterface>;
+  virtual ~NetworkControllerInterface() = default;
+
+  // Called when network availabilty changes.
+  virtual void OnNetworkAvailability(NetworkAvailability) = 0;
+  // Called when the receiving or sending endpoint changes address.
+  virtual void OnNetworkRouteChange(NetworkRouteChange) = 0;
+  // Called periodically with a periodicy as specified by
+  // NetworkControllerFactoryInterface::GetProcessInterval.
+  virtual void OnProcessInterval(ProcessInterval) = 0;
+  // Called when remotely calculated bitrate is received.
+  virtual void OnRemoteBitrateReport(RemoteBitrateReport) = 0;
+  // Called round trip time has been calculated by protocol specific mechanisms.
+  virtual void OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0;
+  // Called when a packet is sent on the network.
+  virtual void OnSentPacket(SentPacket) = 0;
+  // Called when the stream specific configuration has been updated.
+  virtual void OnStreamsConfig(StreamsConfig) = 0;
+  // Called when target transfer rate constraints has been changed.
+  virtual void OnTargetRateConstraints(TargetRateConstraints) = 0;
+  // Called when a protocol specific calculation of packet loss has been made.
+  virtual void OnTransportLossReport(TransportLossReport) = 0;
+  // Called with per packet feedback regarding receive time.
+  virtual void OnTransportPacketsFeedback(TransportPacketsFeedback) = 0;
+};
+
+// NetworkControllerFactoryInterface is an interface for creating a network
+// controller.
+class NetworkControllerFactoryInterface {
+ public:
+  using uptr = std::unique_ptr<NetworkControllerFactoryInterface>;
+  // Used to create a new network controller, requires an observer to be
+  // provided to handle callbacks.
+  virtual NetworkControllerInterface::uptr Create(
+      NetworkControllerObserver* observer) = 0;
+  // Returns the interval by which the network controller expects
+  // OnProcessInterval calls.
+  virtual TimeDelta GetProcessInterval() const = 0;
+  virtual ~NetworkControllerFactoryInterface() = default;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_
diff --git a/modules/congestion_controller/network_control/include/network_types.h b/modules/congestion_controller/network_control/include/network_types.h
new file mode 100644
index 0000000..1df3c4e
--- /dev/null
+++ b/modules/congestion_controller/network_control/include/network_types.h
@@ -0,0 +1,172 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_
+#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_
+#include <stdint.h>
+#include <ostream>
+#include <vector>
+#include "modules/congestion_controller/network_control/include/network_units.h"
+#include "modules/include/module_common_types.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+
+// Configuration
+
+// Use StreamsConfig for information about streams that is required for specific
+// adjustments to the algorithms in network controllers. Especially useful
+// for experiments.
+struct StreamsConfig {
+  StreamsConfig();
+  StreamsConfig(const StreamsConfig&);
+  ~StreamsConfig();
+  Timestamp at_time;
+  bool requests_alr_probing = false;
+  rtc::Optional<double> pacing_factor;
+  rtc::Optional<DataRate> min_pacing_rate;
+  rtc::Optional<DataRate> max_padding_rate;
+};
+
+struct TargetRateConstraints {
+  Timestamp at_time;
+  DataRate starting_rate;
+  DataRate min_data_rate;
+  DataRate max_data_rate;
+};
+
+// Send side information
+
+struct NetworkAvailability {
+  Timestamp at_time;
+  bool network_available = false;
+};
+
+struct NetworkRouteChange {
+  Timestamp at_time;
+  // The TargetRateConstraints are set here so they can be changed synchronously
+  // when network route changes.
+  TargetRateConstraints constraints;
+};
+
+struct SentPacket {
+  Timestamp send_time;
+  DataSize size;
+  PacedPacketInfo pacing_info;
+};
+
+struct PacerQueueUpdate {
+  TimeDelta expected_queue_time;
+};
+
+// Transport level feedback
+
+struct RemoteBitrateReport {
+  Timestamp receive_time;
+  DataRate bandwidth;
+};
+
+struct RoundTripTimeUpdate {
+  Timestamp receive_time;
+  TimeDelta round_trip_time;
+  bool smoothed = false;
+};
+
+struct TransportLossReport {
+  Timestamp receive_time;
+  Timestamp start_time;
+  Timestamp end_time;
+  uint64_t packets_lost_delta = 0;
+  uint64_t packets_received_delta = 0;
+};
+
+struct OutstandingData {
+  DataSize in_flight_data;
+};
+
+// Packet level feedback
+
+struct PacketResult {
+  PacketResult();
+  PacketResult(const PacketResult&);
+  ~PacketResult();
+
+  rtc::Optional<SentPacket> sent_packet;
+  Timestamp receive_time;
+};
+
+struct TransportPacketsFeedback {
+  TransportPacketsFeedback();
+  TransportPacketsFeedback(const TransportPacketsFeedback& other);
+  ~TransportPacketsFeedback();
+
+  Timestamp feedback_time;
+  DataSize data_in_flight;
+  DataSize prior_in_flight;
+  std::vector<PacketResult> packet_feedbacks;
+
+  std::vector<PacketResult> ReceivedWithSendInfo() const;
+  std::vector<PacketResult> LostWithSendInfo() const;
+  std::vector<PacketResult> PacketsWithFeedback() const;
+};
+
+// Network estimation
+
+struct NetworkEstimate {
+  Timestamp at_time;
+  DataRate bandwidth;
+  TimeDelta round_trip_time;
+  TimeDelta bwe_period;
+
+  float loss_rate_ratio = 0;
+  bool changed = true;
+};
+
+// Network control
+struct CongestionWindow {
+  bool enabled = true;
+  DataSize data_window;
+};
+
+struct PacerConfig {
+  Timestamp at_time;
+  // Pacer should send at most data_window data over time_window duration.
+  DataSize data_window;
+  TimeDelta time_window;
+  // Pacer should send at least pad_window data over time_window duration.
+  DataSize pad_window;
+  DataRate data_rate() const { return data_window / time_window; }
+};
+
+struct ProbeClusterConfig {
+  Timestamp at_time;
+  DataRate target_data_rate;
+  TimeDelta target_duration;
+  uint32_t target_probe_count;
+};
+
+struct TargetTransferRate {
+  Timestamp at_time;
+  DataRate target_rate;
+  // The estimate on which the target rate is based on.
+  NetworkEstimate network_estimate;
+};
+
+// Process control
+struct ProcessInterval {
+  Timestamp at_time;
+};
+
+::std::ostream& operator<<(::std::ostream& os,
+                           const ProbeClusterConfig& config);
+::std::ostream& operator<<(::std::ostream& os, const PacerConfig& config);
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_
diff --git a/modules/congestion_controller/network_control/include/network_units.h b/modules/congestion_controller/network_control/include/network_units.h
new file mode 100644
index 0000000..ab7b4b2
--- /dev/null
+++ b/modules/congestion_controller/network_control/include/network_units.h
@@ -0,0 +1,353 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
+#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
+#include <stdint.h>
+#include <limits>
+#include <ostream>
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+namespace units_internal {
+inline int64_t DivideAndRound(int64_t numerator, int64_t denominators) {
+  if (numerator >= 0) {
+    return (numerator + (denominators / 2)) / denominators;
+  } else {
+    return (numerator + (denominators / 2)) / denominators - 1;
+  }
+}
+}  // namespace units_internal
+
+// TimeDelta represents the difference between two timestamps. Connomly this can
+// be a duration. However since two Timestamps are not guaranteed to have the
+// same epoch (they might come from different computers, making exact
+// synchronisation infeasible), the duration covered by a TimeDelta can be
+// undefined. To simplify usage, it can be constructed and converted to
+// different units, specifically seconds (s), milliseconds (ms) and
+// microseconds (us).
+class TimeDelta {
+ public:
+  static const TimeDelta kPlusInfinity;
+  static const TimeDelta kMinusInfinity;
+  static const TimeDelta kNotInitialized;
+  static const TimeDelta kZero;
+  TimeDelta() : TimeDelta(kNotInitialized) {}
+  static TimeDelta Zero() { return kZero; }
+  static TimeDelta Infinity() { return kPlusInfinity; }
+  static TimeDelta seconds(int64_t seconds) { return TimeDelta::s(seconds); }
+  static TimeDelta s(int64_t seconds) {
+    return TimeDelta::us(seconds * 1000000);
+  }
+  static TimeDelta ms(int64_t milliseconds) {
+    return TimeDelta::us(milliseconds * 1000);
+  }
+  static TimeDelta us(int64_t microseconds) {
+    // Infinities only allowed via use of explicit constants.
+    RTC_DCHECK(microseconds > std::numeric_limits<int64_t>::min());
+    RTC_DCHECK(microseconds < std::numeric_limits<int64_t>::max());
+    return TimeDelta(microseconds);
+  }
+  int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
+  int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
+  int64_t us() const {
+    RTC_DCHECK(IsFinite());
+    return microseconds_;
+  }
+  TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
+  bool IsZero() const { return microseconds_ == 0; }
+  bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
+  bool IsInitialized() const {
+    return microseconds_ != kNotInitialized.microseconds_;
+  }
+  bool IsInfinite() const {
+    return *this == kPlusInfinity || *this == kMinusInfinity;
+  }
+  TimeDelta operator+(const TimeDelta& other) const {
+    return TimeDelta::us(us() + other.us());
+  }
+  TimeDelta operator-(const TimeDelta& other) const {
+    return TimeDelta::us(us() - other.us());
+  }
+  TimeDelta operator*(double scalar) const {
+    return TimeDelta::us(us() * scalar);
+  }
+  TimeDelta operator*(int64_t scalar) const {
+    return TimeDelta::us(us() * scalar);
+  }
+  TimeDelta operator*(int32_t scalar) const {
+    return TimeDelta::us(us() * scalar);
+  }
+  bool operator==(const TimeDelta& other) const {
+    return microseconds_ == other.microseconds_;
+  }
+  bool operator!=(const TimeDelta& other) const {
+    return microseconds_ != other.microseconds_;
+  }
+  bool operator<=(const TimeDelta& other) const {
+    return microseconds_ <= other.microseconds_;
+  }
+  bool operator>=(const TimeDelta& other) const {
+    return microseconds_ >= other.microseconds_;
+  }
+  bool operator>(const TimeDelta& other) const {
+    return microseconds_ > other.microseconds_;
+  }
+  bool operator<(const TimeDelta& other) const {
+    return microseconds_ < other.microseconds_;
+  }
+
+ private:
+  explicit TimeDelta(int64_t us) : microseconds_(us) {}
+  int64_t microseconds_;
+};
+inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
+  return delta * scalar;
+}
+
+// Timestamp represents the time that has passed since some unspecified epoch.
+// The epoch is assumed to be before any represented timestamps, this means that
+// negative values are not valid. The most notable feature is that the
+// difference of of two Timestamps results in a TimeDelta.
+class Timestamp {
+ public:
+  static const Timestamp kPlusInfinity;
+  static const Timestamp kNotInitialized;
+  Timestamp() : Timestamp(kNotInitialized) {}
+  static Timestamp Infinity() { return kPlusInfinity; }
+  static Timestamp s(int64_t seconds) { return Timestamp(seconds * 1000000); }
+  static Timestamp ms(int64_t millis) { return Timestamp(millis * 1000); }
+  static Timestamp us(int64_t micros) { return Timestamp(micros); }
+  int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
+  int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
+  int64_t us() const {
+    RTC_DCHECK(IsFinite());
+    return microseconds_;
+  }
+  bool IsInfinite() const {
+    return microseconds_ == kPlusInfinity.microseconds_;
+  }
+  bool IsInitialized() const {
+    return microseconds_ != kNotInitialized.microseconds_;
+  }
+  bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
+  TimeDelta operator-(const Timestamp& other) const {
+    return TimeDelta::us(us() - other.us());
+  }
+  Timestamp operator-(const TimeDelta& delta) const {
+    return Timestamp::us(us() - delta.us());
+  }
+  Timestamp operator+(const TimeDelta& delta) const {
+    return Timestamp::us(us() + delta.us());
+  }
+  bool operator==(const Timestamp& other) const {
+    return microseconds_ == other.microseconds_;
+  }
+  bool operator!=(const Timestamp& other) const {
+    return microseconds_ != other.microseconds_;
+  }
+  bool operator<=(const Timestamp& other) const { return us() <= other.us(); }
+  bool operator>=(const Timestamp& other) const { return us() >= other.us(); }
+  bool operator>(const Timestamp& other) const { return us() > other.us(); }
+  bool operator<(const Timestamp& other) const { return us() < other.us(); }
+
+ private:
+  explicit Timestamp(int64_t us) : microseconds_(us) {}
+  int64_t microseconds_;
+};
+
+// DataSize is a class represeting a count of bytes. Note that while it can be
+// initialized by a number of bits, it does not guarantee that the resolution is
+// kept and the internal storage is in bytes. The number of bits will be
+// truncated to fit.
+class DataSize {
+ public:
+  static const DataSize kZero;
+  static const DataSize kPlusInfinity;
+  static const DataSize kNotInitialized;
+  DataSize() : DataSize(kNotInitialized) {}
+  static DataSize Zero() { return kZero; }
+  static DataSize Infinity() { return kPlusInfinity; }
+  static DataSize bytes(int64_t bytes) { return DataSize(bytes); }
+  static DataSize bits(int64_t bits) { return DataSize(bits / 8); }
+  int64_t bytes() const {
+    RTC_DCHECK(IsFinite());
+    return bytes_;
+  }
+  int64_t kilobytes() const {
+    return units_internal::DivideAndRound(bytes(), 1000);
+  }
+  int64_t bits() const { return bytes() * 8; }
+  int64_t kilobits() const {
+    return units_internal::DivideAndRound(bits(), 1000);
+  }
+  bool IsZero() const { return bytes_ == 0; }
+  bool IsInfinite() const { return bytes_ == kPlusInfinity.bytes_; }
+  bool IsInitialized() const { return bytes_ != kNotInitialized.bytes_; }
+  bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
+  DataSize operator-(const DataSize& other) const {
+    return DataSize::bytes(bytes() - other.bytes());
+  }
+  DataSize operator+(const DataSize& other) const {
+    return DataSize::bytes(bytes() + other.bytes());
+  }
+  DataSize operator*(double scalar) const {
+    return DataSize::bytes(bytes() * scalar);
+  }
+  DataSize operator*(int64_t scalar) const {
+    return DataSize::bytes(bytes() * scalar);
+  }
+  DataSize operator*(int32_t scalar) const {
+    return DataSize::bytes(bytes() * scalar);
+  }
+  DataSize operator/(int64_t scalar) const {
+    return DataSize::bytes(bytes() / scalar);
+  }
+  DataSize& operator-=(const DataSize& other) {
+    bytes_ -= other.bytes();
+    return *this;
+  }
+  DataSize& operator+=(const DataSize& other) {
+    bytes_ += other.bytes();
+    return *this;
+  }
+  bool operator==(const DataSize& other) const {
+    return bytes_ == other.bytes_;
+  }
+  bool operator!=(const DataSize& other) const {
+    return bytes_ != other.bytes_;
+  }
+  bool operator<=(const DataSize& other) const {
+    return bytes_ <= other.bytes_;
+  }
+  bool operator>=(const DataSize& other) const {
+    return bytes_ >= other.bytes_;
+  }
+  bool operator>(const DataSize& other) const { return bytes_ > other.bytes_; }
+  bool operator<(const DataSize& other) const { return bytes_ < other.bytes_; }
+
+ private:
+  explicit DataSize(int64_t bytes) : bytes_(bytes) {}
+  int64_t bytes_;
+};
+inline DataSize operator*(const double& scalar, const DataSize& size) {
+  return size * scalar;
+}
+inline DataSize operator*(const int64_t& scalar, const DataSize& size) {
+  return size * scalar;
+}
+inline DataSize operator*(const int32_t& scalar, const DataSize& size) {
+  return size * scalar;
+}
+
+// DataRate is a class that represents a given data rate. This can be used to
+// represent bandwidth, encoding bitrate, etc. The internal storage is currently
+// bits per second (bps) since this makes it easier to intepret the raw value
+// when debugging. The promised precision, however is only that it will
+// represent bytes per second accurately. Any implementation depending on bps
+// resolution should document this by changing this comment.
+class DataRate {
+ public:
+  static const DataRate kZero;
+  static const DataRate kPlusInfinity;
+  static const DataRate kNotInitialized;
+  DataRate() : DataRate(kNotInitialized) {}
+  static DataRate Zero() { return kZero; }
+  static DataRate Infinity() { return kPlusInfinity; }
+  static DataRate bytes_per_second(int64_t bytes_per_sec) {
+    return DataRate(bytes_per_sec * 8);
+  }
+  static DataRate bits_per_second(int64_t bits_per_sec) {
+    return DataRate(bits_per_sec);
+  }
+  static DataRate bps(int64_t bits_per_sec) {
+    return DataRate::bits_per_second(bits_per_sec);
+  }
+  static DataRate kbps(int64_t kilobits_per_sec) {
+    return DataRate::bits_per_second(kilobits_per_sec * 1000);
+  }
+  int64_t bits_per_second() const {
+    RTC_DCHECK(IsFinite());
+    return bits_per_sec_;
+  }
+  int64_t bytes_per_second() const { return bits_per_second() / 8; }
+  int64_t bps() const { return bits_per_second(); }
+  int64_t kbps() const { return units_internal::DivideAndRound(bps(), 1000); }
+  bool IsZero() const { return bits_per_sec_ == 0; }
+  bool IsInfinite() const {
+    return bits_per_sec_ == kPlusInfinity.bits_per_sec_;
+  }
+  bool IsInitialized() const {
+    return bits_per_sec_ != kNotInitialized.bits_per_sec_;
+  }
+  bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
+  DataRate operator*(double scalar) const {
+    return DataRate::bytes_per_second(bytes_per_second() * scalar);
+  }
+  DataRate operator*(int64_t scalar) const {
+    return DataRate::bytes_per_second(bytes_per_second() * scalar);
+  }
+  DataRate operator*(int32_t scalar) const {
+    return DataRate::bytes_per_second(bytes_per_second() * scalar);
+  }
+  bool operator==(const DataRate& other) const {
+    return bits_per_sec_ == other.bits_per_sec_;
+  }
+  bool operator!=(const DataRate& other) const {
+    return bits_per_sec_ != other.bits_per_sec_;
+  }
+  bool operator<=(const DataRate& other) const {
+    return bits_per_sec_ <= other.bits_per_sec_;
+  }
+  bool operator>=(const DataRate& other) const {
+    return bits_per_sec_ >= other.bits_per_sec_;
+  }
+  bool operator>(const DataRate& other) const {
+    return bits_per_sec_ > other.bits_per_sec_;
+  }
+  bool operator<(const DataRate& other) const {
+    return bits_per_sec_ < other.bits_per_sec_;
+  }
+
+ private:
+  // Bits per second used internally to simplify debugging by making the value
+  // more recognizable.
+  explicit DataRate(int64_t bits_per_second) : bits_per_sec_(bits_per_second) {}
+  int64_t bits_per_sec_;
+};
+inline DataRate operator*(const double& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
+  return rate * scalar;
+}
+
+DataRate operator/(const DataSize& size, const TimeDelta& duration);
+TimeDelta operator/(const DataSize& size, const DataRate& rate);
+DataSize operator*(const DataRate& rate, const TimeDelta& duration);
+DataSize operator*(const TimeDelta& duration, const DataRate& rate);
+
+::std::ostream& operator<<(::std::ostream& os, const DataRate& datarate);
+::std::ostream& operator<<(::std::ostream& os, const DataSize& datasize);
+::std::ostream& operator<<(::std::ostream& os, const Timestamp& timestamp);
+::std::ostream& operator<<(::std::ostream& os, const TimeDelta& delta);
+
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
diff --git a/modules/congestion_controller/network_control/network_types.cc b/modules/congestion_controller/network_control/network_types.cc
new file mode 100644
index 0000000..e535559
--- /dev/null
+++ b/modules/congestion_controller/network_control/network_types.cc
@@ -0,0 +1,63 @@
+/*
+ *  Copyright (c) 2018 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 "modules/congestion_controller/network_control/include/network_types.h"
+
+namespace webrtc {
+
+StreamsConfig::StreamsConfig() = default;
+StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
+StreamsConfig::~StreamsConfig() = default;
+
+PacketResult::PacketResult() = default;
+PacketResult::PacketResult(const PacketResult& other) = default;
+PacketResult::~PacketResult() = default;
+
+TransportPacketsFeedback::TransportPacketsFeedback() = default;
+TransportPacketsFeedback::TransportPacketsFeedback(
+    const TransportPacketsFeedback& other) = default;
+TransportPacketsFeedback::~TransportPacketsFeedback() = default;
+
+std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
+    const {
+  std::vector<PacketResult> res;
+  for (const PacketResult& fb : packet_feedbacks) {
+    if (fb.receive_time.IsFinite() && fb.sent_packet.has_value()) {
+      res.push_back(fb);
+    }
+  }
+  return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
+  std::vector<PacketResult> res;
+  for (const PacketResult& fb : packet_feedbacks) {
+    if (fb.receive_time.IsInfinite() && fb.sent_packet.has_value()) {
+      res.push_back(fb);
+    }
+  }
+  return res;
+}
+
+std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
+    const {
+  return packet_feedbacks;
+}
+
+::std::ostream& operator<<(::std::ostream& os,
+                           const ProbeClusterConfig& config) {
+  return os << "ProbeClusterConfig(...)";
+}
+
+::std::ostream& operator<<(::std::ostream& os, const PacerConfig& config) {
+  return os << "PacerConfig(...)";
+}
+
+}  // namespace webrtc
diff --git a/modules/congestion_controller/network_control/network_units.cc b/modules/congestion_controller/network_control/network_units.cc
new file mode 100644
index 0000000..fd4a301
--- /dev/null
+++ b/modules/congestion_controller/network_control/network_units.cc
@@ -0,0 +1,101 @@
+/*
+ *  Copyright (c) 2018 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 "modules/congestion_controller/network_control/include/network_units.h"
+
+namespace webrtc {
+namespace {
+int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
+int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
+int64_t kSignedNotInitializedVal = kMinusInfinityVal + 1;
+int64_t kNotInitializedVal = -1;
+}  // namespace
+const TimeDelta TimeDelta::kZero = TimeDelta(0);
+const TimeDelta TimeDelta::kMinusInfinity = TimeDelta(kMinusInfinityVal);
+const TimeDelta TimeDelta::kPlusInfinity = TimeDelta(kPlusInfinityVal);
+const TimeDelta TimeDelta::kNotInitialized =
+    TimeDelta(kSignedNotInitializedVal);
+
+const Timestamp Timestamp::kPlusInfinity = Timestamp(kPlusInfinityVal);
+const Timestamp Timestamp::kNotInitialized = Timestamp(kNotInitializedVal);
+
+const DataRate DataRate::kZero = DataRate(0);
+const DataRate DataRate::kPlusInfinity = DataRate(kPlusInfinityVal);
+const DataRate DataRate::kNotInitialized = DataRate(kNotInitializedVal);
+
+const DataSize DataSize::kZero = DataSize(0);
+const DataSize DataSize::kPlusInfinity = DataSize(kPlusInfinityVal);
+const DataSize DataSize::kNotInitialized = DataSize(kNotInitializedVal);
+
+DataRate operator/(const DataSize& size, const TimeDelta& duration) {
+  RTC_DCHECK(size.bytes() < std::numeric_limits<int64_t>::max() / 1000000)
+      << "size is too large, size: " << size.bytes() << " is not less than "
+      << std::numeric_limits<int64_t>::max() / 1000000;
+  auto bytes_per_sec = size.bytes() * 1000000 / duration.us();
+  return DataRate::bytes_per_second(bytes_per_sec);
+}
+
+TimeDelta operator/(const DataSize& size, const DataRate& rate) {
+  RTC_DCHECK(size.bytes() < std::numeric_limits<int64_t>::max() / 1000000)
+      << "size is too large, size: " << size.bytes() << " is not less than "
+      << std::numeric_limits<int64_t>::max() / 1000000;
+  auto microseconds = size.bytes() * 1000000 / rate.bytes_per_second();
+  return TimeDelta::us(microseconds);
+}
+
+DataSize operator*(const DataRate& rate, const TimeDelta& duration) {
+  auto micro_bytes = rate.bytes_per_second() * duration.us();
+  auto bytes = units_internal::DivideAndRound(micro_bytes, 1000000);
+  return DataSize::bytes(bytes);
+}
+
+DataSize operator*(const TimeDelta& duration, const DataRate& rate) {
+  return rate * duration;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const DataRate& value) {
+  if (value == DataRate::kPlusInfinity) {
+    return os << "inf bps";
+  } else if (value == DataRate::kNotInitialized) {
+    return os << "? bps";
+  } else {
+    return os << value.bps() << " bps";
+  }
+}
+::std::ostream& operator<<(::std::ostream& os, const DataSize& value) {
+  if (value == DataSize::kPlusInfinity) {
+    return os << "inf bytes";
+  } else if (value == DataSize::kNotInitialized) {
+    return os << "? bytes";
+  } else {
+    return os << value.bytes() << " bytes";
+  }
+}
+::std::ostream& operator<<(::std::ostream& os, const Timestamp& value) {
+  if (value == Timestamp::kPlusInfinity) {
+    return os << "inf ms";
+  } else if (value == Timestamp::kNotInitialized) {
+    return os << "? ms";
+  } else {
+    return os << value.ms() << " ms";
+  }
+}
+::std::ostream& operator<<(::std::ostream& os, const TimeDelta& value) {
+  if (value == TimeDelta::kPlusInfinity) {
+    return os << "+inf ms";
+  } else if (value == TimeDelta::kMinusInfinity) {
+    return os << "-inf ms";
+  } else if (value == TimeDelta::kNotInitialized) {
+    return os << "? ms";
+  } else {
+    return os << value.ms() << " ms";
+  }
+}
+}  // namespace webrtc
diff --git a/modules/congestion_controller/network_control/network_units_unittest.cc b/modules/congestion_controller/network_control/network_units_unittest.cc
new file mode 100644
index 0000000..5c7fa87
--- /dev/null
+++ b/modules/congestion_controller/network_control/network_units_unittest.cc
@@ -0,0 +1,307 @@
+/*
+ *  Copyright (c) 2018 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 "modules/congestion_controller/network_control/include/network_units.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace test {
+
+TEST(TimeDeltaTest, GetBackSameValues) {
+  const int64_t kValue = 499;
+  for (int sign = -1; sign <= 1; ++sign) {
+    int64_t value = kValue * sign;
+    EXPECT_EQ(TimeDelta::ms(value).ms(), value);
+    EXPECT_EQ(TimeDelta::us(value).us(), value);
+    EXPECT_EQ(TimeDelta::s(value).s(), value);
+    EXPECT_EQ(TimeDelta::seconds(value).s(), value);
+  }
+  EXPECT_EQ(TimeDelta::Zero().us(), 0);
+}
+
+TEST(TimeDeltaTest, GetDifferentPrefix) {
+  const int64_t kValue = 3000000;
+  EXPECT_EQ(TimeDelta::us(kValue).s(), kValue / 1000000);
+  EXPECT_EQ(TimeDelta::ms(kValue).s(), kValue / 1000);
+  EXPECT_EQ(TimeDelta::us(kValue).ms(), kValue / 1000);
+
+  EXPECT_EQ(TimeDelta::ms(kValue).us(), kValue * 1000);
+  EXPECT_EQ(TimeDelta::s(kValue).ms(), kValue * 1000);
+  EXPECT_EQ(TimeDelta::s(kValue).us(), kValue * 1000000);
+}
+
+TEST(TimeDeltaTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(TimeDelta::Zero().IsZero());
+  EXPECT_FALSE(TimeDelta::ms(kValue).IsZero());
+
+  EXPECT_TRUE(TimeDelta::Infinity().IsInfinite());
+  EXPECT_TRUE(TimeDelta::kPlusInfinity.IsInfinite());
+  EXPECT_TRUE(TimeDelta::kMinusInfinity.IsInfinite());
+  EXPECT_FALSE(TimeDelta::Zero().IsInfinite());
+  EXPECT_FALSE(TimeDelta::ms(-kValue).IsInfinite());
+  EXPECT_FALSE(TimeDelta::ms(kValue).IsInfinite());
+
+  EXPECT_FALSE(TimeDelta::Infinity().IsFinite());
+  EXPECT_FALSE(TimeDelta::kPlusInfinity.IsFinite());
+  EXPECT_FALSE(TimeDelta::kMinusInfinity.IsFinite());
+  EXPECT_TRUE(TimeDelta::ms(-kValue).IsFinite());
+  EXPECT_TRUE(TimeDelta::ms(kValue).IsFinite());
+  EXPECT_TRUE(TimeDelta::Zero().IsFinite());
+}
+
+TEST(TimeDeltaTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const TimeDelta small = TimeDelta::ms(kSmall);
+  const TimeDelta large = TimeDelta::ms(kLarge);
+
+  EXPECT_EQ(TimeDelta::Zero(), TimeDelta::Zero());
+  EXPECT_EQ(TimeDelta::Infinity(), TimeDelta::Infinity());
+  EXPECT_EQ(small, TimeDelta::ms(kSmall));
+  EXPECT_LE(small, TimeDelta::ms(kSmall));
+  EXPECT_GE(small, TimeDelta::ms(kSmall));
+  EXPECT_NE(small, TimeDelta::ms(kLarge));
+  EXPECT_LE(small, TimeDelta::ms(kLarge));
+  EXPECT_LT(small, TimeDelta::ms(kLarge));
+  EXPECT_GE(large, TimeDelta::ms(kSmall));
+  EXPECT_GT(large, TimeDelta::ms(kSmall));
+  EXPECT_LT(TimeDelta::kZero, small);
+  EXPECT_GT(TimeDelta::kZero, TimeDelta::ms(-kSmall));
+  EXPECT_GT(TimeDelta::kZero, TimeDelta::ms(-kSmall));
+
+  EXPECT_GT(TimeDelta::kPlusInfinity, large);
+  EXPECT_LT(TimeDelta::kMinusInfinity, TimeDelta::kZero);
+}
+
+TEST(TimeDeltaTest, MathOperations) {
+  const int64_t kValueA = 267;
+  const int64_t kValueB = 450;
+  const TimeDelta delta_a = TimeDelta::ms(kValueA);
+  const TimeDelta delta_b = TimeDelta::ms(kValueB);
+  EXPECT_EQ((delta_a + delta_b).ms(), kValueA + kValueB);
+  EXPECT_EQ((delta_a - delta_b).ms(), kValueA - kValueB);
+
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((TimeDelta::us(kValueA) * kValueB).us(), kValueA * kValueB);
+  EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value);
+  EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue);
+
+  EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
+  EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
+}
+
+TEST(TimestampTest, GetBackSameValues) {
+  const int64_t kValue = 499;
+  EXPECT_EQ(Timestamp::ms(kValue).ms(), kValue);
+  EXPECT_EQ(Timestamp::us(kValue).us(), kValue);
+  EXPECT_EQ(Timestamp::s(kValue).s(), kValue);
+}
+
+TEST(TimestampTest, GetDifferentPrefix) {
+  const int64_t kValue = 3000000;
+  EXPECT_EQ(Timestamp::us(kValue).s(), kValue / 1000000);
+  EXPECT_EQ(Timestamp::ms(kValue).s(), kValue / 1000);
+  EXPECT_EQ(Timestamp::us(kValue).ms(), kValue / 1000);
+
+  EXPECT_EQ(Timestamp::ms(kValue).us(), kValue * 1000);
+  EXPECT_EQ(Timestamp::s(kValue).ms(), kValue * 1000);
+  EXPECT_EQ(Timestamp::s(kValue).us(), kValue * 1000000);
+}
+
+TEST(TimestampTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+
+  EXPECT_TRUE(Timestamp::Infinity().IsInfinite());
+  EXPECT_FALSE(Timestamp::ms(kValue).IsInfinite());
+
+  EXPECT_FALSE(Timestamp::kNotInitialized.IsFinite());
+  EXPECT_FALSE(Timestamp::Infinity().IsFinite());
+  EXPECT_TRUE(Timestamp::ms(kValue).IsFinite());
+}
+
+TEST(TimestampTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+
+  EXPECT_EQ(Timestamp::Infinity(), Timestamp::Infinity());
+  EXPECT_EQ(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_GE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
+  EXPECT_NE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_LT(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
+  EXPECT_GE(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
+  EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
+}
+
+TEST(UnitConversionTest, TimestampAndTimeDeltaMath) {
+  const int64_t kValueA = 267;
+  const int64_t kValueB = 450;
+  const Timestamp time_a = Timestamp::ms(kValueA);
+  const Timestamp time_b = Timestamp::ms(kValueB);
+  const TimeDelta delta_a = TimeDelta::ms(kValueA);
+
+  EXPECT_EQ((time_a - time_b), TimeDelta::ms(kValueA - kValueB));
+  EXPECT_EQ((time_b - delta_a), Timestamp::ms(kValueB - kValueA));
+  EXPECT_EQ((time_b + delta_a), Timestamp::ms(kValueB + kValueA));
+}
+
+TEST(DataSizeTest, GetBackSameValues) {
+  const int64_t kValue = 123 * 8;
+  EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue);
+  EXPECT_EQ(DataSize::bits(kValue).bits(), kValue);
+}
+
+TEST(DataSizeTest, GetDifferentPrefix) {
+  const int64_t kValue = 123 * 8000;
+  EXPECT_EQ(DataSize::bytes(kValue).bits(), kValue * 8);
+  EXPECT_EQ(DataSize::bits(kValue).bytes(), kValue / 8);
+  EXPECT_EQ(DataSize::bits(kValue).kilobits(), kValue / 1000);
+  EXPECT_EQ(DataSize::bytes(kValue).kilobytes(), kValue / 1000);
+}
+
+TEST(DataSizeTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(DataSize::Zero().IsZero());
+  EXPECT_FALSE(DataSize::bytes(kValue).IsZero());
+
+  EXPECT_TRUE(DataSize::Infinity().IsInfinite());
+  EXPECT_TRUE(DataSize::kPlusInfinity.IsInfinite());
+  EXPECT_FALSE(DataSize::Zero().IsInfinite());
+  EXPECT_FALSE(DataSize::bytes(kValue).IsInfinite());
+
+  EXPECT_FALSE(DataSize::Infinity().IsFinite());
+  EXPECT_FALSE(DataSize::kPlusInfinity.IsFinite());
+  EXPECT_TRUE(DataSize::bytes(kValue).IsFinite());
+  EXPECT_TRUE(DataSize::Zero().IsFinite());
+}
+
+TEST(DataSizeTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const DataSize small = DataSize::bytes(kSmall);
+  const DataSize large = DataSize::bytes(kLarge);
+
+  EXPECT_EQ(DataSize::Zero(), DataSize::Zero());
+  EXPECT_EQ(DataSize::Infinity(), DataSize::Infinity());
+  EXPECT_EQ(small, small);
+  EXPECT_LE(small, small);
+  EXPECT_GE(small, small);
+  EXPECT_NE(small, large);
+  EXPECT_LE(small, large);
+  EXPECT_LT(small, large);
+  EXPECT_GE(large, small);
+  EXPECT_GT(large, small);
+  EXPECT_LT(DataSize::kZero, small);
+
+  EXPECT_GT(DataSize::kPlusInfinity, large);
+}
+
+TEST(DataSizeTest, MathOperations) {
+  const int64_t kValueA = 450;
+  const int64_t kValueB = 267;
+  const DataSize size_a = DataSize::bytes(kValueA);
+  const DataSize size_b = DataSize::bytes(kValueB);
+  EXPECT_EQ((size_a + size_b).bytes(), kValueA + kValueB);
+  EXPECT_EQ((size_a - size_b).bytes(), kValueA - kValueB);
+
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((size_a * kValueB).bytes(), kValueA * kValueB);
+  EXPECT_EQ((size_a * kInt32Value).bytes(), kValueA * kInt32Value);
+  EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue);
+
+  EXPECT_EQ((size_a / 10).bytes(), kValueA / 10);
+
+  DataSize mutable_size = DataSize::bytes(kValueA);
+  mutable_size += size_b;
+  EXPECT_EQ(mutable_size.bytes(), kValueA + kValueB);
+  mutable_size -= size_a;
+  EXPECT_EQ(mutable_size.bytes(), kValueB);
+}
+
+TEST(DataRateTest, GetBackSameValues) {
+  const int64_t kValue = 123 * 8;
+  EXPECT_EQ(DataRate::bytes_per_second(kValue).bytes_per_second(), kValue);
+  EXPECT_EQ(DataRate::bits_per_second(kValue).bits_per_second(), kValue);
+  EXPECT_EQ(DataRate::bps(kValue).bps(), kValue);
+  EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue);
+}
+
+TEST(DataRateTest, GetDifferentPrefix) {
+  const int64_t kValue = 123 * 8000;
+  EXPECT_EQ(DataRate::bytes_per_second(kValue).bps(), kValue * 8);
+  EXPECT_EQ(DataRate::bits_per_second(kValue).bytes_per_second(), kValue / 8);
+  EXPECT_EQ(DataRate::bps(kValue).kbps(), kValue / 1000);
+}
+
+TEST(DataRateTest, IdentityChecks) {
+  const int64_t kValue = 3000;
+  EXPECT_TRUE(DataRate::Zero().IsZero());
+  EXPECT_FALSE(DataRate::bytes_per_second(kValue).IsZero());
+
+  EXPECT_TRUE(DataRate::Infinity().IsInfinite());
+  EXPECT_TRUE(DataRate::kPlusInfinity.IsInfinite());
+  EXPECT_FALSE(DataRate::Zero().IsInfinite());
+  EXPECT_FALSE(DataRate::bytes_per_second(kValue).IsInfinite());
+
+  EXPECT_FALSE(DataRate::Infinity().IsFinite());
+  EXPECT_FALSE(DataRate::kPlusInfinity.IsFinite());
+  EXPECT_TRUE(DataRate::bytes_per_second(kValue).IsFinite());
+  EXPECT_TRUE(DataRate::Zero().IsFinite());
+}
+
+TEST(DataRateTest, ComparisonOperators) {
+  const int64_t kSmall = 450;
+  const int64_t kLarge = 451;
+  const DataRate small = DataRate::bytes_per_second(kSmall);
+  const DataRate large = DataRate::bytes_per_second(kLarge);
+
+  EXPECT_EQ(DataRate::Zero(), DataRate::Zero());
+  EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity());
+  EXPECT_EQ(small, small);
+  EXPECT_LE(small, small);
+  EXPECT_GE(small, small);
+  EXPECT_NE(small, large);
+  EXPECT_LE(small, large);
+  EXPECT_LT(small, large);
+  EXPECT_GE(large, small);
+  EXPECT_GT(large, small);
+  EXPECT_LT(DataRate::kZero, small);
+  EXPECT_GT(DataRate::kPlusInfinity, large);
+}
+
+TEST(DataRateTest, MathOperations) {
+  const int64_t kValueA = 450;
+  const int64_t kValueB = 267;
+  const DataRate size_a = DataRate::bytes_per_second(kValueA);
+  const int32_t kInt32Value = 123;
+  const double kFloatValue = 123.0;
+  EXPECT_EQ((size_a * kValueB).bytes_per_second(), kValueA * kValueB);
+  EXPECT_EQ((size_a * kInt32Value).bytes_per_second(), kValueA * kInt32Value);
+  EXPECT_EQ((size_a * kFloatValue).bytes_per_second(), kValueA * kFloatValue);
+}
+
+TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
+  const int64_t kValueA = 5;
+  const int64_t kValueB = 450;
+  const int64_t kValueC = 45000;
+  const TimeDelta delta_a = TimeDelta::seconds(kValueA);
+  const DataRate rate_b = DataRate::bytes_per_second(kValueB);
+  const DataSize size_c = DataSize::bytes(kValueC);
+  EXPECT_EQ((delta_a * rate_b).bytes(), kValueA * kValueB);
+  EXPECT_EQ((size_c / delta_a).bytes_per_second(), kValueC / kValueA);
+  EXPECT_EQ((size_c / rate_b).s(), kValueC / kValueB);
+}
+
+}  // namespace test
+}  // namespace webrtc
diff --git a/modules/congestion_controller/pacer_controller.cc b/modules/congestion_controller/pacer_controller.cc
new file mode 100644
index 0000000..556448b
--- /dev/null
+++ b/modules/congestion_controller/pacer_controller.cc
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2018 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 "modules/congestion_controller/pacer_controller.h"
+
+#include "modules/congestion_controller/network_control/include/network_units.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+PacerController::PacerController(PacedSender* pacer) : pacer_(pacer) {
+  sequenced_checker_.Detach();
+}
+
+PacerController::~PacerController() = default;
+
+void PacerController::OnCongestionWindow(CongestionWindow congestion_window) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  if (congestion_window.enabled) {
+    congestion_window_ = congestion_window;
+  } else {
+    congestion_window_ = rtc::nullopt;
+    congested_ = false;
+    UpdatePacerState();
+  }
+}
+
+void PacerController::OnNetworkAvailability(NetworkAvailability msg) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  network_available_ = msg.network_available;
+  congested_ = false;
+  UpdatePacerState();
+}
+
+void PacerController::OnNetworkRouteChange(NetworkRouteChange) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  congested_ = false;
+  UpdatePacerState();
+}
+
+void PacerController::OnPacerConfig(PacerConfig msg) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  DataRate pacing_rate = msg.data_window / msg.time_window;
+  DataRate padding_rate = msg.pad_window / msg.time_window;
+  pacer_->SetPacingRates(pacing_rate.bps(), padding_rate.bps());
+}
+
+void PacerController::OnProbeClusterConfig(ProbeClusterConfig config) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  int64_t bitrate_bps = config.target_data_rate.bps();
+  pacer_->CreateProbeCluster(bitrate_bps);
+}
+
+void PacerController::OnOutstandingData(OutstandingData msg) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  if (congestion_window_.has_value()) {
+    congested_ = msg.in_flight_data > congestion_window_->data_window;
+  }
+  UpdatePacerState();
+}
+
+void PacerController::UpdatePacerState() {
+  bool pause = congested_ || !network_available_;
+  SetPacerState(pause);
+}
+
+void PacerController::SetPacerState(bool paused) {
+  if (paused && !pacer_paused_)
+    pacer_->Pause();
+  else if (!paused && pacer_paused_)
+    pacer_->Resume();
+  pacer_paused_ = paused;
+}
+
+}  // namespace webrtc
diff --git a/modules/congestion_controller/pacer_controller.h b/modules/congestion_controller/pacer_controller.h
new file mode 100644
index 0000000..2679894
--- /dev/null
+++ b/modules/congestion_controller/pacer_controller.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2018 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.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_PACER_CONTROLLER_H_
+#define MODULES_CONGESTION_CONTROLLER_PACER_CONTROLLER_H_
+
+#include <memory>
+
+#include "modules/congestion_controller/network_control/include/network_types.h"
+#include "modules/pacing/paced_sender.h"
+#include "rtc_base/sequenced_task_checker.h"
+
+namespace webrtc {
+class Clock;
+
+// Wrapper class to control pacer using task queues. Note that this class is
+// only designed to be used from a single task queue and has no built in
+// concurrency safety.
+// TODO(srte): Integrate this interface directly into PacedSender.
+class PacerController {
+ public:
+  explicit PacerController(PacedSender* pacer);
+  ~PacerController();
+  void OnCongestionWindow(CongestionWindow msg);
+  void OnNetworkAvailability(NetworkAvailability msg);
+  void OnNetworkRouteChange(NetworkRouteChange msg);
+  void OnOutstandingData(OutstandingData msg);
+  void OnPacerConfig(PacerConfig msg);
+  void OnProbeClusterConfig(ProbeClusterConfig msg);
+
+ private:
+  void UpdatePacerState();
+  void SetPacerState(bool paused);
+  PacedSender* const pacer_;
+
+  rtc::Optional<PacerConfig> current_pacer_config_;
+  rtc::Optional<CongestionWindow> congestion_window_;
+  bool congested_ = false;
+  bool pacer_paused_ = false;
+  bool network_available_ = true;
+
+  rtc::SequencedTaskChecker sequenced_checker_;
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(PacerController);
+};
+}  // namespace webrtc
+#endif  // MODULES_CONGESTION_CONTROLLER_PACER_CONTROLLER_H_
diff --git a/modules/congestion_controller/probe_bitrate_estimator.cc b/modules/congestion_controller/probe_bitrate_estimator.cc
index 8c754d7..34f4891 100644
--- a/modules/congestion_controller/probe_bitrate_estimator.cc
+++ b/modules/congestion_controller/probe_bitrate_estimator.cc
@@ -66,8 +66,8 @@
 
   EraseOldClusters(packet_feedback.arrival_time_ms - kMaxClusterHistoryMs);
 
-  int payload_size_bits = rtc::dchecked_cast<int>(
-      packet_feedback.payload_size * 8);
+  int payload_size_bits =
+      rtc::dchecked_cast<int>(packet_feedback.payload_size * 8);
   AggregatedCluster* cluster = &clusters_[cluster_id];
 
   if (packet_feedback.send_time_ms < cluster->first_send_ms) {
diff --git a/modules/congestion_controller/probe_bitrate_estimator.h b/modules/congestion_controller/probe_bitrate_estimator.h
index bb8a7ed..cb10a6f 100644
--- a/modules/congestion_controller/probe_bitrate_estimator.h
+++ b/modules/congestion_controller/probe_bitrate_estimator.h
@@ -11,8 +11,8 @@
 #ifndef MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
 #define MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
 
-#include <map>
 #include <limits>
+#include <map>
 
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 
diff --git a/modules/congestion_controller/probe_bitrate_estimator_unittest.cc b/modules/congestion_controller/probe_bitrate_estimator_unittest.cc
index 6d21de4..df4f24b 100644
--- a/modules/congestion_controller/probe_bitrate_estimator_unittest.cc
+++ b/modules/congestion_controller/probe_bitrate_estimator_unittest.cc
@@ -10,8 +10,8 @@
 
 #include "modules/congestion_controller/probe_bitrate_estimator.h"
 
-#include <vector>
 #include <utility>
+#include <vector>
 
 #include "modules/remote_bitrate_estimator/aimd_rate_control.h"
 #include "test/gmock.h"
diff --git a/modules/congestion_controller/probe_controller.cc b/modules/congestion_controller/probe_controller.cc
index 8e6ae7c..b0fca7b 100644
--- a/modules/congestion_controller/probe_controller.cc
+++ b/modules/congestion_controller/probe_controller.cc
@@ -21,6 +21,12 @@
 namespace webrtc {
 
 namespace {
+// The minimum number probing packets used.
+constexpr int kMinProbePacketsSent = 5;
+
+// The minimum probing duration in ms.
+constexpr int kMinProbeDurationMs = 15;
+
 // Maximum waiting time from the time of initiating probing to getting
 // the measured results back.
 constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000;
@@ -69,19 +75,20 @@
 
 }  // namespace
 
-ProbeController::ProbeController(PacedSender* pacer, const Clock* clock)
-    : pacer_(pacer), clock_(clock), enable_periodic_alr_probing_(false) {
-  Reset();
+ProbeController::ProbeController(NetworkControllerObserver* observer)
+    : observer_(observer), enable_periodic_alr_probing_(false) {
+  Reset(0);
   in_rapid_recovery_experiment_ = webrtc::field_trial::FindFullName(
                                       kBweRapidRecoveryExperiment) == "Enabled";
 }
 
+ProbeController::~ProbeController() {}
+
 void ProbeController::SetBitrates(int64_t min_bitrate_bps,
                                   int64_t start_bitrate_bps,
-                                  int64_t max_bitrate_bps) {
-  rtc::CritScope cs(&critsect_);
-
-  if (start_bitrate_bps > 0)  {
+                                  int64_t max_bitrate_bps,
+                                  int64_t at_time_ms) {
+  if (start_bitrate_bps > 0) {
     start_bitrate_bps_ = start_bitrate_bps;
     estimated_bitrate_bps_ = start_bitrate_bps;
   } else if (start_bitrate_bps_ == 0) {
@@ -95,8 +102,8 @@
 
   switch (state_) {
     case State::kInit:
-      if (network_state_ == kNetworkUp)
-        InitiateExponentialProbing();
+      if (network_available_)
+        InitiateExponentialProbing(at_time_ms);
       break;
 
     case State::kWaitingForProbingResult:
@@ -119,33 +126,32 @@
         RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated",
                                    max_bitrate_bps_ / 1000);
 
-        InitiateProbing(clock_->TimeInMilliseconds(), {max_bitrate_bps}, false);
+        InitiateProbing(at_time_ms, {max_bitrate_bps}, false);
       }
       break;
   }
 }
 
-void ProbeController::OnNetworkStateChanged(NetworkState network_state) {
-  rtc::CritScope cs(&critsect_);
-  network_state_ = network_state;
-  if (network_state_ == kNetworkUp && state_ == State::kInit)
-    InitiateExponentialProbing();
+void ProbeController::OnNetworkAvailability(NetworkAvailability msg) {
+  network_available_ = msg.network_available;
+  if (network_available_ && state_ == State::kInit && start_bitrate_bps_ > 0)
+    InitiateExponentialProbing(msg.at_time.ms());
 }
 
-void ProbeController::InitiateExponentialProbing() {
-  RTC_DCHECK(network_state_ == kNetworkUp);
+void ProbeController::InitiateExponentialProbing(int64_t at_time_ms) {
+  RTC_DCHECK(network_available_);
   RTC_DCHECK(state_ == State::kInit);
   RTC_DCHECK_GT(start_bitrate_bps_, 0);
 
   // When probing at 1.8 Mbps ( 6x 300), this represents a threshold of
   // 1.2 Mbps to continue probing.
-  InitiateProbing(clock_->TimeInMilliseconds(),
-                  {3 * start_bitrate_bps_, 6 * start_bitrate_bps_}, true);
+  InitiateProbing(at_time_ms, {3 * start_bitrate_bps_, 6 * start_bitrate_bps_},
+                  true);
 }
 
-void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps) {
-  rtc::CritScope cs(&critsect_);
-  int64_t now_ms = clock_->TimeInMilliseconds();
+void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps,
+                                          int64_t at_time_ms) {
+  int64_t now_ms = at_time_ms;
 
   if (mid_call_probing_waiting_for_result_ &&
       bitrate_bps >= mid_call_probing_succcess_threshold_) {
@@ -179,36 +185,36 @@
 }
 
 void ProbeController::EnablePeriodicAlrProbing(bool enable) {
-  rtc::CritScope cs(&critsect_);
   enable_periodic_alr_probing_ = enable;
 }
 
+void ProbeController::SetAlrStartTimeMs(
+    rtc::Optional<int64_t> alr_start_time_ms) {
+  alr_start_time_ms_ = alr_start_time_ms;
+}
 void ProbeController::SetAlrEndedTimeMs(int64_t alr_end_time_ms) {
-  rtc::CritScope cs(&critsect_);
   alr_end_time_ms_.emplace(alr_end_time_ms);
 }
 
-void ProbeController::RequestProbe() {
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  rtc::CritScope cs(&critsect_);
+void ProbeController::RequestProbe(int64_t at_time_ms) {
   // Called once we have returned to normal state after a large drop in
   // estimated bandwidth. The current response is to initiate a single probe
   // session (if not already probing) at the previous bitrate.
   //
   // If the probe session fails, the assumption is that this drop was a
   // real one from a competing flow or a network change.
-  bool in_alr = pacer_->GetApplicationLimitedRegionStartTime().has_value();
+  bool in_alr = alr_start_time_ms_.has_value();
   bool alr_ended_recently =
       (alr_end_time_ms_.has_value() &&
-       now_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
+       at_time_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
   if (in_alr || alr_ended_recently || in_rapid_recovery_experiment_) {
     if (state_ == State::kProbingComplete) {
       uint32_t suggested_probe_bps =
           kProbeFractionAfterDrop * bitrate_before_last_large_drop_bps_;
       uint32_t min_expected_probe_result_bps =
           (1 - kProbeUncertainty) * suggested_probe_bps;
-      int64_t time_since_drop_ms = now_ms - time_of_last_large_drop_ms_;
-      int64_t time_since_probe_ms = now_ms - last_bwe_drop_probing_time_ms_;
+      int64_t time_since_drop_ms = at_time_ms - time_of_last_large_drop_ms_;
+      int64_t time_since_probe_ms = at_time_ms - last_bwe_drop_probing_time_ms_;
       if (min_expected_probe_result_bps > estimated_bitrate_bps_ &&
           time_since_drop_ms < kBitrateDropTimeoutMs &&
           time_since_probe_ms > kMinTimeBetweenAlrProbesMs) {
@@ -216,24 +222,23 @@
         // Track how often we probe in response to bandwidth drop in ALR.
         RTC_HISTOGRAM_COUNTS_10000(
             "WebRTC.BWE.BweDropProbingIntervalInS",
-            (now_ms - last_bwe_drop_probing_time_ms_) / 1000);
-        InitiateProbing(now_ms, {suggested_probe_bps}, false);
-        last_bwe_drop_probing_time_ms_ = now_ms;
+            (at_time_ms - last_bwe_drop_probing_time_ms_) / 1000);
+        InitiateProbing(at_time_ms, {suggested_probe_bps}, false);
+        last_bwe_drop_probing_time_ms_ = at_time_ms;
       }
     }
   }
 }
 
-void ProbeController::Reset() {
-  rtc::CritScope cs(&critsect_);
-  network_state_ = kNetworkUp;
+void ProbeController::Reset(int64_t at_time_ms) {
+  network_available_ = true;
   state_ = State::kInit;
   min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
   time_last_probing_initiated_ms_ = 0;
   estimated_bitrate_bps_ = 0;
   start_bitrate_bps_ = 0;
   max_bitrate_bps_ = 0;
-  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t now_ms = at_time_ms;
   last_bwe_drop_probing_time_ms_ = now_ms;
   alr_end_time_ms_.reset();
   mid_call_probing_waiting_for_result_ = false;
@@ -241,10 +246,8 @@
   bitrate_before_last_large_drop_bps_ = 0;
 }
 
-void ProbeController::Process() {
-  rtc::CritScope cs(&critsect_);
-
-  int64_t now_ms = clock_->TimeInMilliseconds();
+void ProbeController::Process(int64_t at_time_ms) {
+  int64_t now_ms = at_time_ms;
 
   if (now_ms - time_last_probing_initiated_ms_ >
       kMaxWaitingTimeForProbingResultMs) {
@@ -261,11 +264,9 @@
     return;
 
   // Probe bandwidth periodically when in ALR state.
-  rtc::Optional<int64_t> alr_start_time =
-      pacer_->GetApplicationLimitedRegionStartTime();
-  if (alr_start_time && estimated_bitrate_bps_ > 0) {
+  if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) {
     int64_t next_probe_time_ms =
-        std::max(*alr_start_time, time_last_probing_initiated_ms_) +
+        std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) +
         kAlrPeriodicProbingIntervalMs;
     if (now_ms >= next_probe_time_ms) {
       InitiateProbing(now_ms, {estimated_bitrate_bps_ * 2}, true);
@@ -285,7 +286,13 @@
       bitrate = max_probe_bitrate_bps;
       probe_further = false;
     }
-    pacer_->CreateProbeCluster(rtc::dchecked_cast<int>(bitrate));
+
+    ProbeClusterConfig config;
+    config.at_time = Timestamp::ms(now_ms);
+    config.target_data_rate = DataRate::bps(rtc::dchecked_cast<int>(bitrate));
+    config.target_duration = TimeDelta::ms(kMinProbeDurationMs);
+    config.target_probe_count = kMinProbePacketsSent;
+    observer_->OnProbeClusterConfig(config);
   }
   time_last_probing_initiated_ms_ = now_ms;
   if (probe_further) {
diff --git a/modules/congestion_controller/probe_controller.h b/modules/congestion_controller/probe_controller.h
index cd0e9b1..187a274 100644
--- a/modules/congestion_controller/probe_controller.h
+++ b/modules/congestion_controller/probe_controller.h
@@ -11,11 +11,12 @@
 #ifndef MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
 #define MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
 
+#include <stdint.h>
+
 #include <initializer_list>
 
-#include "common_types.h"  // NOLINT(build/include)
-#include "modules/pacing/paced_sender.h"
-#include "rtc_base/criticalsection.h"
+#include "api/optional.h"
+#include "modules/congestion_controller/network_control/include/network_control.h"
 
 namespace webrtc {
 
@@ -26,27 +27,30 @@
 // bitrate is adjusted by an application.
 class ProbeController {
  public:
-  ProbeController(PacedSender* pacer, const Clock* clock);
+  explicit ProbeController(NetworkControllerObserver* observer);
+  ~ProbeController();
 
   void SetBitrates(int64_t min_bitrate_bps,
                    int64_t start_bitrate_bps,
-                   int64_t max_bitrate_bps);
+                   int64_t max_bitrate_bps,
+                   int64_t at_time_ms);
 
-  void OnNetworkStateChanged(NetworkState state);
+  void OnNetworkAvailability(NetworkAvailability msg);
 
-  void SetEstimatedBitrate(int64_t bitrate_bps);
+  void SetEstimatedBitrate(int64_t bitrate_bps, int64_t at_time_ms);
 
   void EnablePeriodicAlrProbing(bool enable);
 
+  void SetAlrStartTimeMs(rtc::Optional<int64_t> alr_start_time);
   void SetAlrEndedTimeMs(int64_t alr_end_time);
 
-  void RequestProbe();
+  void RequestProbe(int64_t at_time_ms);
 
   // Resets the ProbeController to a state equivalent to as if it was just
   // created EXCEPT for |enable_periodic_alr_probing_|.
-  void Reset();
+  void Reset(int64_t at_time_ms);
 
-  void Process();
+  void Process(int64_t at_time_ms);
 
  private:
   enum class State {
@@ -58,33 +62,32 @@
     kProbingComplete,
   };
 
-  void InitiateExponentialProbing() RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_);
+  void InitiateExponentialProbing(int64_t at_time_ms);
   void InitiateProbing(int64_t now_ms,
                        std::initializer_list<int64_t> bitrates_to_probe,
-                       bool probe_further)
-      RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_);
+                       bool probe_further);
 
-  rtc::CriticalSection critsect_;
-  PacedSender* const pacer_;
-  const Clock* const clock_;
-  NetworkState network_state_ RTC_GUARDED_BY(critsect_);
-  State state_ RTC_GUARDED_BY(critsect_);
-  int64_t min_bitrate_to_probe_further_bps_ RTC_GUARDED_BY(critsect_);
-  int64_t time_last_probing_initiated_ms_ RTC_GUARDED_BY(critsect_);
-  int64_t estimated_bitrate_bps_ RTC_GUARDED_BY(critsect_);
-  int64_t start_bitrate_bps_ RTC_GUARDED_BY(critsect_);
-  int64_t max_bitrate_bps_ RTC_GUARDED_BY(critsect_);
-  int64_t last_bwe_drop_probing_time_ms_ RTC_GUARDED_BY(critsect_);
-  rtc::Optional<int64_t> alr_end_time_ms_ RTC_GUARDED_BY(critsect_);
-  bool enable_periodic_alr_probing_ RTC_GUARDED_BY(critsect_);
-  int64_t time_of_last_large_drop_ms_ RTC_GUARDED_BY(critsect_);
-  int64_t bitrate_before_last_large_drop_bps_ RTC_GUARDED_BY(critsect_);
+  NetworkControllerObserver* const observer_;
 
-  bool in_rapid_recovery_experiment_ RTC_GUARDED_BY(critsect_);
+  bool network_available_;
+  State state_;
+  int64_t min_bitrate_to_probe_further_bps_;
+  int64_t time_last_probing_initiated_ms_;
+  int64_t estimated_bitrate_bps_;
+  int64_t start_bitrate_bps_;
+  int64_t max_bitrate_bps_;
+  int64_t last_bwe_drop_probing_time_ms_;
+  rtc::Optional<int64_t> alr_start_time_ms_;
+  rtc::Optional<int64_t> alr_end_time_ms_;
+  bool enable_periodic_alr_probing_;
+  int64_t time_of_last_large_drop_ms_;
+  int64_t bitrate_before_last_large_drop_bps_;
+
+  bool in_rapid_recovery_experiment_;
   // For WebRTC.BWE.MidCallProbing.* metric.
-  bool mid_call_probing_waiting_for_result_ RTC_GUARDED_BY(&critsect_);
-  int64_t mid_call_probing_bitrate_bps_ RTC_GUARDED_BY(&critsect_);
-  int64_t mid_call_probing_succcess_threshold_ RTC_GUARDED_BY(&critsect_);
+  bool mid_call_probing_waiting_for_result_;
+  int64_t mid_call_probing_bitrate_bps_;
+  int64_t mid_call_probing_succcess_threshold_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
 };
diff --git a/modules/congestion_controller/probe_controller_unittest.cc b/modules/congestion_controller/probe_controller_unittest.cc
index 3477c87..ac889dc 100644
--- a/modules/congestion_controller/probe_controller_unittest.cc
+++ b/modules/congestion_controller/probe_controller_unittest.cc
@@ -9,8 +9,8 @@
  */
 #include <memory>
 
+#include "modules/congestion_controller/network_control/include/network_types.h"
 #include "modules/congestion_controller/probe_controller.h"
-#include "modules/pacing/mock/mock_paced_sender.h"
 #include "rtc_base/logging.h"
 #include "system_wrappers/include/clock.h"
 #include "test/gmock.h"
@@ -18,9 +18,13 @@
 
 using testing::_;
 using testing::AtLeast;
+using testing::Field;
+using testing::Matcher;
 using testing::NiceMock;
 using testing::Return;
 
+using webrtc::ProbeClusterConfig;
+
 namespace webrtc {
 namespace test {
 
@@ -36,234 +40,252 @@
 constexpr int kAlrEndedTimeoutMs = 3000;
 constexpr int kBitrateDropTimeoutMs = 5000;
 
+inline Matcher<ProbeClusterConfig> DataRateEqBps(int bps) {
+  return Field(&ProbeClusterConfig::target_data_rate, DataRate::bps(bps));
+}
+class MockNetworkControllerObserver : public NetworkControllerObserver {
+ public:
+  MOCK_METHOD1(OnCongestionWindow, void(CongestionWindow));
+  MOCK_METHOD1(OnPacerConfig, void(PacerConfig));
+  MOCK_METHOD1(OnProbeClusterConfig, void(ProbeClusterConfig));
+  MOCK_METHOD1(OnTargetTransferRate, void(TargetTransferRate));
+};
 }  // namespace
 
 class ProbeControllerTest : public ::testing::Test {
  protected:
   ProbeControllerTest() : clock_(100000000L) {
-    probe_controller_.reset(new ProbeController(&pacer_, &clock_));
+    probe_controller_.reset(new ProbeController(&cluster_handler_));
   }
   ~ProbeControllerTest() override {}
 
+  void SetNetworkAvailable(bool available) {
+    NetworkAvailability msg;
+    msg.at_time = Timestamp::ms(NowMs());
+    msg.network_available = available;
+    probe_controller_->OnNetworkAvailability(msg);
+  }
+
+  int64_t NowMs() { return clock_.TimeInMilliseconds(); }
+
   SimulatedClock clock_;
-  NiceMock<MockPacedSender> pacer_;
+  NiceMock<MockNetworkControllerObserver> cluster_handler_;
   std::unique_ptr<ProbeController> probe_controller_;
 };
 
 TEST_F(ProbeControllerTest, InitiatesProbingAtStart) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
 }
 
 TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
-  probe_controller_->OnNetworkStateChanged(kNetworkDown);
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
+  SetNetworkAvailable(false);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
 
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
-  probe_controller_->OnNetworkStateChanged(kNetworkUp);
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
+  SetNetworkAvailable(true);
 }
 
 TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
   // Long enough to time out exponential probing.
   clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
-  probe_controller_->SetEstimatedBitrate(kStartBitrateBps);
-  probe_controller_->Process();
+  probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
+  probe_controller_->Process(NowMs());
 
-  EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100));
+  EXPECT_CALL(cluster_handler_,
+              OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps + 100);
+                                 kMaxBitrateBps + 100, NowMs());
 }
 
 TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
   // Long enough to time out exponential probing.
   clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
-  probe_controller_->SetEstimatedBitrate(kStartBitrateBps);
-  probe_controller_->Process();
+  probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
+  probe_controller_->Process(NowMs());
 
-  probe_controller_->SetEstimatedBitrate(kMaxBitrateBps);
-  EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100));
+  probe_controller_->SetEstimatedBitrate(kMaxBitrateBps, NowMs());
+  EXPECT_CALL(cluster_handler_,
+              OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps + 100);
+                                 kMaxBitrateBps + 100, NowMs());
 }
 
 TEST_F(ProbeControllerTest, TestExponentialProbing) {
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
 
   // Repeated probe should only be sent when estimated bitrate climbs above
   // 0.7 * 6 * kStartBitrateBps = 1260.
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  probe_controller_->SetEstimatedBitrate(1000);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(1000, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 
-  EXPECT_CALL(pacer_, CreateProbeCluster(2 * 1800));
-  probe_controller_->SetEstimatedBitrate(1800);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(2 * 1800)));
+  probe_controller_->SetEstimatedBitrate(1800, NowMs());
 }
 
 TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) {
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
 
   // Advance far enough to cause a time out in waiting for probing result.
   clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
-  probe_controller_->Process();
+  probe_controller_->Process(NowMs());
 
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  probe_controller_->SetEstimatedBitrate(1800);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(1800, NowMs());
 }
 
 TEST_F(ProbeControllerTest, RequestProbeInAlr) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
-  EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(clock_.TimeInMilliseconds()));
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
+      .Times(1);
+  probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
   clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(250);
-  probe_controller_->RequestProbe();
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
+  probe_controller_->RequestProbe(NowMs());
 }
 
 TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
-  EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(rtc::nullopt));
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
+      .Times(1);
+  probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
   clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(250);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
   probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
   clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
-  probe_controller_->RequestProbe();
+  probe_controller_->RequestProbe(NowMs());
 }
 
 TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(rtc::nullopt));
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
   clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(250);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
   probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
   clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
-  probe_controller_->RequestProbe();
+  probe_controller_->RequestProbe(NowMs());
 }
 
 TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(clock_.TimeInMilliseconds()));
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
   clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(250);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
   clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
-  probe_controller_->RequestProbe();
+  probe_controller_->RequestProbe(NowMs());
 }
 
 TEST_F(ProbeControllerTest, PeriodicProbing) {
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->EnablePeriodicAlrProbing(true);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 
   int64_t start_time = clock_.TimeInMilliseconds();
 
   // Expect the controller to send a new probe after 5s has passed.
-  EXPECT_CALL(pacer_, CreateProbeCluster(1000)).Times(1);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(start_time));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(1000)))
+      .Times(1);
+  probe_controller_->SetAlrStartTimeMs(start_time);
   clock_.AdvanceTimeMilliseconds(5000);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 
   // The following probe should be sent at 10s into ALR.
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(start_time));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetAlrStartTimeMs(start_time);
   clock_.AdvanceTimeMilliseconds(4000);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(1);
-  EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(start_time));
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(1);
+  probe_controller_->SetAlrStartTimeMs(start_time);
   clock_.AdvanceTimeMilliseconds(1000);
-  probe_controller_->Process();
-  probe_controller_->SetEstimatedBitrate(500);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 }
 
 TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) {
-  testing::StrictMock<MockPacedSender> local_pacer;
-  probe_controller_.reset(new ProbeController(&local_pacer, &clock_));
+  NiceMock<MockNetworkControllerObserver> local_handler;
+  probe_controller_.reset(new ProbeController(&local_handler));
   int64_t alr_start_time = clock_.TimeInMilliseconds();
-  EXPECT_CALL(local_pacer, GetApplicationLimitedRegionStartTime())
-      .WillRepeatedly(Return(alr_start_time));
 
-  EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2);
+  probe_controller_->SetAlrStartTimeMs(alr_start_time);
+  EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->EnablePeriodicAlrProbing(true);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
-  probe_controller_->Reset();
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->Reset(NowMs());
 
   clock_.AdvanceTimeMilliseconds(10000);
-  probe_controller_->Process();
+  probe_controller_->Process(NowMs());
 
-  EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2);
+  EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
   probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
-                                 kMaxBitrateBps);
+                                 kMaxBitrateBps, NowMs());
 
   // Make sure we use |kStartBitrateBps| as the estimated bitrate
   // until SetEstimatedBitrate is called with an updated estimate.
   clock_.AdvanceTimeMilliseconds(10000);
-  EXPECT_CALL(local_pacer, CreateProbeCluster(kStartBitrateBps*2));
-  probe_controller_->Process();
+  EXPECT_CALL(local_handler,
+              OnProbeClusterConfig(DataRateEqBps(kStartBitrateBps * 2)));
+  probe_controller_->Process(NowMs());
 }
 
 TEST_F(ProbeControllerTest, TestExponentialProbingOverflow) {
   const int64_t kMbpsMultiplier = 1000000;
   probe_controller_->SetBitrates(kMinBitrateBps, 10 * kMbpsMultiplier,
-                                 100 * kMbpsMultiplier);
+                                 100 * kMbpsMultiplier, NowMs());
 
-  // Verify that probe bitrate is capped at the specified max bitrate
-  EXPECT_CALL(pacer_, CreateProbeCluster(100 * kMbpsMultiplier));
-  probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier);
-  testing::Mock::VerifyAndClearExpectations(&pacer_);
+  // Verify that probe bitrate is capped at the specified max bitrate.
+  EXPECT_CALL(cluster_handler_,
+              OnProbeClusterConfig(DataRateEqBps(100 * kMbpsMultiplier)));
+  probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
 
   // Verify that repeated probes aren't sent.
-  EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
-  probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier, NowMs());
 }
 
 }  // namespace test
diff --git a/modules/congestion_controller/send_side_congestion_controller.cc b/modules/congestion_controller/send_side_congestion_controller.cc
index 2a67578..fa81f24 100644
--- a/modules/congestion_controller/send_side_congestion_controller.cc
+++ b/modules/congestion_controller/send_side_congestion_controller.cc
@@ -11,141 +11,330 @@
 #include "modules/congestion_controller/include/send_side_congestion_controller.h"
 
 #include <algorithm>
-#include <cstdio>
+#include <functional>
 #include <memory>
 #include <vector>
-
-#include "modules/bitrate_controller/include/bitrate_controller.h"
-#include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
-#include "modules/congestion_controller/probe_controller.h"
-#include "modules/pacing/alr_detector.h"
+#include "modules/congestion_controller/include/goog_cc_factory.h"
+#include "modules/congestion_controller/network_control/include/network_types.h"
+#include "modules/congestion_controller/network_control/include/network_units.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
 #include "rtc_base/checks.h"
 #include "rtc_base/format_macros.h"
 #include "rtc_base/logging.h"
 #include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/numerics/safe_minmax.h"
 #include "rtc_base/ptr_util.h"
 #include "rtc_base/rate_limiter.h"
+#include "rtc_base/sequenced_task_checker.h"
 #include "rtc_base/socket.h"
 #include "rtc_base/timeutils.h"
 #include "system_wrappers/include/field_trial.h"
 #include "system_wrappers/include/runtime_enabled_features.h"
 
+using rtc::MakeUnique;
+
 namespace webrtc {
 namespace {
 
-const char kCwndExperiment[] = "WebRTC-CwndExperiment";
-const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
-const int64_t kDefaultAcceptedQueueMs = 250;
-
-bool CwndExperimentEnabled() {
-  std::string experiment_string =
-      webrtc::field_trial::FindFullName(kCwndExperiment);
-  // The experiment is enabled iff the field trial string begins with "Enabled".
-  return experiment_string.find("Enabled") == 0;
-}
-
-bool ReadCwndExperimentParameter(int64_t* accepted_queue_ms) {
-  RTC_DCHECK(accepted_queue_ms);
-  std::string experiment_string =
-      webrtc::field_trial::FindFullName(kCwndExperiment);
-  int parsed_values =
-      sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
-  if (parsed_values == 1) {
-    RTC_CHECK_GE(*accepted_queue_ms, 0)
-        << "Accepted must be greater than or equal to 0.";
-    return true;
-  }
-  return false;
-}
-
 static const int64_t kRetransmitWindowSizeMs = 500;
 
-// Makes sure that the bitrate and the min, max values are in valid range.
-static void ClampBitrates(int* bitrate_bps,
-                          int* min_bitrate_bps,
-                          int* max_bitrate_bps) {
-  // TODO(holmer): We should make sure the default bitrates are set to 10 kbps,
-  // and that we don't try to set the min bitrate to 0 from any applications.
-  // The congestion controller should allow a min bitrate of 0.
-  if (*min_bitrate_bps < congestion_controller::GetMinBitrateBps())
-    *min_bitrate_bps = congestion_controller::GetMinBitrateBps();
-  if (*max_bitrate_bps > 0)
-    *max_bitrate_bps = std::max(*min_bitrate_bps, *max_bitrate_bps);
-  if (*bitrate_bps > 0)
-    *bitrate_bps = std::max(*min_bitrate_bps, *bitrate_bps);
+const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
+
+bool IsPacerPushbackExperimentEnabled() {
+  return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) ||
+         (!webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) &&
+          webrtc::runtime_enabled_features::IsFeatureEnabled(
+              webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
 }
 
-std::vector<webrtc::PacketFeedback> ReceivedPacketFeedbackVector(
-    const std::vector<webrtc::PacketFeedback>& input) {
-  std::vector<PacketFeedback> received_packet_feedback_vector;
-  auto is_received = [](const webrtc::PacketFeedback& packet_feedback) {
-    return packet_feedback.arrival_time_ms !=
-           webrtc::PacketFeedback::kNotReceived;
-  };
-  std::copy_if(input.begin(), input.end(),
-               std::back_inserter(received_packet_feedback_vector),
-               is_received);
-  return received_packet_feedback_vector;
+NetworkControllerFactoryInterface::uptr ControllerFactory(
+    RtcEventLog* event_log) {
+  return rtc::MakeUnique<GoogCcNetworkControllerFactory>(event_log);
 }
 
-void SortPacketFeedbackVector(
-    std::vector<webrtc::PacketFeedback>* const input) {
-  RTC_DCHECK(input);
+void SortPacketFeedbackVector(std::vector<webrtc::PacketFeedback>* input) {
   std::sort(input->begin(), input->end(), PacketFeedbackComparator());
 }
 
-bool IsPacerPushbackExperimentEnabled() {
-  return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) || (
-      !webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) &&
-      webrtc::runtime_enabled_features::IsFeatureEnabled(
-          webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
+PacketResult NetworkPacketFeedbackFromRtpPacketFeedback(
+    const webrtc::PacketFeedback& pf) {
+  PacketResult feedback;
+  if (pf.arrival_time_ms == webrtc::PacketFeedback::kNotReceived)
+    feedback.receive_time = Timestamp::Infinity();
+  else
+    feedback.receive_time = Timestamp::ms(pf.arrival_time_ms);
+  if (pf.send_time_ms != webrtc::PacketFeedback::kNoSendTime) {
+    feedback.sent_packet = SentPacket();
+    feedback.sent_packet->send_time = Timestamp::ms(pf.send_time_ms);
+    feedback.sent_packet->size = DataSize::bytes(pf.payload_size);
+    feedback.sent_packet->pacing_info = pf.pacing_info;
+  }
+  return feedback;
 }
 
+std::vector<PacketResult> PacketResultsFromRtpFeedbackVector(
+    const std::vector<PacketFeedback>& feedback_vector) {
+  RTC_DCHECK(std::is_sorted(feedback_vector.begin(), feedback_vector.end(),
+                            PacketFeedbackComparator()));
+
+  std::vector<PacketResult> packet_feedbacks;
+  packet_feedbacks.reserve(feedback_vector.size());
+  for (const PacketFeedback& rtp_feedback : feedback_vector) {
+    auto feedback = NetworkPacketFeedbackFromRtpPacketFeedback(rtp_feedback);
+    packet_feedbacks.push_back(feedback);
+  }
+  return packet_feedbacks;
+}
+
+TargetRateConstraints ConvertConstraints(int min_bitrate_bps,
+                                         int max_bitrate_bps,
+                                         int start_bitrate_bps,
+                                         const Clock* clock) {
+  TargetRateConstraints msg;
+  msg.at_time = Timestamp::ms(clock->TimeInMilliseconds());
+  msg.min_data_rate =
+      min_bitrate_bps >= 0 ? DataRate::bps(min_bitrate_bps) : DataRate::Zero();
+  msg.starting_rate = start_bitrate_bps > 0 ? DataRate::bps(start_bitrate_bps)
+                                            : DataRate::kNotInitialized;
+  msg.max_data_rate = max_bitrate_bps > 0 ? DataRate::bps(max_bitrate_bps)
+                                          : DataRate::Infinity();
+  return msg;
+}
 }  // namespace
 
+namespace send_side_cc_internal {
+class ControlHandler : public NetworkControllerObserver {
+ public:
+  ControlHandler(PacerController* pacer_controller, const Clock* clock);
+
+  void OnCongestionWindow(CongestionWindow window) override;
+  void OnPacerConfig(PacerConfig config) override;
+  void OnProbeClusterConfig(ProbeClusterConfig config) override;
+  void OnTargetTransferRate(TargetTransferRate target_rate) override;
+
+  void OnNetworkAvailability(NetworkAvailability msg);
+  void OnPacerQueueUpdate(PacerQueueUpdate msg);
+
+  void RegisterNetworkObserver(
+      SendSideCongestionController::Observer* observer);
+  void DeRegisterNetworkObserver(
+      SendSideCongestionController::Observer* observer);
+
+  rtc::Optional<TargetTransferRate> last_transfer_rate();
+  bool pacer_configured();
+  RateLimiter* retransmission_rate_limiter();
+
+ private:
+  void OnNetworkInvalidation();
+  bool GetNetworkParameters(int32_t* estimated_bitrate_bps,
+                            uint8_t* fraction_loss,
+                            int64_t* rtt_ms);
+  bool IsSendQueueFull() const;
+  bool HasNetworkParametersToReportChanged(int64_t bitrate_bps,
+                                           uint8_t fraction_loss,
+                                           int64_t rtt);
+  PacerController* pacer_controller_;
+  RateLimiter retransmission_rate_limiter_;
+
+  rtc::CriticalSection state_lock_;
+  rtc::Optional<TargetTransferRate> last_target_rate_
+      RTC_GUARDED_BY(state_lock_);
+  bool pacer_configured_ RTC_GUARDED_BY(state_lock_) = false;
+
+  SendSideCongestionController::Observer* observer_ = nullptr;
+  rtc::Optional<TargetTransferRate> current_target_rate_msg_;
+  bool network_available_ = true;
+  int64_t last_reported_target_bitrate_bps_ = 0;
+  uint8_t last_reported_fraction_loss_ = 0;
+  int64_t last_reported_rtt_ms_ = 0;
+  const bool pacer_pushback_experiment_ = false;
+  int64_t pacer_expected_queue_ms_ = 0;
+  float encoding_rate_ratio_ = 1.0;
+
+  rtc::SequencedTaskChecker sequenced_checker_;
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ControlHandler);
+};
+
+ControlHandler::ControlHandler(PacerController* pacer_controller,
+                               const Clock* clock)
+    : pacer_controller_(pacer_controller),
+      retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs),
+      pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
+  sequenced_checker_.Detach();
+}
+
+void ControlHandler::OnCongestionWindow(CongestionWindow window) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  pacer_controller_->OnCongestionWindow(window);
+}
+
+void ControlHandler::OnPacerConfig(PacerConfig config) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  pacer_controller_->OnPacerConfig(config);
+  rtc::CritScope cs(&state_lock_);
+  pacer_configured_ = true;
+}
+
+void ControlHandler::OnProbeClusterConfig(ProbeClusterConfig config) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  pacer_controller_->OnProbeClusterConfig(config);
+}
+
+void ControlHandler::OnTargetTransferRate(TargetTransferRate target_rate) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  retransmission_rate_limiter_.SetMaxRate(
+      target_rate.network_estimate.bandwidth.bps());
+
+  current_target_rate_msg_ = target_rate;
+  OnNetworkInvalidation();
+  rtc::CritScope cs(&state_lock_);
+  last_target_rate_ = target_rate;
+}
+
+void ControlHandler::OnNetworkAvailability(NetworkAvailability msg) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  network_available_ = msg.network_available;
+  OnNetworkInvalidation();
+}
+
+void ControlHandler::OnPacerQueueUpdate(PacerQueueUpdate msg) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  pacer_expected_queue_ms_ = msg.expected_queue_time.ms();
+  OnNetworkInvalidation();
+}
+
+void ControlHandler::RegisterNetworkObserver(
+    SendSideCongestionController::Observer* observer) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  RTC_DCHECK(observer_ == nullptr);
+  observer_ = observer;
+}
+
+void ControlHandler::DeRegisterNetworkObserver(
+    SendSideCongestionController::Observer* observer) {
+  RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
+  RTC_DCHECK_EQ(observer_, observer);
+  observer_ = nullptr;
+}
+
+void ControlHandler::OnNetworkInvalidation() {
+  if (!current_target_rate_msg_.has_value())
+    return;
+
+  uint32_t target_bitrate_bps = current_target_rate_msg_->target_rate.bps();
+  int64_t rtt_ms =
+      current_target_rate_msg_->network_estimate.round_trip_time.ms();
+  float loss_rate_ratio =
+      current_target_rate_msg_->network_estimate.loss_rate_ratio;
+
+  int loss_ratio_255 = loss_rate_ratio * 255;
+  uint8_t fraction_loss =
+      rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
+
+  int64_t probing_interval_ms =
+      current_target_rate_msg_->network_estimate.bwe_period.ms();
+
+  if (!network_available_) {
+    target_bitrate_bps = 0;
+  } else if (!pacer_pushback_experiment_) {
+    target_bitrate_bps = IsSendQueueFull() ? 0 : target_bitrate_bps;
+  } else {
+    int64_t queue_length_ms = pacer_expected_queue_ms_;
+
+    if (queue_length_ms == 0) {
+      encoding_rate_ratio_ = 1.0;
+    } else if (queue_length_ms > 50) {
+      float encoding_ratio = 1.0 - queue_length_ms / 1000.0;
+      encoding_rate_ratio_ = std::min(encoding_rate_ratio_, encoding_ratio);
+      encoding_rate_ratio_ = std::max(encoding_rate_ratio_, 0.0f);
+    }
+
+    target_bitrate_bps *= encoding_rate_ratio_;
+    target_bitrate_bps = target_bitrate_bps < 50000 ? 0 : target_bitrate_bps;
+  }
+  if (HasNetworkParametersToReportChanged(target_bitrate_bps, fraction_loss,
+                                          rtt_ms)) {
+    if (observer_) {
+      observer_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt_ms,
+                                  probing_interval_ms);
+    }
+  }
+}
+bool ControlHandler::HasNetworkParametersToReportChanged(
+    int64_t target_bitrate_bps,
+    uint8_t fraction_loss,
+    int64_t rtt_ms) {
+  bool changed = last_reported_target_bitrate_bps_ != target_bitrate_bps ||
+                 (target_bitrate_bps > 0 &&
+                  (last_reported_fraction_loss_ != fraction_loss ||
+                   last_reported_rtt_ms_ != rtt_ms));
+  if (changed &&
+      (last_reported_target_bitrate_bps_ == 0 || target_bitrate_bps == 0)) {
+    RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: "
+                     << target_bitrate_bps << " bps.";
+  }
+  last_reported_target_bitrate_bps_ = target_bitrate_bps;
+  last_reported_fraction_loss_ = fraction_loss;
+  last_reported_rtt_ms_ = rtt_ms;
+  return changed;
+}
+
+bool ControlHandler::IsSendQueueFull() const {
+  return pacer_expected_queue_ms_ > PacedSender::kMaxQueueLengthMs;
+}
+
+rtc::Optional<TargetTransferRate> ControlHandler::last_transfer_rate() {
+  rtc::CritScope cs(&state_lock_);
+  return last_target_rate_;
+}
+
+bool ControlHandler::pacer_configured() {
+  rtc::CritScope cs(&state_lock_);
+  return pacer_configured_;
+}
+
+RateLimiter* ControlHandler::retransmission_rate_limiter() {
+  return &retransmission_rate_limiter_;
+}
+}  // namespace send_side_cc_internal
+
 SendSideCongestionController::SendSideCongestionController(
     const Clock* clock,
     Observer* observer,
     RtcEventLog* event_log,
     PacedSender* pacer)
+    : SendSideCongestionController(clock,
+                                   event_log,
+                                   pacer,
+                                   ControllerFactory(event_log)) {
+  if (observer != nullptr)
+    RegisterNetworkObserver(observer);
+}
+
+SendSideCongestionController::SendSideCongestionController(
+    const Clock* clock,
+    RtcEventLog* event_log,
+    PacedSender* pacer,
+    NetworkControllerFactoryInterface::uptr controller_factory)
     : clock_(clock),
-      observer_(observer),
-      event_log_(event_log),
       pacer_(pacer),
-      bitrate_controller_(
-          BitrateController::CreateBitrateController(clock_, event_log)),
-      acknowledged_bitrate_estimator_(
-          rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
-      probe_controller_(new ProbeController(pacer_, clock_)),
-      retransmission_rate_limiter_(
-          new RateLimiter(clock, kRetransmitWindowSizeMs)),
       transport_feedback_adapter_(clock_),
-      last_reported_bitrate_bps_(0),
-      last_reported_fraction_loss_(0),
-      last_reported_rtt_(0),
-      network_state_(kNetworkUp),
-      pause_pacer_(false),
-      pacer_paused_(false),
-      min_bitrate_bps_(congestion_controller::GetMinBitrateBps()),
-      delay_based_bwe_(new DelayBasedBwe(event_log_, clock_)),
-      in_cwnd_experiment_(CwndExperimentEnabled()),
-      accepted_queue_ms_(kDefaultAcceptedQueueMs),
-      was_in_alr_(false),
+      pacer_controller_(MakeUnique<PacerController>(pacer_)),
+      control_handler(MakeUnique<send_side_cc_internal::ControlHandler>(
+          pacer_controller_.get(),
+          clock_)),
+      controller_(controller_factory->Create(control_handler.get())),
+      process_interval_(controller_factory->GetProcessInterval()),
       send_side_bwe_with_overhead_(
           webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
       transport_overhead_bytes_per_packet_(0),
-      pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
-  delay_based_bwe_->SetMinBitrate(min_bitrate_bps_);
-  if (in_cwnd_experiment_ &&
-      !ReadCwndExperimentParameter(&accepted_queue_ms_)) {
-    RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
-                           "from field trial string. Experiment disabled.";
-    in_cwnd_experiment_ = false;
-  }
-}
+      network_available_(true),
+      task_queue_(MakeUnique<rtc::TaskQueue>("SendSideCCQueue")) {}
 
-SendSideCongestionController::~SendSideCongestionController() {}
+SendSideCongestionController::~SendSideCongestionController() {
+  // Must be destructed before any objects used by calls on the task queue.
+  task_queue_.reset();
+}
 
 void SendSideCongestionController::RegisterPacketFeedbackObserver(
     PacketFeedbackObserver* observer) {
@@ -158,92 +347,84 @@
 }
 
 void SendSideCongestionController::RegisterNetworkObserver(Observer* observer) {
-  rtc::CritScope cs(&observer_lock_);
-  RTC_DCHECK(observer_ == nullptr);
-  observer_ = observer;
+  WaitOnTask([this, observer]() {
+    control_handler->RegisterNetworkObserver(observer);
+  });
 }
 
 void SendSideCongestionController::DeRegisterNetworkObserver(
     Observer* observer) {
-  rtc::CritScope cs(&observer_lock_);
-  RTC_DCHECK_EQ(observer_, observer);
-  observer_ = nullptr;
+  WaitOnTask([this, observer]() {
+    control_handler->DeRegisterNetworkObserver(observer);
+  });
 }
 
 void SendSideCongestionController::SetBweBitrates(int min_bitrate_bps,
                                                   int start_bitrate_bps,
                                                   int max_bitrate_bps) {
-  ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
-  bitrate_controller_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
-                                   max_bitrate_bps);
-
-  probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
-                                 max_bitrate_bps);
-
-  {
-    rtc::CritScope cs(&bwe_lock_);
-    if (start_bitrate_bps > 0)
-      delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
-    min_bitrate_bps_ = min_bitrate_bps;
-    delay_based_bwe_->SetMinBitrate(min_bitrate_bps_);
-  }
-  MaybeTriggerOnNetworkChanged();
+  TargetRateConstraints msg = ConvertConstraints(
+      min_bitrate_bps, max_bitrate_bps, start_bitrate_bps, clock_);
+  WaitOnTask([this, msg]() { controller_->OnTargetRateConstraints(msg); });
 }
 
 // TODO(holmer): Split this up and use SetBweBitrates in combination with
 // OnNetworkRouteChanged.
 void SendSideCongestionController::OnNetworkRouteChanged(
     const rtc::NetworkRoute& network_route,
-    int bitrate_bps,
+    int start_bitrate_bps,
     int min_bitrate_bps,
     int max_bitrate_bps) {
-  ClampBitrates(&bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
-  // TODO(honghaiz): Recreate this object once the bitrate controller is
-  // no longer exposed outside SendSideCongestionController.
-  bitrate_controller_->ResetBitrates(bitrate_bps, min_bitrate_bps,
-                                     max_bitrate_bps);
-
   transport_feedback_adapter_.SetNetworkIds(network_route.local_network_id,
                                             network_route.remote_network_id);
-  {
-    rtc::CritScope cs(&bwe_lock_);
-    min_bitrate_bps_ = min_bitrate_bps;
-    delay_based_bwe_.reset(new DelayBasedBwe(event_log_, clock_));
-    acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
-    delay_based_bwe_->SetStartBitrate(bitrate_bps);
-    delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
-  }
 
-  probe_controller_->Reset();
-  probe_controller_->SetBitrates(min_bitrate_bps, bitrate_bps, max_bitrate_bps);
-
-  MaybeTriggerOnNetworkChanged();
-}
-
-BitrateController* SendSideCongestionController::GetBitrateController() const {
-  return bitrate_controller_.get();
+  NetworkRouteChange msg;
+  msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
+  msg.constraints = ConvertConstraints(min_bitrate_bps, max_bitrate_bps,
+                                       start_bitrate_bps, clock_);
+  WaitOnTask([this, msg]() {
+    controller_->OnNetworkRouteChange(msg);
+    pacer_controller_->OnNetworkRouteChange(msg);
+  });
 }
 
 bool SendSideCongestionController::AvailableBandwidth(
     uint32_t* bandwidth) const {
-  return bitrate_controller_->AvailableBandwidth(bandwidth);
+  // TODO(srte): Remove this interface and push information about bandwidth
+  // estimation to users of this class, thereby reducing synchronous calls.
+  if (control_handler->last_transfer_rate().has_value()) {
+    *bandwidth =
+        control_handler->last_transfer_rate()->network_estimate.bandwidth.bps();
+    return true;
+  }
+  return false;
 }
 
-RtcpBandwidthObserver* SendSideCongestionController::GetBandwidthObserver()
-    const {
-  return bitrate_controller_.get();
+RtcpBandwidthObserver* SendSideCongestionController::GetBandwidthObserver() {
+  return this;
 }
 
 RateLimiter* SendSideCongestionController::GetRetransmissionRateLimiter() {
-  return retransmission_rate_limiter_.get();
+  return control_handler->retransmission_rate_limiter();
 }
 
 void SendSideCongestionController::EnablePeriodicAlrProbing(bool enable) {
-  probe_controller_->EnablePeriodicAlrProbing(enable);
+  WaitOnTask([this, enable]() {
+    streams_config_.requests_alr_probing = enable;
+    UpdateStreamsConfig();
+  });
+}
+
+void SendSideCongestionController::UpdateStreamsConfig() {
+  RTC_DCHECK(task_queue_->IsCurrent());
+  streams_config_.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
+  controller_->OnStreamsConfig(streams_config_);
 }
 
 int64_t SendSideCongestionController::GetPacerQueuingDelayMs() const {
-  return IsNetworkDown() ? 0 : pacer_->QueueInMs();
+  // TODO(srte): This should be made less synchronous. Now it grabs a lock in
+  // the pacer just for stats usage. Some kind of push interface might make
+  // sense.
+  return network_available_ ? pacer_->QueueInMs() : 0;
 }
 
 int64_t SendSideCongestionController::GetFirstPacketTimeMs() const {
@@ -258,18 +439,19 @@
 void SendSideCongestionController::SignalNetworkState(NetworkState state) {
   RTC_LOG(LS_INFO) << "SignalNetworkState "
                    << (state == kNetworkUp ? "Up" : "Down");
-  {
-    rtc::CritScope cs(&network_state_lock_);
-    pause_pacer_ = state == kNetworkDown;
-    network_state_ = state;
-  }
-  probe_controller_->OnNetworkStateChanged(state);
-  MaybeTriggerOnNetworkChanged();
+  NetworkAvailability msg;
+  msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
+  msg.network_available = state == kNetworkUp;
+  network_available_ = msg.network_available;
+  WaitOnTask([this, msg]() {
+    controller_->OnNetworkAvailability(msg);
+    pacer_controller_->OnNetworkAvailability(msg);
+    control_handler->OnNetworkAvailability(msg);
+  });
 }
 
 void SendSideCongestionController::SetTransportOverhead(
     size_t transport_overhead_bytes_per_packet) {
-  rtc::CritScope cs(&bwe_lock_);
   transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
 }
 
@@ -281,38 +463,52 @@
     return;
   transport_feedback_adapter_.OnSentPacket(sent_packet.packet_id,
                                            sent_packet.send_time_ms);
-  if (in_cwnd_experiment_)
-    LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
+  MaybeUpdateOutstandingData();
+  auto packet = transport_feedback_adapter_.GetPacket(sent_packet.packet_id);
+  if (packet.has_value()) {
+    SentPacket msg;
+    msg.size = DataSize::bytes(packet->payload_size);
+    msg.send_time = Timestamp::ms(packet->send_time_ms);
+    task_queue_->PostTask([this, msg]() { controller_->OnSentPacket(msg); });
+  }
 }
 
 void SendSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms,
                                                int64_t max_rtt_ms) {
-  rtc::CritScope cs(&bwe_lock_);
-  delay_based_bwe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms);
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  RoundTripTimeUpdate report;
+  report.receive_time = Timestamp::ms(now_ms);
+  report.round_trip_time = TimeDelta::ms(avg_rtt_ms);
+  report.smoothed = true;
+  task_queue_->PostTask(
+      [this, report]() { controller_->OnRoundTripTimeUpdate(report); });
 }
 
 int64_t SendSideCongestionController::TimeUntilNextProcess() {
-  return bitrate_controller_->TimeUntilNextProcess();
+  const int kMaxProcessInterval = 60 * 1000;
+  if (process_interval_.IsInfinite())
+    return kMaxProcessInterval;
+  int64_t next_process_ms = last_process_update_ms_ + process_interval_.ms();
+  int64_t time_until_next_process =
+      next_process_ms - clock_->TimeInMilliseconds();
+  return std::max<int64_t>(time_until_next_process, 0);
 }
 
 void SendSideCongestionController::Process() {
-  bool pause_pacer;
-  // TODO(holmer): Once this class is running on a task queue we should
-  // replace this with a task instead.
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  last_process_update_ms_ = now_ms;
   {
-    rtc::CritScope lock(&network_state_lock_);
-    pause_pacer = pause_pacer_;
+    ProcessInterval msg;
+    msg.at_time = Timestamp::ms(now_ms);
+    task_queue_->PostTask(
+        [this, msg]() { controller_->OnProcessInterval(msg); });
   }
-  if (pause_pacer && !pacer_paused_) {
-    pacer_->Pause();
-    pacer_paused_ = true;
-  } else if (!pause_pacer && pacer_paused_) {
-    pacer_->Resume();
-    pacer_paused_ = false;
+  if (control_handler->pacer_configured()) {
+    PacerQueueUpdate msg;
+    msg.expected_queue_time = TimeDelta::ms(pacer_->ExpectedQueueTimeMs());
+    task_queue_->PostTask(
+        [this, msg]() { control_handler->OnPacerQueueUpdate(msg); });
   }
-  bitrate_controller_->Process();
-  probe_controller_->Process();
-  MaybeTriggerOnNetworkChanged();
 }
 
 void SendSideCongestionController::AddPacket(
@@ -321,7 +517,6 @@
     size_t length,
     const PacedPacketInfo& pacing_info) {
   if (send_side_bwe_with_overhead_) {
-    rtc::CritScope cs(&bwe_lock_);
     length += transport_overhead_bytes_per_packet_;
   }
   transport_feedback_adapter_.AddPacket(ssrc, sequence_number, length,
@@ -331,61 +526,35 @@
 void SendSideCongestionController::OnTransportFeedback(
     const rtcp::TransportFeedback& feedback) {
   RTC_DCHECK_RUNS_SERIALIZED(&worker_race_);
+  int64_t feedback_time_ms = clock_->TimeInMilliseconds();
+
+  DataSize prior_in_flight =
+      DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
   transport_feedback_adapter_.OnTransportFeedback(feedback);
-  std::vector<PacketFeedback> feedback_vector = ReceivedPacketFeedbackVector(
-      transport_feedback_adapter_.GetTransportFeedbackVector());
+  MaybeUpdateOutstandingData();
+
+  std::vector<PacketFeedback> feedback_vector =
+      transport_feedback_adapter_.GetTransportFeedbackVector();
   SortPacketFeedbackVector(&feedback_vector);
 
-  bool currently_in_alr =
-      pacer_->GetApplicationLimitedRegionStartTime().has_value();
-  if (was_in_alr_ && !currently_in_alr) {
-    int64_t now_ms = rtc::TimeMillis();
-    acknowledged_bitrate_estimator_->SetAlrEndedTimeMs(now_ms);
-    probe_controller_->SetAlrEndedTimeMs(now_ms);
+  if (!feedback_vector.empty()) {
+    TransportPacketsFeedback msg;
+    msg.packet_feedbacks = PacketResultsFromRtpFeedbackVector(feedback_vector);
+    msg.feedback_time = Timestamp::ms(feedback_time_ms);
+    msg.prior_in_flight = prior_in_flight;
+    msg.data_in_flight =
+        DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
+    task_queue_->PostTask(
+        [this, msg]() { controller_->OnTransportPacketsFeedback(msg); });
   }
-  was_in_alr_ = currently_in_alr;
-
-  acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
-      feedback_vector);
-  DelayBasedBwe::Result result;
-  {
-    rtc::CritScope cs(&bwe_lock_);
-    result = delay_based_bwe_->IncomingPacketFeedbackVector(
-        feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps());
-  }
-  if (result.updated) {
-    bitrate_controller_->OnDelayBasedBweResult(result);
-    // Update the estimate in the ProbeController, in case we want to probe.
-    MaybeTriggerOnNetworkChanged();
-  }
-  if (result.recovered_from_overuse)
-    probe_controller_->RequestProbe();
-  if (in_cwnd_experiment_)
-    LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
 }
 
-void SendSideCongestionController::LimitOutstandingBytes(
-    size_t num_outstanding_bytes) {
-  RTC_DCHECK(in_cwnd_experiment_);
-  rtc::CritScope lock(&network_state_lock_);
-  rtc::Optional<int64_t> min_rtt_ms =
-      transport_feedback_adapter_.GetMinFeedbackLoopRtt();
-  // No valid RTT. Could be because send-side BWE isn't used, in which case
-  // we don't try to limit the outstanding packets.
-  if (!min_rtt_ms)
-    return;
-  const size_t kMinCwndBytes = 2 * 1500;
-  size_t max_outstanding_bytes =
-      std::max<size_t>((*min_rtt_ms + accepted_queue_ms_) *
-                           last_reported_bitrate_bps_ / 1000 / 8,
-                       kMinCwndBytes);
-  RTC_LOG(LS_INFO) << clock_->TimeInMilliseconds()
-                   << " Outstanding bytes: " << num_outstanding_bytes
-                   << " pacer queue: " << pacer_->QueueInMs()
-                   << " max outstanding: " << max_outstanding_bytes;
-  RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_rtt_ms
-                   << " Bitrate: " << last_reported_bitrate_bps_;
-  pause_pacer_ = num_outstanding_bytes > max_outstanding_bytes;
+void SendSideCongestionController::MaybeUpdateOutstandingData() {
+  OutstandingData msg;
+  msg.in_flight_data =
+      DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
+  task_queue_->PostTask(
+      [this, msg]() { pacer_controller_->OnOutstandingData(msg); });
 }
 
 std::vector<PacketFeedback>
@@ -394,81 +563,99 @@
   return transport_feedback_adapter_.GetTransportFeedbackVector();
 }
 
-void SendSideCongestionController::MaybeTriggerOnNetworkChanged() {
-  uint32_t bitrate_bps;
-  uint8_t fraction_loss;
-  int64_t rtt;
-  bool estimate_changed = bitrate_controller_->GetNetworkParameters(
-      &bitrate_bps, &fraction_loss, &rtt);
-  if (estimate_changed) {
-    pacer_->SetEstimatedBitrate(bitrate_bps);
-    probe_controller_->SetEstimatedBitrate(bitrate_bps);
-    retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
-  }
+void SendSideCongestionController::WaitOnTasks() {
+  rtc::Event event(false, false);
+  task_queue_->PostTask([&event]() { event.Set(); });
+  event.Wait(rtc::Event::kForever);
+}
 
-  if (!pacer_pushback_experiment_) {
-    bitrate_bps = IsNetworkDown() || IsSendQueueFull() ? 0 : bitrate_bps;
-  } else {
-    if (IsNetworkDown()) {
-      bitrate_bps = 0;
-    } else {
-      int64_t queue_length_ms = pacer_->ExpectedQueueTimeMs();
+void SendSideCongestionController::WaitOnTask(std::function<void()> closure) {
+  rtc::Event done(false, false);
+  task_queue_->PostTask(rtc::NewClosure(closure, [&done] { done.Set(); }));
+  done.Wait(rtc::Event::kForever);
+}
 
-      if (queue_length_ms == 0) {
-        encoding_rate_ = 1.0;
-      } else if (queue_length_ms > 50) {
-        float encoding_rate = 1.0 - queue_length_ms / 1000.0;
-        encoding_rate_ = std::min(encoding_rate_, encoding_rate);
-        encoding_rate_ = std::max(encoding_rate_, 0.0f);
-      }
+void SendSideCongestionController::SetSendBitrateLimits(
+    int64_t min_send_bitrate_bps,
+    int64_t max_padding_bitrate_bps) {
+  WaitOnTask([this, min_send_bitrate_bps, max_padding_bitrate_bps]() {
+    streams_config_.min_pacing_rate = DataRate::bps(min_send_bitrate_bps);
+    streams_config_.max_padding_rate = DataRate::bps(max_padding_bitrate_bps);
+    UpdateStreamsConfig();
+  });
+}
 
-      bitrate_bps *= encoding_rate_;
-      bitrate_bps = bitrate_bps < 50000 ? 0 : bitrate_bps;
+void SendSideCongestionController::SetPacingFactor(float pacing_factor) {
+  WaitOnTask([this, pacing_factor]() {
+    streams_config_.pacing_factor = pacing_factor;
+    UpdateStreamsConfig();
+  });
+}
+
+void SendSideCongestionController::OnReceivedEstimatedBitrate(
+    uint32_t bitrate) {
+  RemoteBitrateReport msg;
+  msg.receive_time = Timestamp::ms(clock_->TimeInMilliseconds());
+  msg.bandwidth = DataRate::bps(bitrate);
+  task_queue_->PostTask(
+      [this, msg]() { controller_->OnRemoteBitrateReport(msg); });
+}
+
+void SendSideCongestionController::OnReceivedRtcpReceiverReport(
+    const webrtc::ReportBlockList& report_blocks,
+    int64_t rtt_ms,
+    int64_t now_ms) {
+  OnReceivedRtcpReceiverReportBlocks(report_blocks, now_ms);
+
+  RoundTripTimeUpdate report;
+  report.receive_time = Timestamp::ms(now_ms);
+  report.round_trip_time = TimeDelta::ms(rtt_ms);
+  report.smoothed = false;
+  task_queue_->PostTask(
+      [this, report]() { controller_->OnRoundTripTimeUpdate(report); });
+}
+
+void SendSideCongestionController::OnReceivedRtcpReceiverReportBlocks(
+    const ReportBlockList& report_blocks,
+    int64_t now_ms) {
+  if (report_blocks.empty())
+    return;
+
+  int total_packets_lost_delta = 0;
+  int total_packets_delta = 0;
+
+  // Compute the packet loss from all report blocks.
+  for (const RTCPReportBlock& report_block : report_blocks) {
+    auto it = last_report_blocks_.find(report_block.source_ssrc);
+    if (it != last_report_blocks_.end()) {
+      auto number_of_packets = report_block.extended_highest_sequence_number -
+                               it->second.extended_highest_sequence_number;
+      total_packets_delta += number_of_packets;
+      auto lost_delta = report_block.packets_lost - it->second.packets_lost;
+      total_packets_lost_delta += lost_delta;
     }
+    last_report_blocks_[report_block.source_ssrc] = report_block;
   }
+  // Can only compute delta if there has been previous blocks to compare to. If
+  // not, total_packets_delta will be unchanged and there's nothing more to do.
+  if (!total_packets_delta)
+    return;
+  int packets_received_delta = total_packets_delta - total_packets_lost_delta;
+  // To detect lost packets, at least one packet has to be received. This check
+  // is needed to avoid bandwith detection update in
+  // VideoSendStreamTest.SuspendBelowMinBitrate
 
-  if (HasNetworkParametersToReportChanged(bitrate_bps, fraction_loss, rtt)) {
-    int64_t probing_interval_ms;
-    {
-      rtc::CritScope cs(&bwe_lock_);
-      probing_interval_ms = delay_based_bwe_->GetExpectedBwePeriodMs();
-    }
-    {
-      rtc::CritScope cs(&observer_lock_);
-      if (observer_) {
-        observer_->OnNetworkChanged(bitrate_bps, fraction_loss, rtt,
-                                    probing_interval_ms);
-      }
-    }
-  }
+  if (packets_received_delta < 1)
+    return;
+  Timestamp now = Timestamp::ms(now_ms);
+  TransportLossReport msg;
+  msg.packets_lost_delta = total_packets_lost_delta;
+  msg.packets_received_delta = packets_received_delta;
+  msg.receive_time = now;
+  msg.start_time = last_report_block_time_;
+  msg.end_time = now;
+  task_queue_->PostTask(
+      [this, msg]() { controller_->OnTransportLossReport(msg); });
+  last_report_block_time_ = now;
 }
-
-bool SendSideCongestionController::HasNetworkParametersToReportChanged(
-    uint32_t bitrate_bps,
-    uint8_t fraction_loss,
-    int64_t rtt) {
-  rtc::CritScope cs(&network_state_lock_);
-  bool changed =
-      last_reported_bitrate_bps_ != bitrate_bps ||
-      (bitrate_bps > 0 && (last_reported_fraction_loss_ != fraction_loss ||
-                           last_reported_rtt_ != rtt));
-  if (changed && (last_reported_bitrate_bps_ == 0 || bitrate_bps == 0)) {
-    RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: " << bitrate_bps
-                     << " bps.";
-  }
-  last_reported_bitrate_bps_ = bitrate_bps;
-  last_reported_fraction_loss_ = fraction_loss;
-  last_reported_rtt_ = rtt;
-  return changed;
-}
-
-bool SendSideCongestionController::IsSendQueueFull() const {
-  return pacer_->ExpectedQueueTimeMs() > PacedSender::kMaxQueueLengthMs;
-}
-
-bool SendSideCongestionController::IsNetworkDown() const {
-  rtc::CritScope cs(&network_state_lock_);
-  return network_state_ == kNetworkDown;
-}
-
 }  // namespace webrtc
diff --git a/modules/congestion_controller/send_side_congestion_controller_unittest.cc b/modules/congestion_controller/send_side_congestion_controller_unittest.cc
index 67d2c402..809526f 100644
--- a/modules/congestion_controller/send_side_congestion_controller_unittest.cc
+++ b/modules/congestion_controller/send_side_congestion_controller_unittest.cc
@@ -8,11 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
+#include "modules/congestion_controller/include/send_side_congestion_controller.h"
 #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
-#include "modules/bitrate_controller/include/bitrate_controller.h"
 #include "modules/congestion_controller/congestion_controller_unittests_helper.h"
 #include "modules/congestion_controller/include/mock/mock_congestion_observer.h"
-#include "modules/congestion_controller/include/send_side_congestion_controller.h"
 #include "modules/pacing/mock/mock_paced_sender.h"
 #include "modules/pacing/packet_router.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
@@ -33,16 +32,31 @@
 using testing::StrictMock;
 
 namespace webrtc {
+namespace test {
 
 namespace {
 const webrtc::PacedPacketInfo kPacingInfo0(0, 5, 2000);
 const webrtc::PacedPacketInfo kPacingInfo1(1, 8, 4000);
 
 const uint32_t kInitialBitrateBps = 60000;
+const float kDefaultPacingRate = 2.5f;
 
+class SendSideCongestionControllerForTest
+    : public SendSideCongestionController {
+ public:
+  SendSideCongestionControllerForTest(const Clock* clock,
+                                      Observer* observer,
+                                      RtcEventLog* event_log,
+                                      PacedSender* pacer)
+      : SendSideCongestionController(clock, observer, event_log, pacer) {}
+  ~SendSideCongestionControllerForTest() {}
+  void Process() override {
+    SendSideCongestionController::Process();
+    SendSideCongestionController::WaitOnTasks();
+  }
+};
 }  // namespace
 
-namespace test {
 
 class SendSideCongestionControllerTest : public ::testing::Test {
  protected:
@@ -52,14 +66,15 @@
 
   void SetUp() override {
     pacer_.reset(new NiceMock<MockPacedSender>());
-    controller_.reset(new SendSideCongestionController(
+    controller_.reset(new SendSideCongestionControllerForTest(
         &clock_, &observer_, &event_log_, pacer_.get()));
     bandwidth_observer_ = controller_->GetBandwidthObserver();
 
     // Set the initial bitrate estimate and expect the |observer| and |pacer_|
     // to be updated.
     EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
-    EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
+    EXPECT_CALL(*pacer_,
+                SetPacingRates(kInitialBitrateBps * kDefaultPacingRate, _));
     EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 3));
     EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 5));
     controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
@@ -68,8 +83,9 @@
   // Custom setup - use an observer that tracks the target bitrate, without
   // prescribing on which iterations it must change (like a mock would).
   void TargetBitrateTrackingSetup() {
+    bandwidth_observer_ = nullptr;
     pacer_.reset(new NiceMock<MockPacedSender>());
-    controller_.reset(new SendSideCongestionController(
+    controller_.reset(new SendSideCongestionControllerForTest(
         &clock_, &target_bitrate_observer_, &event_log_, pacer_.get()));
     controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
   }
@@ -137,7 +153,7 @@
   RtcpBandwidthObserver* bandwidth_observer_;
   PacketRouter packet_router_;
   std::unique_ptr<NiceMock<MockPacedSender>> pacer_;
-  std::unique_ptr<SendSideCongestionController> controller_;
+  std::unique_ptr<SendSideCongestionControllerForTest> controller_;
 
   rtc::Optional<uint32_t> target_bitrate_bps_;
 };
@@ -148,13 +164,15 @@
   controller_->Process();
 
   EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
+  EXPECT_CALL(*pacer_,
+              SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
   bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
 
   EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
+  EXPECT_CALL(*pacer_,
+              SetPacingRates(kInitialBitrateBps * kDefaultPacingRate, _));
   bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps);
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
@@ -162,14 +180,14 @@
 
 TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
 
   EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
   controller_->Process();
 
   // Let the pacer not be full next time the controller checks.
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
 
   EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
   controller_->Process();
@@ -177,23 +195,24 @@
 
 TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) {
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
   EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
   controller_->Process();
 
   // Receive new estimate but let the queue still be full.
   bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
   //  The send pacer should get the new estimate though.
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
+  EXPECT_CALL(*pacer_,
+              SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
 
   // Let the pacer not be full next time the controller checks.
   // |OnNetworkChanged| should be called with the new estimate.
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
   EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
@@ -214,7 +233,7 @@
   int new_bitrate = 200000;
   testing::Mock::VerifyAndClearExpectations(pacer_.get());
   EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
+  EXPECT_CALL(*pacer_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
   rtc::NetworkRoute route;
   route.local_network_id = 1;
   controller_->OnNetworkRouteChanged(route, new_bitrate, -1, -1);
@@ -224,8 +243,10 @@
   EXPECT_CALL(
       observer_,
       OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
-  EXPECT_CALL(*pacer_,
-              SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
+  EXPECT_CALL(
+      *pacer_,
+      SetPacingRates(
+          congestion_controller::GetMinBitrateBps() * kDefaultPacingRate, _));
   route.local_network_id = 2;
   controller_->OnNetworkRouteChanged(route, -1, -1, -1);
 }
@@ -234,7 +255,7 @@
   int new_bitrate = 200000;
   testing::Mock::VerifyAndClearExpectations(pacer_.get());
   EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
+  EXPECT_CALL(*pacer_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
 
   // Send a few packets on the first network route.
   std::vector<PacketFeedback> packets;
@@ -267,15 +288,17 @@
   EXPECT_CALL(
       observer_,
       OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
-  EXPECT_CALL(*pacer_,
-              SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
+  EXPECT_CALL(
+      *pacer_,
+      SetPacingRates(
+          congestion_controller::GetMinBitrateBps() * kDefaultPacingRate, _));
   route.local_network_id = 2;
   controller_->OnNetworkRouteChanged(route, -1, -1, -1);
 }
 
 TEST_F(SendSideCongestionControllerTest,
        SignalNetworkStateAndQueueIsFullAndEstimateChange) {
-  // Send queue is full
+  // Send queue is full.
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
       .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
   EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
@@ -290,14 +313,15 @@
   controller_->Process();
 
   // Receive new estimate but let the queue still be full.
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
+  EXPECT_CALL(*pacer_,
+              SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
   bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
 
   // Let the pacer not be full next time the controller checks.
   EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
-      .WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
+      .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
   EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
   controller_->Process();
 }
@@ -323,7 +347,7 @@
   controller_->Process();
 
   EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, testing::Ne(0)));
-  EXPECT_CALL(*pacer_, SetEstimatedBitrate(_));
+  EXPECT_CALL(*pacer_, SetPacingRates(_, _));
   bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
   clock_.AdvanceTimeMilliseconds(25);
   controller_->Process();
diff --git a/modules/congestion_controller/send_time_history.cc b/modules/congestion_controller/send_time_history.cc
index e5bc416..45d81c8 100644
--- a/modules/congestion_controller/send_time_history.cc
+++ b/modules/congestion_controller/send_time_history.cc
@@ -50,6 +50,17 @@
   return true;
 }
 
+rtc::Optional<PacketFeedback> SendTimeHistory::GetPacket(
+    uint16_t sequence_number) const {
+  int64_t unwrapped_seq_num =
+      seq_num_unwrapper_.UnwrapWithoutUpdate(sequence_number);
+  rtc::Optional<PacketFeedback> optional_feedback;
+  auto it = history_.find(unwrapped_seq_num);
+  if (it != history_.end())
+    optional_feedback.emplace(it->second);
+  return optional_feedback;
+}
+
 bool SendTimeHistory::GetFeedback(PacketFeedback* packet_feedback,
                                   bool remove) {
   RTC_DCHECK(packet_feedback);
diff --git a/modules/congestion_controller/send_time_history.h b/modules/congestion_controller/send_time_history.h
index 366fec9..649ef6a 100644
--- a/modules/congestion_controller/send_time_history.h
+++ b/modules/congestion_controller/send_time_history.h
@@ -33,6 +33,9 @@
   // Return false if not found.
   bool OnSentPacket(uint16_t sequence_number, int64_t send_time_ms);
 
+  // Retrieves packet info identified by |sequence_number|.
+  rtc::Optional<PacketFeedback> GetPacket(uint16_t sequence_number) const;
+
   // Look up PacketFeedback for a sent packet, based on the sequence number, and
   // populate all fields except for arrival_time. The packet parameter must
   // thus be non-null and have the sequence_number field set.
diff --git a/modules/congestion_controller/send_time_history_unittest.cc b/modules/congestion_controller/send_time_history_unittest.cc
index 64f30c0..15907cc 100644
--- a/modules/congestion_controller/send_time_history_unittest.cc
+++ b/modules/congestion_controller/send_time_history_unittest.cc
@@ -52,8 +52,7 @@
   uint16_t sequence_number = 0;
   int64_t now_ms = clock_.TimeInMilliseconds();
   for (int i = 1; i < 5; ++i) {
-    PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1,
-                          kPacingInfo);
+    PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1, kPacingInfo);
     history_.AddAndRemoveOld(packet);
     history_.OnSentPacket(sequence_number, now_ms);
     PacketFeedback restored(now_ms, sequence_number);
@@ -82,6 +81,26 @@
   EXPECT_FALSE(history_.GetFeedback(&received_packet3, true));
 }
 
+TEST_F(SendTimeHistoryTest, GetPacketReturnsSentPacket) {
+  const uint16_t kSeqNo = 10;
+  const PacedPacketInfo kPacingInfo(0, 5, 1200);
+  const PacketFeedback kSentPacket(0, -1, 1, kSeqNo, 123, 0, 0, kPacingInfo);
+  AddPacketWithSendTime(kSeqNo, 123, 1, kPacingInfo);
+  auto sent_packet = history_.GetPacket(kSeqNo);
+  EXPECT_EQ(kSentPacket, *sent_packet);
+}
+
+TEST_F(SendTimeHistoryTest, GetPacketEmptyForRemovedPacket) {
+  const uint16_t kSeqNo = 10;
+  const PacedPacketInfo kPacingInfo(0, 5, 1200);
+  AddPacketWithSendTime(kSeqNo, 123, 1, kPacingInfo);
+  auto sent_packet = history_.GetPacket(kSeqNo);
+  PacketFeedback received_packet(0, 0, kSeqNo, 0, kPacingInfo);
+  EXPECT_TRUE(history_.GetFeedback(&received_packet, true));
+  sent_packet = history_.GetPacket(kSeqNo);
+  EXPECT_FALSE(sent_packet.has_value());
+}
+
 TEST_F(SendTimeHistoryTest, PopulatesExpectedFields) {
   const uint16_t kSeqNo = 10;
   const int64_t kSendTime = 1000;
diff --git a/modules/congestion_controller/transport_feedback_adapter.cc b/modules/congestion_controller/transport_feedback_adapter.cc
index 7a5f7c4..8973eca 100644
--- a/modules/congestion_controller/transport_feedback_adapter.cc
+++ b/modules/congestion_controller/transport_feedback_adapter.cc
@@ -82,6 +82,12 @@
   send_time_history_.OnSentPacket(sequence_number, send_time_ms);
 }
 
+rtc::Optional<PacketFeedback> TransportFeedbackAdapter::GetPacket(
+    uint16_t sequence_number) const {
+  rtc::CritScope cs(&lock_);
+  return send_time_history_.GetPacket(sequence_number);
+}
+
 void TransportFeedbackAdapter::SetNetworkIds(uint16_t local_id,
                                              uint16_t remote_id) {
   rtc::CritScope cs(&lock_);
@@ -118,7 +124,6 @@
     return packet_feedback_vector;
   }
   packet_feedback_vector.reserve(feedback.GetPacketStatusCount());
-  int64_t feedback_rtt = -1;
   {
     rtc::CritScope cs(&lock_);
     size_t failed_lookups = 0;
@@ -148,12 +153,6 @@
         ++failed_lookups;
       if (packet_feedback.local_net_id == local_net_id_ &&
           packet_feedback.remote_net_id == remote_net_id_) {
-        if (packet_feedback.send_time_ms >= 0) {
-          int64_t rtt = now_ms - packet_feedback.send_time_ms;
-          // max() is used to account for feedback being delayed by the
-          // receiver.
-          feedback_rtt = std::max(rtt, feedback_rtt);
-        }
         packet_feedback_vector.push_back(packet_feedback);
       }
 
@@ -165,14 +164,6 @@
                           << " packet" << (failed_lookups > 1 ? "s" : "")
                           << ". Send time history too small?";
     }
-    if (feedback_rtt > -1) {
-      feedback_rtts_.push_back(feedback_rtt);
-      const size_t kFeedbackRttWindow = 32;
-      if (feedback_rtts_.size() > kFeedbackRttWindow)
-        feedback_rtts_.pop_front();
-      min_feedback_rtt_.emplace(
-          *std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
-    }
   }
   return packet_feedback_vector;
 }
@@ -193,11 +184,6 @@
   return last_packet_feedback_vector_;
 }
 
-rtc::Optional<int64_t> TransportFeedbackAdapter::GetMinFeedbackLoopRtt() const {
-  rtc::CritScope cs(&lock_);
-  return min_feedback_rtt_;
-}
-
 size_t TransportFeedbackAdapter::GetOutstandingBytes() const {
   rtc::CritScope cs(&lock_);
   return send_time_history_.GetOutstandingBytes(local_net_id_, remote_net_id_);
diff --git a/modules/congestion_controller/transport_feedback_adapter.h b/modules/congestion_controller/transport_feedback_adapter.h
index 2e9bf7c..2659254 100644
--- a/modules/congestion_controller/transport_feedback_adapter.h
+++ b/modules/congestion_controller/transport_feedback_adapter.h
@@ -47,7 +47,7 @@
   // to the CongestionController interface.
   void OnTransportFeedback(const rtcp::TransportFeedback& feedback);
   std::vector<PacketFeedback> GetTransportFeedbackVector() const;
-  rtc::Optional<int64_t> GetMinFeedbackLoopRtt() const;
+  rtc::Optional<PacketFeedback> GetPacket(uint16_t sequence_number) const;
 
   void SetTransportOverhead(int transport_overhead_bytes_per_packet);
 
@@ -67,8 +67,6 @@
   std::vector<PacketFeedback> last_packet_feedback_vector_;
   uint16_t local_net_id_ RTC_GUARDED_BY(&lock_);
   uint16_t remote_net_id_ RTC_GUARDED_BY(&lock_);
-  std::deque<int64_t> feedback_rtts_ RTC_GUARDED_BY(&lock_);
-  rtc::Optional<int64_t> min_feedback_rtt_ RTC_GUARDED_BY(&lock_);
 
   rtc::CriticalSection observers_lock_;
   std::vector<PacketFeedbackObserver*> observers_
diff --git a/modules/pacing/BUILD.gn b/modules/pacing/BUILD.gn
index 4ac56d2..fdfa3b2 100644
--- a/modules/pacing/BUILD.gn
+++ b/modules/pacing/BUILD.gn
@@ -10,8 +10,6 @@
 
 rtc_static_library("pacing") {
   sources = [
-    "alr_detector.cc",
-    "alr_detector.h",
     "bitrate_prober.cc",
     "bitrate_prober.h",
     "interval_budget.cc",
@@ -60,7 +58,6 @@
     testonly = true
 
     sources = [
-      "alr_detector_unittest.cc",
       "bitrate_prober_unittest.cc",
       "interval_budget_unittest.cc",
       "paced_sender_unittest.cc",
diff --git a/modules/pacing/interval_budget.cc b/modules/pacing/interval_budget.cc
index b63bc37..f739a98 100644
--- a/modules/pacing/interval_budget.cc
+++ b/modules/pacing/interval_budget.cc
@@ -15,7 +15,6 @@
 namespace webrtc {
 namespace {
 constexpr int kWindowMs = 500;
-constexpr int kDeltaTimeMs = 2000;
 }
 
 IntervalBudget::IntervalBudget(int initial_target_rate_kbps)
@@ -35,7 +34,6 @@
 }
 
 void IntervalBudget::IncreaseBudget(int64_t delta_time_ms) {
-  RTC_DCHECK_LT(delta_time_ms, kDeltaTimeMs);
   int bytes = target_rate_kbps_ * delta_time_ms / 8;
   if (bytes_remaining_ < 0 || can_build_up_underuse_) {
     // We overused last interval, compensate this interval.
@@ -56,6 +54,8 @@
 }
 
 int IntervalBudget::budget_level_percent() const {
+  if (max_bytes_in_budget_ == 0)
+    return 0;
   return bytes_remaining_ * 100 / max_bytes_in_budget_;
 }
 
diff --git a/modules/pacing/mock/mock_paced_sender.h b/modules/pacing/mock/mock_paced_sender.h
index 3366aa8..cf98996 100644
--- a/modules/pacing/mock/mock_paced_sender.h
+++ b/modules/pacing/mock/mock_paced_sender.h
@@ -30,12 +30,10 @@
                                 size_t bytes,
                                 bool retransmission));
   MOCK_METHOD1(CreateProbeCluster, void(int));
-  MOCK_METHOD1(SetEstimatedBitrate, void(uint32_t));
+  MOCK_METHOD2(SetPacingRates, void(uint32_t, uint32_t));
   MOCK_CONST_METHOD0(QueueInMs, int64_t());
   MOCK_CONST_METHOD0(QueueInPackets, int());
   MOCK_CONST_METHOD0(ExpectedQueueTimeMs, int64_t());
-  MOCK_CONST_METHOD0(GetApplicationLimitedRegionStartTime,
-                     rtc::Optional<int64_t>());
   MOCK_METHOD0(Process, void());
 };
 
diff --git a/modules/pacing/paced_sender.cc b/modules/pacing/paced_sender.cc
index 4bccb00..862f4e1 100644
--- a/modules/pacing/paced_sender.cc
+++ b/modules/pacing/paced_sender.cc
@@ -18,7 +18,6 @@
 #include <utility>
 
 #include "modules/include/module_common_types.h"
-#include "modules/pacing/alr_detector.h"
 #include "modules/pacing/bitrate_prober.h"
 #include "modules/pacing/interval_budget.h"
 #include "modules/pacing/packet_queue.h"
@@ -54,7 +53,6 @@
 namespace webrtc {
 
 const int64_t PacedSender::kMaxQueueLengthMs = 2000;
-const float PacedSender::kDefaultPaceMultiplier = 2.5f;
 
 namespace {
 std::unique_ptr<PacketQueueInterface> CreatePacketQueue(const Clock* clock,
@@ -81,21 +79,16 @@
                          std::unique_ptr<PacketQueueInterface> packets)
     : clock_(clock),
       packet_sender_(packet_sender),
-      alr_detector_(rtc::MakeUnique<AlrDetector>(event_log)),
       paused_(false),
       media_budget_(rtc::MakeUnique<IntervalBudget>(0)),
       padding_budget_(rtc::MakeUnique<IntervalBudget>(0)),
       prober_(rtc::MakeUnique<BitrateProber>(event_log)),
       probing_send_failure_(false),
-      estimated_bitrate_bps_(0),
-      min_send_bitrate_kbps_(0u),
-      max_padding_bitrate_kbps_(0u),
       pacing_bitrate_kbps_(0),
       time_last_update_us_(clock->TimeInMicroseconds()),
       first_sent_packet_ms_(-1),
       packets_(std::move(packets)),
       packet_counter_(0),
-      pacing_factor_(kDefaultPaceMultiplier),
       queue_time_limit(kMaxQueueLengthMs),
       account_for_audio_(false) {
   UpdateBudgetWithElapsedTime(kMinPacketLimitMs);
@@ -116,6 +109,7 @@
     paused_ = true;
     packets_->SetPauseState(true, clock_->TimeInMilliseconds());
   }
+  rtc::CritScope cs(&process_thread_lock_);
   // Tell the process thread to call our TimeUntilNextProcess() method to get
   // a new (longer) estimate for when to call Process().
   if (process_thread_)
@@ -130,6 +124,7 @@
     paused_ = false;
     packets_->SetPauseState(false, clock_->TimeInMilliseconds());
   }
+  rtc::CritScope cs(&process_thread_lock_);
   // Tell the process thread to call our TimeUntilNextProcess() method to
   // refresh the estimate for when to call Process().
   if (process_thread_)
@@ -142,29 +137,12 @@
   prober_->SetEnabled(enabled);
 }
 
-void PacedSender::SetEstimatedBitrate(uint32_t bitrate_bps) {
-  if (bitrate_bps == 0)
-    RTC_LOG(LS_ERROR) << "PacedSender is not designed to handle 0 bitrate.";
+void PacedSender::SetPacingRates(uint32_t pacing_rate_bps,
+                                 uint32_t padding_rate_bps) {
   rtc::CritScope cs(&critsect_);
-  estimated_bitrate_bps_ = bitrate_bps;
-  padding_budget_->set_target_rate_kbps(
-      std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
-  pacing_bitrate_kbps_ =
-      std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
-      pacing_factor_;
-  alr_detector_->SetEstimatedBitrate(bitrate_bps);
-}
-
-void PacedSender::SetSendBitrateLimits(int min_send_bitrate_bps,
-                                       int padding_bitrate) {
-  rtc::CritScope cs(&critsect_);
-  min_send_bitrate_kbps_ = min_send_bitrate_bps / 1000;
-  pacing_bitrate_kbps_ =
-      std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
-      pacing_factor_;
-  max_padding_bitrate_kbps_ = padding_bitrate / 1000;
-  padding_budget_->set_target_rate_kbps(
-      std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
+  RTC_DCHECK(pacing_rate_bps > 0);
+  pacing_bitrate_kbps_ = pacing_rate_bps / 1000;
+  padding_budget_->set_target_rate_kbps(padding_rate_bps / 1000);
 }
 
 void PacedSender::InsertPacket(RtpPacketSender::Priority priority,
@@ -174,8 +152,8 @@
                                size_t bytes,
                                bool retransmission) {
   rtc::CritScope cs(&critsect_);
-  RTC_DCHECK(estimated_bitrate_bps_ > 0)
-        << "SetEstimatedBitrate must be called before InsertPacket.";
+  RTC_DCHECK(pacing_bitrate_kbps_ > 0)
+      << "SetPacingRate must be called before InsertPacket.";
 
   int64_t now_ms = clock_->TimeInMilliseconds();
   prober_->OnIncomingPacket(bytes);
@@ -200,12 +178,6 @@
                               pacing_bitrate_kbps_);
 }
 
-rtc::Optional<int64_t> PacedSender::GetApplicationLimitedRegionStartTime()
-    const {
-  rtc::CritScope cs(&critsect_);
-  return alr_detector_->GetApplicationLimitedRegionStartTime();
-}
-
 size_t PacedSender::QueueSizePackets() const {
   rtc::CritScope cs(&critsect_);
   return packets_->SizeInPackets();
@@ -257,8 +229,7 @@
     // do, timestamps get messed up.
     if (packet_counter_ == 0)
       return;
-    size_t bytes_sent = SendPadding(1, pacing_info);
-    alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
+    SendPadding(1, pacing_info);
     return;
   }
 
@@ -291,7 +262,7 @@
     pacing_info = prober_->CurrentCluster();
     recommended_probe_size = prober_->RecommendedMinProbeSize();
   }
-  while (!packets_->Empty()) {
+  while (!packets_->Empty() && !paused_) {
     // Since we need to release the lock in order to send, we first pop the
     // element from the priority queue but keep it in storage, so that we can
     // reinsert it if send fails.
@@ -319,8 +290,9 @@
       int padding_needed =
           static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent)
                                       : padding_budget_->bytes_remaining());
-      if (padding_needed > 0)
+      if (padding_needed > 0) {
         bytes_sent += SendPadding(padding_needed, pacing_info);
+      }
     }
   }
   if (is_probing) {
@@ -328,11 +300,11 @@
     if (!probing_send_failure_)
       prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent);
   }
-  alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
 }
 
 void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) {
   RTC_LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread;
+  rtc::CritScope cs(&process_thread_lock_);
   process_thread_ = process_thread;
 }
 
@@ -388,14 +360,6 @@
   padding_budget_->UseBudget(bytes_sent);
 }
 
-void PacedSender::SetPacingFactor(float pacing_factor) {
-  rtc::CritScope cs(&critsect_);
-  pacing_factor_ = pacing_factor;
-  // Make sure new padding factor is applied immediately, otherwise we need to
-  // wait for the send bitrate estimate to be updated before this takes effect.
-  SetEstimatedBitrate(estimated_bitrate_bps_);
-}
-
 void PacedSender::SetQueueTimeLimit(int limit_ms) {
   rtc::CritScope cs(&critsect_);
   queue_time_limit = limit_ms;
diff --git a/modules/pacing/paced_sender.h b/modules/pacing/paced_sender.h
index 02ebdcd..0501bbb 100644
--- a/modules/pacing/paced_sender.h
+++ b/modules/pacing/paced_sender.h
@@ -21,7 +21,6 @@
 #include "typedefs.h"  // NOLINT(build/include)
 
 namespace webrtc {
-class AlrDetector;
 class BitrateProber;
 class Clock;
 class ProbeClusterCreatedObserver;
@@ -55,12 +54,6 @@
   // encoding them). Bitrate sent may temporarily exceed target set by
   // UpdateBitrate() so that this limit will be upheld.
   static const int64_t kMaxQueueLengthMs;
-  // Pacing-rate relative to our target send rate.
-  // Multiplicative factor that is applied to the target bitrate to calculate
-  // the number of bytes that can be transmitted per interval.
-  // Increasing this factor will result in lower delays in cases of bitrate
-  // overshoots from the encoder.
-  static const float kDefaultPaceMultiplier;
 
   PacedSender(const Clock* clock,
               PacketSender* packet_sender,
@@ -86,22 +79,9 @@
   // effect.
   void SetProbingEnabled(bool enabled);
 
-  // Sets the estimated capacity of the network. Must be called once before
-  // packets can be sent.
-  // |bitrate_bps| is our estimate of what we are allowed to send on average.
-  // We will pace out bursts of packets at a bitrate of
-  // |bitrate_bps| * kDefaultPaceMultiplier.
-  void SetEstimatedBitrate(uint32_t bitrate_bps) override;
-
-  // Sets the minimum send bitrate and maximum padding bitrate requested by send
-  // streams.
-  // |min_send_bitrate_bps| might be higher that the estimated available network
-  // bitrate and if so, the pacer will send with |min_send_bitrate_bps|.
-  // |max_padding_bitrate_bps| might be higher than the estimate available
-  // network bitrate and if so, the pacer will send padding packets to reach
-  // the min of the estimated available bitrate and |max_padding_bitrate_bps|.
-  void SetSendBitrateLimits(int min_send_bitrate_bps,
-                            int max_padding_bitrate_bps);
+  // Sets the pacing rates. Must be called once before packets can be sent.
+  void SetPacingRates(uint32_t pacing_rate_bps,
+                      uint32_t padding_rate_bps) override;
 
   // Returns true if we send the packet now, else it will add the packet
   // information to the queue and call TimeToSendPacket when it's time to send.
@@ -131,14 +111,6 @@
   // packets in the queue, given the current size and bitrate, ignoring prio.
   virtual int64_t ExpectedQueueTimeMs() const;
 
-  // Returns time in milliseconds when the current application-limited region
-  // started or empty result if the sender is currently not application-limited.
-  //
-  // Application Limited Region (ALR) 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.
-  virtual rtc::Optional<int64_t> GetApplicationLimitedRegionStartTime() const;
-
   // Returns the number of milliseconds until the module want a worker thread
   // to call Process.
   int64_t TimeUntilNextProcess() override;
@@ -148,7 +120,6 @@
 
   // Called when the prober is associated with a process thread.
   void ProcessThreadAttached(ProcessThread* process_thread) override;
-  void SetPacingFactor(float pacing_factor);
   void SetQueueTimeLimit(int limit_ms);
 
  private:
@@ -166,7 +137,6 @@
 
   const Clock* const clock_;
   PacketSender* const packet_sender_;
-  const std::unique_ptr<AlrDetector> alr_detector_ RTC_PT_GUARDED_BY(critsect_);
 
   rtc::CriticalSection critsect_;
   bool paused_ RTC_GUARDED_BY(critsect_);
@@ -184,9 +154,6 @@
   bool probing_send_failure_ RTC_GUARDED_BY(critsect_);
   // Actual configured bitrates (media_budget_ may temporarily be higher in
   // order to meet pace time constraint).
-  uint32_t estimated_bitrate_bps_ RTC_GUARDED_BY(critsect_);
-  uint32_t min_send_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
-  uint32_t max_padding_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
   uint32_t pacing_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
 
   int64_t time_last_update_us_ RTC_GUARDED_BY(critsect_);
@@ -195,9 +162,15 @@
   const std::unique_ptr<PacketQueueInterface> packets_
       RTC_PT_GUARDED_BY(critsect_);
   uint64_t packet_counter_ RTC_GUARDED_BY(critsect_);
-  ProcessThread* process_thread_ = nullptr;
 
-  float pacing_factor_ RTC_GUARDED_BY(critsect_);
+  // Lock to avoid race when attaching process thread. This can happen due to
+  // the Call class setting network state on SendSideCongestionController, which
+  // in turn calls Pause/Resume on Pacedsender, before actually starting the
+  // pacer process thread. If SendSideCongestionController is running on a task
+  // queue separate from the thread used by Call, this causes a race.
+  rtc::CriticalSection process_thread_lock_;
+  ProcessThread* process_thread_ RTC_GUARDED_BY(process_thread_lock_) = nullptr;
+
   int64_t queue_time_limit RTC_GUARDED_BY(critsect_);
   bool account_for_audio_ RTC_GUARDED_BY(critsect_);
 };
diff --git a/modules/pacing/paced_sender_unittest.cc b/modules/pacing/paced_sender_unittest.cc
index 4281ec2..4507f3f 100644
--- a/modules/pacing/paced_sender_unittest.cc
+++ b/modules/pacing/paced_sender_unittest.cc
@@ -31,6 +31,8 @@
 // values. This results in probing slightly higher than the target bitrate.
 // For 1.8 Mbps, this comes to be about 120 kbps with 1200 probe packets.
 constexpr int kBitrateProbingError = 150000;
+
+const float kPaceMultiplier = 2.5f;
 }  // namespace
 
 namespace webrtc {
@@ -116,7 +118,7 @@
     // have to enable probing, either by creating a new PacedSender instance or
     // by calling SetProbingEnabled(true).
     send_bucket_->SetProbingEnabled(false);
-    send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
+    send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier, 0);
 
     clock_.AdvanceTimeMilliseconds(send_bucket_->TimeUntilNextProcess());
   }
@@ -171,7 +173,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -220,7 +222,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -305,14 +307,14 @@
   uint32_t ssrc = 12345;
   uint16_t sequence_number = 1234;
 
-  send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
-  send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
 
   // Due to the multiplicative factor we can send 5 packets during a send
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -342,8 +344,8 @@
 }
 
 TEST_P(PacedSenderTest, NoPaddingBeforeNormalPacket) {
-  send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
-  send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
 
   EXPECT_CALL(callback_, TimeToSendPadding(_, _)).Times(0);
   send_bucket_->Process();
@@ -370,8 +372,8 @@
   int64_t capture_time_ms = 56789;
   const int kTimeStep = 5;
   const int64_t kBitrateWindow = 100;
-  send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
-  send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
 
   int64_t start_time = clock_.TimeInMilliseconds();
   while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) {
@@ -398,11 +400,8 @@
   PacedSenderPadding callback;
   send_bucket_.reset(new PacedSender(&clock_, &callback, nullptr));
   send_bucket_->SetProbingEnabled(false);
-  send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
-
-  send_bucket_->SetSendBitrateLimits(
-      0 /*allocated_bitrate_bps*/,
-      kTargetBitrateBps * 2 /* max_padding_bitrate_bps */);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
 
   int64_t start_time = clock_.TimeInMilliseconds();
   size_t media_bytes = 0;
@@ -433,7 +432,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -487,7 +486,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   send_bucket_->Process();
   EXPECT_EQ(0u, send_bucket_->QueueSizePackets());
 
@@ -548,7 +547,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
     SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -582,7 +581,7 @@
   // interval. (network capacity * multiplier / (8 bits per byte *
   // (packet size * #send intervals per second)
   const size_t packets_to_send_per_interval =
-      kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
+      kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
   for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), 250, false);
@@ -741,10 +740,10 @@
   uint16_t sequence_number = 1234;
   const size_t kNumPackets = 60;
   const size_t kPacketSize = 1200;
-  const int32_t kMaxBitrate = PacedSender::kDefaultPaceMultiplier * 30000;
+  const int32_t kMaxBitrate = kPaceMultiplier * 30000;
   EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
 
-  send_bucket_->SetEstimatedBitrate(30000);
+  send_bucket_->SetPacingRates(30000 * kPaceMultiplier, 0);
   for (size_t i = 0; i < kNumPackets; ++i) {
     SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                         clock_.TimeInMilliseconds(), kPacketSize, false);
@@ -778,7 +777,7 @@
   uint16_t sequence_number = 1234;
   EXPECT_EQ(0, send_bucket_->QueueInMs());
 
-  send_bucket_->SetEstimatedBitrate(30000);
+  send_bucket_->SetPacingRates(30000 * kPaceMultiplier, 0);
   SendAndExpectPacket(PacedSender::kNormalPriority,
                       ssrc,
                       sequence_number,
@@ -802,7 +801,7 @@
   send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr));
   send_bucket_->CreateProbeCluster(kFirstClusterBps);
   send_bucket_->CreateProbeCluster(kSecondClusterBps);
-  send_bucket_->SetEstimatedBitrate(kInitialBitrateBps);
+  send_bucket_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
 
   for (int i = 0; i < 10; ++i) {
     send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@@ -847,7 +846,7 @@
   PacedSenderProbing packet_sender;
   send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr));
   send_bucket_->CreateProbeCluster(kFirstClusterBps);
-  send_bucket_->SetEstimatedBitrate(kInitialBitrateBps);
+  send_bucket_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
 
   for (int i = 0; i < 3; ++i) {
     send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@@ -935,8 +934,7 @@
   const size_t kPacketSize = 1200;
 
   send_bucket_->Process();
-  send_bucket_->SetEstimatedBitrate(60000);
-  send_bucket_->SetSendBitrateLimits(60000, 0);
+  send_bucket_->SetPacingRates(60000 * kPaceMultiplier, 0);
 
   SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                       clock_.TimeInMilliseconds(), kPacketSize, false);
@@ -945,7 +943,7 @@
   // Add 30kbit padding. When increasing budget, media budget will increase from
   // negative (overuse) while padding budget will increase from 0.
   clock_.AdvanceTimeMilliseconds(5);
-  send_bucket_->SetSendBitrateLimits(60000, 30000);
+  send_bucket_->SetPacingRates(60000 * kPaceMultiplier, 30000);
 
   SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
                       clock_.TimeInMilliseconds(), kPacketSize, false);
@@ -963,7 +961,7 @@
   const size_t kPacketSize = 1200;
   const int kBitrateBps = 10 * kPacketSize * 8;  // 10 packets per second.
 
-  send_bucket_->SetEstimatedBitrate(kBitrateBps);
+  send_bucket_->SetPacingRates(kBitrateBps * kPaceMultiplier, 0);
 
   EXPECT_EQ(0, send_bucket_->AverageQueueTimeMs());
 
@@ -1008,7 +1006,8 @@
   uint16_t sequence_number = 1234;
   const size_t kPacketSize = 1200;
 
-  send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
   send_bucket_->SetProbingEnabled(true);
   for (int i = 0; i < 10; ++i) {
     send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@@ -1054,7 +1053,8 @@
   uint16_t sequence_number = 1234;
   const size_t kPacketSize = kFirstClusterBps / (8000 / 10);
 
-  send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
+  send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
+                               kTargetBitrateBps);
   send_bucket_->SetProbingEnabled(true);
   send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
                              sequence_number, clock_.TimeInMilliseconds(),
diff --git a/modules/pacing/pacer.h b/modules/pacing/pacer.h
index 8b43e18..4941e15 100644
--- a/modules/pacing/pacer.h
+++ b/modules/pacing/pacer.h
@@ -17,7 +17,8 @@
 namespace webrtc {
 class Pacer : public Module, public RtpPacketSender {
  public:
-  virtual void SetEstimatedBitrate(uint32_t bitrate_bps) {}
+  virtual void SetPacingRates(uint32_t pacing_rate_bps,
+                              uint32_t padding_rate_bps) {}
   virtual void SetEstimatedBitrateAndCongestionWindow(
       uint32_t bitrate_bps,
       bool in_probe_rtt,
diff --git a/modules/pacing/packet_queue.cc b/modules/pacing/packet_queue.cc
index 5e4e58c..eb0f822 100644
--- a/modules/pacing/packet_queue.cc
+++ b/modules/pacing/packet_queue.cc
@@ -15,7 +15,6 @@
 #include <vector>
 
 #include "modules/include/module_common_types.h"
-#include "modules/pacing/alr_detector.h"
 #include "modules/pacing/bitrate_prober.h"
 #include "modules/pacing/interval_budget.h"
 #include "modules/utility/include/process_thread.h"
diff --git a/modules/pacing/packet_router.cc b/modules/pacing/packet_router.cc
index e3d935e..ef9d10a 100644
--- a/modules/pacing/packet_router.cc
+++ b/modules/pacing/packet_router.cc
@@ -98,7 +98,6 @@
                                     int64_t capture_timestamp,
                                     bool retransmission,
                                     const PacedPacketInfo& pacing_info) {
-  RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
   rtc::CritScope cs(&modules_crit_);
   for (auto* rtp_module : rtp_send_modules_) {
     if (!rtp_module->SendingMedia())
@@ -114,7 +113,6 @@
 
 size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
                                        const PacedPacketInfo& pacing_info) {
-  RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
   size_t total_bytes_sent = 0;
   rtc::CritScope cs(&modules_crit_);
   // Rtp modules are ordered by which stream can most benefit from padding.
@@ -223,7 +221,6 @@
 }
 
 bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
-  RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
   rtc::CritScope cs(&modules_crit_);
   // Prefer send modules.
   for (auto* rtp_module : rtp_send_modules_) {
diff --git a/modules/pacing/packet_router.h b/modules/pacing/packet_router.h
index 9597896..22a578c 100644
--- a/modules/pacing/packet_router.h
+++ b/modules/pacing/packet_router.h
@@ -91,7 +91,6 @@
   void UnsetActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_);
   void DetermineActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_);
 
-  rtc::RaceChecker pacer_race_;
   rtc::CriticalSection modules_crit_;
   // Rtp and Rtcp modules of the rtp senders.
   std::list<RtpRtcp*> rtp_send_modules_ RTC_GUARDED_BY(modules_crit_);
diff --git a/modules/remote_bitrate_estimator/bwe_simulations.cc b/modules/remote_bitrate_estimator/bwe_simulations.cc
index f8866d8..87106f1 100644
--- a/modules/remote_bitrate_estimator/bwe_simulations.cc
+++ b/modules/remote_bitrate_estimator/bwe_simulations.cc
@@ -477,47 +477,47 @@
   RunPauseResumeFlows(GetParam());
 }
 
-// Following test cases begin with "GccComparison" run the
-// evaluation test cases for both GCC and other calling RMCAT.
+// Following test cases begin with "GoogCcComparison" run the
+// evaluation test cases for both GoogCc and other calling RMCAT.
 
-TEST_P(BweSimulation, GccComparison1) {
+TEST_P(BweSimulation, GoogCcComparison1) {
   RunVariableCapacity1SingleFlow(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator);
 }
 
-TEST_P(BweSimulation, GccComparison2) {
+TEST_P(BweSimulation, GoogCcComparison2) {
   const size_t kNumFlows = 2;
   RunVariableCapacity2MultipleFlows(GetParam(), kNumFlows);
-  BweTest gcc_test(false);
-  gcc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows);
 }
 
-TEST_P(BweSimulation, GccComparison3) {
+TEST_P(BweSimulation, GoogCcComparison3) {
   RunBidirectionalFlow(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunBidirectionalFlow(kSendSideEstimator);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunBidirectionalFlow(kSendSideEstimator);
 }
 
-TEST_P(BweSimulation, GccComparison4) {
+TEST_P(BweSimulation, GoogCcComparison4) {
   RunSelfFairness(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunSelfFairness(GetParam());
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunSelfFairness(GetParam());
 }
 
-TEST_P(BweSimulation, GccComparison5) {
+TEST_P(BweSimulation, GoogCcComparison5) {
   RunRoundTripTimeFairness(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunRoundTripTimeFairness(kSendSideEstimator);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunRoundTripTimeFairness(kSendSideEstimator);
 }
 
-TEST_P(BweSimulation, GccComparison6) {
+TEST_P(BweSimulation, GoogCcComparison6) {
   RunLongTcpFairness(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunLongTcpFairness(kSendSideEstimator);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunLongTcpFairness(kSendSideEstimator);
 }
 
-TEST_P(BweSimulation, GccComparison7) {
+TEST_P(BweSimulation, GoogCcComparison7) {
   const int kNumTcpFiles = 10;
 
   std::vector<int> tcp_file_sizes_bytes =
@@ -528,24 +528,24 @@
   RunMultipleShortTcpFairness(GetParam(), tcp_file_sizes_bytes,
                               tcp_starting_times_ms);
 
-  BweTest gcc_test(false);
-  gcc_test.RunMultipleShortTcpFairness(kSendSideEstimator, tcp_file_sizes_bytes,
-                                       tcp_starting_times_ms);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunMultipleShortTcpFairness(
+      kSendSideEstimator, tcp_file_sizes_bytes, tcp_starting_times_ms);
 }
 
-TEST_P(BweSimulation, GccComparison8) {
+TEST_P(BweSimulation, GoogCcComparison8) {
   RunPauseResumeFlows(GetParam());
-  BweTest gcc_test(false);
-  gcc_test.RunPauseResumeFlows(kSendSideEstimator);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunPauseResumeFlows(kSendSideEstimator);
 }
 
-TEST_P(BweSimulation, GccComparisonChoke) {
+TEST_P(BweSimulation, GoogCcComparisonChoke) {
   int array[] = {1000, 500, 1000};
   std::vector<int> capacities_kbps(array, array + 3);
   RunChoke(GetParam(), capacities_kbps);
 
-  BweTest gcc_test(false);
-  gcc_test.RunChoke(kSendSideEstimator, capacities_kbps);
+  BweTest goog_cc_test(false);
+  goog_cc_test.RunChoke(kSendSideEstimator, capacities_kbps);
 }
 
 }  // namespace bwe
diff --git a/modules/remote_bitrate_estimator/test/bwe.h b/modules/remote_bitrate_estimator/test/bwe.h
index 96aed21..9cc5063 100644
--- a/modules/remote_bitrate_estimator/test/bwe.h
+++ b/modules/remote_bitrate_estimator/test/bwe.h
@@ -181,7 +181,8 @@
   kBbrEstimator
 };
 
-const char* const bwe_names[] = {"Null", "NADA", "REMB", "GCC", "TCP", "BBR"};
+const char* const bwe_names[] = {"Null",   "NADA", "REMB",
+                                 "GoogCc", "TCP",  "BBR"};
 
 int64_t GetAbsSendTimeInMs(uint32_t abs_send_time);
 
diff --git a/modules/remote_bitrate_estimator/test/estimators/send_side.cc b/modules/remote_bitrate_estimator/test/estimators/send_side.cc
index 6e03eee..123def9 100644
--- a/modules/remote_bitrate_estimator/test/estimators/send_side.cc
+++ b/modules/remote_bitrate_estimator/test/estimators/send_side.cc
@@ -32,7 +32,7 @@
                                                      &event_log_)),
       acknowledged_bitrate_estimator_(
           rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
-      bwe_(new DelayBasedBwe(nullptr, clock)),
+      bwe_(new DelayBasedBwe(nullptr)),
       feedback_observer_(bitrate_controller_.get()),
       clock_(clock),
       send_time_history_(clock_, 10000),
@@ -72,7 +72,7 @@
 
   int64_t rtt_ms =
       clock_->TimeInMilliseconds() - feedback.latest_send_time_ms();
-  bwe_->OnRttUpdate(rtt_ms, rtt_ms);
+  bwe_->OnRttUpdate(rtt_ms);
   BWE_TEST_LOGGING_PLOT(1, "RTT", clock_->TimeInMilliseconds(), rtt_ms);
 
   std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(),
@@ -80,7 +80,8 @@
   acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
       packet_feedback_vector);
   DelayBasedBwe::Result result = bwe_->IncomingPacketFeedbackVector(
-      packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps());
+      packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
+      clock_->TimeInMilliseconds());
   if (result.updated)
     bitrate_controller_->OnDelayBasedBweResult(result);
 
diff --git a/modules/remote_bitrate_estimator/test/packet_sender.cc b/modules/remote_bitrate_estimator/test/packet_sender.cc
index 08db1a3..d45f363 100644
--- a/modules/remote_bitrate_estimator/test/packet_sender.cc
+++ b/modules/remote_bitrate_estimator/test/packet_sender.cc
@@ -24,6 +24,9 @@
 namespace webrtc {
 namespace testing {
 namespace bwe {
+namespace {
+const float kPaceMultiplier = 2.5f;
+}
 
 void PacketSender::Pause() {
   running_ = false;
@@ -164,7 +167,7 @@
               ? static_cast<Pacer*>(new BbrPacedSender(&clock_, this, nullptr))
               : static_cast<Pacer*>(new PacedSender(&clock_, this, nullptr))) {
   modules_.push_back(pacer_.get());
-  pacer_->SetEstimatedBitrate(source->bits_per_second());
+  pacer_->SetPacingRates(source->bits_per_second() * kPaceMultiplier, 0);
 }
 
 PacedVideoSender::~PacedVideoSender() {
@@ -312,7 +315,7 @@
                                         uint8_t fraction_lost,
                                         int64_t rtt) {
   VideoSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
-  pacer_->SetEstimatedBitrate(target_bitrate_bps);
+  pacer_->SetPacingRates(target_bitrate_bps * kPaceMultiplier, 0);
 }
 
 void PacedVideoSender::OnNetworkChanged(uint32_t bitrate_for_encoder_bps,
diff --git a/rtc_tools/BUILD.gn b/rtc_tools/BUILD.gn
index f04bd2d..32a594b 100644
--- a/rtc_tools/BUILD.gn
+++ b/rtc_tools/BUILD.gn
@@ -231,7 +231,6 @@
         "../modules/audio_coding:ana_debug_dump_proto",
         "../modules/audio_coding:audio_network_adaptor",
         "../modules/audio_coding:neteq_tools",
-        "../modules/congestion_controller:estimators",
         "../modules/rtp_rtcp:rtp_rtcp_format",
         "../rtc_base:checks",
         "../rtc_base:rtc_base_approved",
@@ -240,6 +239,8 @@
         # TODO(kwiberg): Remove this dependency.
         "../api/audio_codecs:audio_codecs_api",
         "../modules/congestion_controller",
+        "../modules/congestion_controller:delay_based_bwe",
+        "../modules/congestion_controller:estimators",
         "../modules/pacing",
         "../modules/rtp_rtcp",
         "../system_wrappers:system_wrappers_default",
diff --git a/rtc_tools/event_log_visualizer/analyzer.cc b/rtc_tools/event_log_visualizer/analyzer.cc
index c32c676..0310cd2 100644
--- a/rtc_tools/event_log_visualizer/analyzer.cc
+++ b/rtc_tools/event_log_visualizer/analyzer.cc
@@ -33,6 +33,7 @@
 #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
 #include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
 #include "modules/congestion_controller/bitrate_estimator.h"
+#include "modules/congestion_controller/delay_based_bwe.h"
 #include "modules/congestion_controller/include/receive_side_congestion_controller.h"
 #include "modules/congestion_controller/include/send_side_congestion_controller.h"
 #include "modules/include/module_common_types.h"
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index 3d59bc2..765ec42 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -839,7 +839,7 @@
     }
     if (alr_settings) {
       transport->send_side_cc()->EnablePeriodicAlrProbing(true);
-      transport->pacer()->SetPacingFactor(alr_settings->pacing_factor);
+      transport->send_side_cc()->SetPacingFactor(alr_settings->pacing_factor);
       configured_pacing_factor_ = alr_settings->pacing_factor;
       transport->pacer()->SetQueueTimeLimit(alr_settings->max_paced_queue_time);
     }