Reland "Moved congestion controller to goog_cc folder."

This is a reland of e6cefdf9c572cdce55ff0497ad6e516c76132ee8.

Original change's description:
> Moved congestion controller to goog_cc folder.
> 
> Bug: webrtc:8415
> Change-Id: I2070da0cacf1dbfc4b6a89285af3e68fd03497ab
> Reviewed-on: https://webrtc-review.googlesource.com/43841
> 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@{#21928}

Bug: webrtc:8415
Change-Id: Ib5cf8641466655d64ac80f720561817f4cab49a9
Reviewed-on: https://webrtc-review.googlesource.com/53062
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22244}
diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn
new file mode 100644
index 0000000..bc17af1
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/BUILD.gn
@@ -0,0 +1,164 @@
+# 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")
+
+config("bwe_test_logging") {
+  if (rtc_enable_bwe_test_logging) {
+    defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=1" ]
+  } else {
+    defines = [ "BWE_TEST_LOGGING_COMPILE_TIME_ENABLE=0" ]
+  }
+}
+
+rtc_static_library("goog_cc") {
+  configs += [ ":bwe_test_logging" ]
+  sources = [
+    "alr_detector.cc",
+    "alr_detector.h",
+    "goog_cc_factory.cc",
+    "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 = [
+    "acknowledged_bitrate_estimator.cc",
+    "acknowledged_bitrate_estimator.h",
+    "bitrate_estimator.cc",
+    "bitrate_estimator.h",
+    "delay_increase_detector_interface.h",
+    "median_slope_estimator.cc",
+    "median_slope_estimator.h",
+    "probe_bitrate_estimator.cc",
+    "probe_bitrate_estimator.h",
+    "trendline_estimator.cc",
+    "trendline_estimator.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 = [
+    "../../../api:optional",
+    "../../../logging:rtc_event_bwe",
+    "../../../logging:rtc_event_log_api",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base:rtc_numerics",
+    "../../../system_wrappers:field_trial_api",
+    "../../../system_wrappers:metrics_api",
+    "../../remote_bitrate_estimator",
+    "../../rtp_rtcp:rtp_rtcp_format",
+  ]
+}
+
+rtc_source_set("delay_based_bwe") {
+  configs += [ ":bwe_test_logging" ]
+  sources = [
+    "delay_based_bwe.cc",
+    "delay_based_bwe.h",
+  ]
+
+  deps = [
+    ":estimators",
+    "../../../:typedefs",
+    "../../../logging:rtc_event_bwe",
+    "../../../logging:rtc_event_log_api",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../system_wrappers:field_trial_api",
+    "../../../system_wrappers:metrics_api",
+    "../../pacing",
+    "../../remote_bitrate_estimator",
+  ]
+
+  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" ]
+  }
+}
+
+if (rtc_include_tests) {
+  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",
+      "//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" ]
+    }
+  }
+}
diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc
new file mode 100644
index 0000000..7e1855d
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.cc
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2017 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/acknowledged_bitrate_estimator.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/ptr_util.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+bool IsInSendTimeHistory(const PacketFeedback& packet) {
+  return packet.send_time_ms != PacketFeedback::kNoSendTime;
+}
+}  // namespace
+
+AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator()
+    : AcknowledgedBitrateEstimator(rtc::MakeUnique<BitrateEstimator>()) {}
+
+AcknowledgedBitrateEstimator::~AcknowledgedBitrateEstimator() {}
+
+AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator(
+    std::unique_ptr<BitrateEstimator> bitrate_estimator)
+    : bitrate_estimator_(std::move(bitrate_estimator)) {}
+
+void AcknowledgedBitrateEstimator::IncomingPacketFeedbackVector(
+    const std::vector<PacketFeedback>& packet_feedback_vector) {
+  RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
+                            packet_feedback_vector.end(),
+                            PacketFeedbackComparator()));
+  for (const auto& packet : packet_feedback_vector) {
+    if (IsInSendTimeHistory(packet)) {
+      MaybeExpectFastRateChange(packet.send_time_ms);
+      bitrate_estimator_->Update(packet.arrival_time_ms,
+                                 rtc::dchecked_cast<int>(packet.payload_size));
+    }
+  }
+}
+
+rtc::Optional<uint32_t> AcknowledgedBitrateEstimator::bitrate_bps() const {
+  return bitrate_estimator_->bitrate_bps();
+}
+
+void AcknowledgedBitrateEstimator::SetAlrEndedTimeMs(
+    int64_t alr_ended_time_ms) {
+  alr_ended_time_ms_.emplace(alr_ended_time_ms);
+}
+
+void AcknowledgedBitrateEstimator::MaybeExpectFastRateChange(
+    int64_t packet_send_time_ms) {
+  if (alr_ended_time_ms_ && packet_send_time_ms > *alr_ended_time_ms_) {
+    bitrate_estimator_->ExpectFastRateChange();
+    alr_ended_time_ms_.reset();
+  }
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h
new file mode 100644
index 0000000..f584792
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2017 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_ACKNOWLEDGED_BITRATE_ESTIMATOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/optional.h"
+#include "modules/congestion_controller/goog_cc/bitrate_estimator.h"
+
+namespace webrtc {
+
+struct PacketFeedback;
+
+namespace webrtc_cc {
+
+class AcknowledgedBitrateEstimator {
+ public:
+  explicit AcknowledgedBitrateEstimator(
+      std::unique_ptr<BitrateEstimator> bitrate_estimator);
+
+  AcknowledgedBitrateEstimator();
+  ~AcknowledgedBitrateEstimator();
+
+  void IncomingPacketFeedbackVector(
+      const std::vector<PacketFeedback>& packet_feedback_vector);
+  rtc::Optional<uint32_t> bitrate_bps() const;
+  void SetAlrEndedTimeMs(int64_t alr_ended_time_ms);
+
+ private:
+  void MaybeExpectFastRateChange(int64_t packet_arrival_time_ms);
+  rtc::Optional<int64_t> alr_ended_time_ms_;
+  std::unique_ptr<BitrateEstimator> bitrate_estimator_;
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_H_
diff --git a/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc
new file mode 100644
index 0000000..f8f5025
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ *  Copyright (c) 2017 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/acknowledged_bitrate_estimator.h"
+
+#include <utility>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "rtc_base/fakeclock.h"
+#include "rtc_base/ptr_util.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using testing::_;
+using testing::NiceMock;
+using testing::InSequence;
+using testing::Return;
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+
+constexpr int64_t kFirstArrivalTimeMs = 10;
+constexpr int64_t kFirstSendTimeMs = 10;
+constexpr uint16_t kSequenceNumber = 1;
+constexpr size_t kPayloadSize = 10;
+
+class MockBitrateEstimator : public BitrateEstimator {
+ public:
+  MOCK_METHOD2(Update, void(int64_t now_ms, int bytes));
+  MOCK_CONST_METHOD0(bitrate_bps, rtc::Optional<uint32_t>());
+  MOCK_METHOD0(ExpectFastRateChange, void());
+};
+
+struct AcknowledgedBitrateEstimatorTestStates {
+  std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator;
+  MockBitrateEstimator* mock_bitrate_estimator;
+};
+
+AcknowledgedBitrateEstimatorTestStates CreateTestStates() {
+  AcknowledgedBitrateEstimatorTestStates states;
+  auto mock_bitrate_estimator = rtc::MakeUnique<MockBitrateEstimator>();
+  states.mock_bitrate_estimator = mock_bitrate_estimator.get();
+  states.acknowledged_bitrate_estimator =
+      rtc::MakeUnique<AcknowledgedBitrateEstimator>(
+          std::move(mock_bitrate_estimator));
+  return states;
+}
+
+std::vector<PacketFeedback> CreateFeedbackVector() {
+  std::vector<PacketFeedback> packet_feedback_vector;
+  const PacedPacketInfo pacing_info;
+  packet_feedback_vector.push_back(
+      PacketFeedback(kFirstArrivalTimeMs, kFirstSendTimeMs, kSequenceNumber,
+                     kPayloadSize, pacing_info));
+  packet_feedback_vector.push_back(
+      PacketFeedback(kFirstArrivalTimeMs + 10, kFirstSendTimeMs + 10,
+                     kSequenceNumber, kPayloadSize + 10, pacing_info));
+  return packet_feedback_vector;
+}
+
+}  // anonymous namespace
+
+TEST(TestAcknowledgedBitrateEstimator, DontAddPacketsWhichAreNotInSendHistory) {
+  auto states = CreateTestStates();
+  std::vector<PacketFeedback> packet_feedback_vector;
+  packet_feedback_vector.push_back(
+      PacketFeedback(kFirstArrivalTimeMs, kSequenceNumber));
+  EXPECT_CALL(*states.mock_bitrate_estimator, Update(_, _)).Times(0);
+  states.acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
+      packet_feedback_vector);
+}
+
+TEST(TestAcknowledgedBitrateEstimator, UpdateBandwith) {
+  auto states = CreateTestStates();
+  auto packet_feedback_vector = CreateFeedbackVector();
+  {
+    InSequence dummy;
+    EXPECT_CALL(
+        *states.mock_bitrate_estimator,
+        Update(packet_feedback_vector[0].arrival_time_ms,
+               static_cast<int>(packet_feedback_vector[0].payload_size)))
+        .Times(1);
+    EXPECT_CALL(
+        *states.mock_bitrate_estimator,
+        Update(packet_feedback_vector[1].arrival_time_ms,
+               static_cast<int>(packet_feedback_vector[1].payload_size)))
+        .Times(1);
+  }
+  states.acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
+      packet_feedback_vector);
+}
+
+TEST(TestAcknowledgedBitrateEstimator, ExpectFastRateChangeWhenLeftAlr) {
+  auto states = CreateTestStates();
+  auto packet_feedback_vector = CreateFeedbackVector();
+  {
+    InSequence dummy;
+    EXPECT_CALL(
+        *states.mock_bitrate_estimator,
+        Update(packet_feedback_vector[0].arrival_time_ms,
+               static_cast<int>(packet_feedback_vector[0].payload_size)))
+        .Times(1);
+    EXPECT_CALL(*states.mock_bitrate_estimator, ExpectFastRateChange())
+        .Times(1);
+    EXPECT_CALL(
+        *states.mock_bitrate_estimator,
+        Update(packet_feedback_vector[1].arrival_time_ms,
+               static_cast<int>(packet_feedback_vector[1].payload_size)))
+        .Times(1);
+  }
+  states.acknowledged_bitrate_estimator->SetAlrEndedTimeMs(kFirstArrivalTimeMs +
+                                                           1);
+  states.acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
+      packet_feedback_vector);
+}
+
+TEST(TestAcknowledgedBitrateEstimator, ReturnBitrate) {
+  auto states = CreateTestStates();
+  rtc::Optional<uint32_t> return_value(42);
+  EXPECT_CALL(*states.mock_bitrate_estimator, bitrate_bps())
+      .Times(1)
+      .WillOnce(Return(return_value));
+  EXPECT_EQ(return_value, states.acknowledged_bitrate_estimator->bitrate_bps());
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc*/
diff --git a/modules/congestion_controller/goog_cc/alr_detector.cc b/modules/congestion_controller/goog_cc/alr_detector.cc
new file mode 100644
index 0000000..f36b1f9
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/alr_detector.cc
@@ -0,0 +1,97 @@
+/*
+ *  Copyright (c) 2016 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/alr_detector.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <string>
+
+#include "logging/rtc_event_log/events/rtc_event_alr_state.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/experiments/alr_experiment.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 webrtc_cc {
+AlrDetector::AlrDetector() : AlrDetector(nullptr) {}
+
+AlrDetector::AlrDetector(RtcEventLog* event_log)
+    : bandwidth_usage_percent_(kDefaultAlrBandwidthUsagePercent),
+      alr_start_budget_level_percent_(kDefaultAlrStartBudgetLevelPercent),
+      alr_stop_budget_level_percent_(kDefaultAlrStopBudgetLevelPercent),
+      alr_budget_(0, true),
+      event_log_(event_log) {
+  RTC_CHECK(AlrExperimentSettings::MaxOneFieldTrialEnabled());
+  rtc::Optional<AlrExperimentSettings> experiment_settings =
+      AlrExperimentSettings::CreateFromFieldTrial(
+          AlrExperimentSettings::kScreenshareProbingBweExperimentName);
+  if (!experiment_settings) {
+    experiment_settings = AlrExperimentSettings::CreateFromFieldTrial(
+        AlrExperimentSettings::kStrictPacingAndProbingExperimentName);
+  }
+  if (experiment_settings) {
+    alr_stop_budget_level_percent_ =
+        experiment_settings->alr_stop_budget_level_percent;
+    alr_start_budget_level_percent_ =
+        experiment_settings->alr_start_budget_level_percent;
+    bandwidth_usage_percent_ = experiment_settings->alr_bandwidth_usage_percent;
+  }
+}
+
+AlrDetector::~AlrDetector() {}
+
+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;
+  if (alr_budget_.budget_level_percent() > alr_start_budget_level_percent_ &&
+      !alr_started_time_ms_) {
+    alr_started_time_ms_.emplace(rtc::TimeMillis());
+    state_changed = true;
+  } else if (alr_budget_.budget_level_percent() <
+                 alr_stop_budget_level_percent_ &&
+             alr_started_time_ms_) {
+    state_changed = true;
+    alr_started_time_ms_.reset();
+  }
+  if (event_log_ && state_changed) {
+    event_log_->Log(
+        rtc::MakeUnique<RtcEventAlrState>(alr_started_time_ms_.has_value()));
+  }
+}
+
+void AlrDetector::SetEstimatedBitrate(int bitrate_bps) {
+  RTC_DCHECK(bitrate_bps);
+  const auto target_rate_kbps = static_cast<int64_t>(bitrate_bps) *
+                                bandwidth_usage_percent_ / (1000 * 100);
+  alr_budget_.set_target_rate_kbps(rtc::dchecked_cast<int>(target_rate_kbps));
+}
+
+rtc::Optional<int64_t> AlrDetector::GetApplicationLimitedRegionStartTime()
+    const {
+  return alr_started_time_ms_;
+}
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/alr_detector.h b/modules/congestion_controller/goog_cc/alr_detector.h
new file mode 100644
index 0000000..98293a7
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/alr_detector.h
@@ -0,0 +1,77 @@
+/*
+ *  Copyright (c) 2016 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_ALR_DETECTOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ALR_DETECTOR_H_
+
+#include "api/optional.h"
+#include "common_types.h"  // NOLINT(build/include)
+#include "modules/pacing/interval_budget.h"
+#include "modules/pacing/paced_sender.h"
+#include "rtc_base/rate_statistics.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace webrtc {
+
+class RtcEventLog;
+
+namespace webrtc_cc {
+
+// Application limited region detector is a class that utilizes signals of
+// elapsed time and bytes sent to estimate whether network traffic is
+// currently limited by the application's ability to generate traffic.
+//
+// AlrDetector provides a signal that can be utilized to adjust
+// estimate bandwidth.
+// Note: This class is not thread-safe.
+class AlrDetector {
+ public:
+  AlrDetector();
+  explicit AlrDetector(RtcEventLog* event_log);
+  ~AlrDetector();
+
+  void OnBytesSent(size_t bytes_sent, int64_t send_time_ms);
+
+  // Set current estimated bandwidth.
+  void SetEstimatedBitrate(int bitrate_bps);
+
+  // Returns time in milliseconds when the current application-limited region
+  // started or empty result if the sender is currently not application-limited.
+  rtc::Optional<int64_t> GetApplicationLimitedRegionStartTime() const;
+
+  // Sent traffic percentage as a function of network capacity used to determine
+  // application-limited region. ALR region start when bandwidth usage drops
+  // below kAlrStartUsagePercent and ends when it raises above
+  // kAlrEndUsagePercent. NOTE: This is intentionally conservative at the moment
+  // until BW adjustments of application limited region is fine tuned.
+  static constexpr int kDefaultAlrBandwidthUsagePercent = 65;
+  static constexpr int kDefaultAlrStartBudgetLevelPercent = 80;
+  static constexpr int kDefaultAlrStopBudgetLevelPercent = 50;
+
+  void UpdateBudgetWithElapsedTime(int64_t delta_time_ms);
+  void UpdateBudgetWithBytesSent(size_t bytes_sent);
+
+ private:
+  int bandwidth_usage_percent_;
+  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_;
+
+  RtcEventLog* event_log_;
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ALR_DETECTOR_H_
diff --git a/modules/congestion_controller/goog_cc/alr_detector_unittest.cc b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc
new file mode 100644
index 0000000..9aeab51
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc
@@ -0,0 +1,177 @@
+/*
+ *  Copyright (c) 2016 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/alr_detector.h"
+
+#include "rtc_base/experiments/alr_experiment.h"
+#include "test/field_trial.h"
+#include "test/gtest.h"
+
+namespace {
+
+constexpr int kEstimatedBitrateBps = 300000;
+
+}  // namespace
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+class SimulateOutgoingTrafficIn {
+ public:
+  explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector,
+                                     int64_t* timestamp_ms)
+      : alr_detector_(alr_detector), timestamp_ms_(timestamp_ms) {
+    RTC_CHECK(alr_detector_);
+  }
+
+  SimulateOutgoingTrafficIn& ForTimeMs(int time_ms) {
+    interval_ms_ = time_ms;
+    ProduceTraffic();
+    return *this;
+  }
+
+  SimulateOutgoingTrafficIn& AtPercentOfEstimatedBitrate(int usage_percentage) {
+    usage_percentage_.emplace(usage_percentage);
+    ProduceTraffic();
+    return *this;
+  }
+
+ private:
+  void ProduceTraffic() {
+    if (!interval_ms_ || !usage_percentage_)
+      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),
+                                 *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),
+                                 *timestamp_ms_);
+    }
+  }
+  AlrDetector* const alr_detector_;
+  int64_t* timestamp_ms_;
+  rtc::Optional<int> interval_ms_;
+  rtc::Optional<int> usage_percentage_;
+};
+}  // namespace
+
+class AlrDetectorTest : public testing::Test {
+ public:
+  void SetUp() override {
+    alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps);
+  }
+
+ protected:
+  AlrDetector alr_detector_;
+  int64_t timestamp_ms_ = 1000;
+};
+
+TEST_F(AlrDetectorTest, AlrDetection) {
+  // Start in non-ALR state.
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // Stay in non-ALR state when usage is close to 100%.
+  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_, &timestamp_ms_)
+      .ForTimeMs(1500)
+      .AtPercentOfEstimatedBitrate(20);
+  EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // Verify that ALR ends when usage is above 65%.
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
+      .ForTimeMs(4000)
+      .AtPercentOfEstimatedBitrate(100);
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+}
+
+TEST_F(AlrDetectorTest, ShortSpike) {
+  // Start in non-ALR state.
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // Verify that we ALR starts when bitrate drops below 20%.
+  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_, &timestamp_ms_)
+      .ForTimeMs(100)
+      .AtPercentOfEstimatedBitrate(150);
+  EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // ALR ends when usage is above 65%.
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
+      .ForTimeMs(3000)
+      .AtPercentOfEstimatedBitrate(100);
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+}
+
+TEST_F(AlrDetectorTest, BandwidthEstimateChanges) {
+  // Start in non-ALR state.
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // ALR starts when bitrate drops below 20%.
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
+      .ForTimeMs(1000)
+      .AtPercentOfEstimatedBitrate(20);
+  EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
+
+  // When bandwidth estimate drops the detector should stay in ALR mode and quit
+  // it shortly afterwards as the sender continues sending the same amount of
+  // traffic. This is necessary to ensure that ProbeController can still react
+  // to the BWE drop by initiating a new probe.
+  alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5);
+  EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
+  SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
+      .ForTimeMs(1000)
+      .AtPercentOfEstimatedBitrate(50);
+  EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
+}
+
+TEST_F(AlrDetectorTest, ParseControlFieldTrial) {
+  webrtc::test::ScopedFieldTrials field_trial(
+      "WebRTC-ProbingScreenshareBwe/Control/");
+  rtc::Optional<AlrExperimentSettings> parsed_params =
+      AlrExperimentSettings::CreateFromFieldTrial(
+          "WebRTC-ProbingScreenshareBwe");
+  EXPECT_FALSE(static_cast<bool>(parsed_params));
+}
+
+TEST_F(AlrDetectorTest, ParseActiveFieldTrial) {
+  webrtc::test::ScopedFieldTrials field_trial(
+      "WebRTC-ProbingScreenshareBwe/1.1,2875,85,20,-20,1/");
+  rtc::Optional<AlrExperimentSettings> parsed_params =
+      AlrExperimentSettings::CreateFromFieldTrial(
+          "WebRTC-ProbingScreenshareBwe");
+  ASSERT_TRUE(static_cast<bool>(parsed_params));
+  EXPECT_EQ(1.1f, parsed_params->pacing_factor);
+  EXPECT_EQ(2875, parsed_params->max_paced_queue_time);
+  EXPECT_EQ(85, parsed_params->alr_bandwidth_usage_percent);
+  EXPECT_EQ(20, parsed_params->alr_start_budget_level_percent);
+  EXPECT_EQ(-20, parsed_params->alr_stop_budget_level_percent);
+  EXPECT_EQ(1, parsed_params->group_id);
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.cc b/modules/congestion_controller/goog_cc/bitrate_estimator.cc
new file mode 100644
index 0000000..2cd5331
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/bitrate_estimator.cc
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (c) 2017 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/bitrate_estimator.h"
+
+#include <cmath>
+
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+constexpr int kInitialRateWindowMs = 500;
+constexpr int kRateWindowMs = 150;
+}  // namespace
+
+BitrateEstimator::BitrateEstimator()
+    : sum_(0),
+      current_win_ms_(0),
+      prev_time_ms_(-1),
+      bitrate_estimate_(-1.0f),
+      bitrate_estimate_var_(50.0f) {}
+
+BitrateEstimator::~BitrateEstimator() = default;
+
+void BitrateEstimator::Update(int64_t now_ms, int bytes) {
+  int rate_window_ms = kRateWindowMs;
+  // We use a larger window at the beginning to get a more stable sample that
+  // we can use to initialize the estimate.
+  if (bitrate_estimate_ < 0.f)
+    rate_window_ms = kInitialRateWindowMs;
+  float bitrate_sample = UpdateWindow(now_ms, bytes, rate_window_ms);
+  if (bitrate_sample < 0.0f)
+    return;
+  if (bitrate_estimate_ < 0.0f) {
+    // This is the very first sample we get. Use it to initialize the estimate.
+    bitrate_estimate_ = bitrate_sample;
+    return;
+  }
+  // Define the sample uncertainty as a function of how far away it is from the
+  // current estimate.
+  float sample_uncertainty =
+      10.0f * std::abs(bitrate_estimate_ - bitrate_sample) / bitrate_estimate_;
+  float sample_var = sample_uncertainty * sample_uncertainty;
+  // Update a bayesian estimate of the rate, weighting it lower if the sample
+  // uncertainty is large.
+  // The bitrate estimate uncertainty is increased with each update to model
+  // that the bitrate changes over time.
+  float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f;
+  bitrate_estimate_ = (sample_var * bitrate_estimate_ +
+                       pred_bitrate_estimate_var * bitrate_sample) /
+                      (sample_var + pred_bitrate_estimate_var);
+  bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var /
+                          (sample_var + pred_bitrate_estimate_var);
+  BWE_TEST_LOGGING_PLOT(1, "acknowledged_bitrate", now_ms,
+                        bitrate_estimate_ * 1000);
+}
+
+float BitrateEstimator::UpdateWindow(int64_t now_ms,
+                                     int bytes,
+                                     int rate_window_ms) {
+  // Reset if time moves backwards.
+  if (now_ms < prev_time_ms_) {
+    prev_time_ms_ = -1;
+    sum_ = 0;
+    current_win_ms_ = 0;
+  }
+  if (prev_time_ms_ >= 0) {
+    current_win_ms_ += now_ms - prev_time_ms_;
+    // Reset if nothing has been received for more than a full window.
+    if (now_ms - prev_time_ms_ > rate_window_ms) {
+      sum_ = 0;
+      current_win_ms_ %= rate_window_ms;
+    }
+  }
+  prev_time_ms_ = now_ms;
+  float bitrate_sample = -1.0f;
+  if (current_win_ms_ >= rate_window_ms) {
+    bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms);
+    current_win_ms_ -= rate_window_ms;
+    sum_ = 0;
+  }
+  sum_ += bytes;
+  return bitrate_sample;
+}
+
+rtc::Optional<uint32_t> BitrateEstimator::bitrate_bps() const {
+  if (bitrate_estimate_ < 0.f)
+    return rtc::nullopt;
+  return bitrate_estimate_ * 1000;
+}
+
+void BitrateEstimator::ExpectFastRateChange() {
+  // By setting the bitrate-estimate variance to a higher value we allow the
+  // bitrate to change fast for the next few samples.
+  bitrate_estimate_var_ += 200;
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/bitrate_estimator.h b/modules/congestion_controller/goog_cc/bitrate_estimator.h
new file mode 100644
index 0000000..ca5a40e
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/bitrate_estimator.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2017 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_BITRATE_ESTIMATOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_BITRATE_ESTIMATOR_H_
+
+#include <vector>
+
+#include "api/optional.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+// Computes a bayesian estimate of the throughput given acks containing
+// the arrival time and payload size. Samples which are far from the current
+// estimate or are based on few packets are given a smaller weight, as they
+// are considered to be more likely to have been caused by, e.g., delay spikes
+// unrelated to congestion.
+class BitrateEstimator {
+ public:
+  BitrateEstimator();
+  virtual ~BitrateEstimator();
+  virtual void Update(int64_t now_ms, int bytes);
+
+  virtual rtc::Optional<uint32_t> bitrate_bps() const;
+
+  virtual void ExpectFastRateChange();
+
+ private:
+  float UpdateWindow(int64_t now_ms, int bytes, int rate_window_ms);
+  int sum_;
+  int64_t current_win_ms_;
+  int64_t prev_time_ms_;
+  float bitrate_estimate_;
+  float bitrate_estimate_var_;
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_BITRATE_ESTIMATOR_H_
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
new file mode 100644
index 0000000..fea5a66
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
@@ -0,0 +1,331 @@
+/*
+ *  Copyright (c) 2016 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/delay_based_bwe.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdio>
+#include <string>
+
+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "modules/congestion_controller/goog_cc/trendline_estimator.h"
+#include "modules/pacing/paced_sender.h"
+#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/ptr_util.h"
+#include "rtc_base/thread_annotations.h"
+#include "system_wrappers/include/field_trial.h"
+#include "system_wrappers/include/metrics.h"
+#include "typedefs.h"  // NOLINT(build/include)
+
+namespace {
+constexpr int kTimestampGroupLengthMs = 5;
+constexpr int kAbsSendTimeFraction = 18;
+constexpr int kAbsSendTimeInterArrivalUpshift = 8;
+constexpr int kInterArrivalShift =
+    kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
+constexpr double kTimestampToMs =
+    1000.0 / static_cast<double>(1 << kInterArrivalShift);
+// This ssrc is used to fulfill the current API but will be removed
+// after the API has been changed.
+constexpr uint32_t kFixedSsrc = 0;
+
+// Parameters for linear least squares fit of regression line to noisy data.
+constexpr size_t kDefaultTrendlineWindowSize = 20;
+constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
+constexpr double kDefaultTrendlineThresholdGain = 4.0;
+
+constexpr int kMaxConsecutiveFailedLookups = 5;
+
+const char kBweWindowSizeInPacketsExperiment[] =
+    "WebRTC-BweWindowSizeInPackets";
+
+size_t ReadTrendlineFilterWindowSize() {
+  std::string experiment_string =
+      webrtc::field_trial::FindFullName(kBweWindowSizeInPacketsExperiment);
+  size_t window_size;
+  int parsed_values =
+      sscanf(experiment_string.c_str(), "Enabled-%zu", &window_size);
+  if (parsed_values == 1) {
+    if (window_size > 1)
+      return window_size;
+    RTC_LOG(WARNING) << "Window size must be greater than 1.";
+  }
+  RTC_LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter "
+                         "experiment from field trial string. Using default.";
+  return kDefaultTrendlineWindowSize;
+}
+}  // namespace
+
+namespace webrtc {
+namespace webrtc_cc {
+
+DelayBasedBwe::Result::Result()
+    : updated(false),
+      probe(false),
+      target_bitrate_bps(0),
+      recovered_from_overuse(false) {}
+
+DelayBasedBwe::Result::Result(bool probe, uint32_t target_bitrate_bps)
+    : updated(true),
+      probe(probe),
+      target_bitrate_bps(target_bitrate_bps),
+      recovered_from_overuse(false) {}
+
+DelayBasedBwe::Result::~Result() {}
+
+DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log)
+    : event_log_(event_log),
+      inter_arrival_(),
+      delay_detector_(),
+      last_seen_packet_ms_(-1),
+      uma_recorded_(false),
+      probe_bitrate_estimator_(event_log),
+      trendline_window_size_(
+          webrtc::field_trial::IsEnabled(kBweWindowSizeInPacketsExperiment)
+              ? ReadTrendlineFilterWindowSize()
+              : kDefaultTrendlineWindowSize),
+      trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff),
+      trendline_threshold_gain_(kDefaultTrendlineThresholdGain),
+      consecutive_delayed_feedbacks_(0),
+      prev_bitrate_(0),
+      prev_state_(BandwidthUsage::kBwNormal) {
+  RTC_LOG(LS_INFO)
+      << "Using Trendline filter for delay change estimation with window size "
+      << trendline_window_size_;
+  delay_detector_.reset(new TrendlineEstimator(trendline_window_size_,
+                                               trendline_smoothing_coeff_,
+                                               trendline_threshold_gain_));
+}
+
+DelayBasedBwe::~DelayBasedBwe() {}
+
+DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
+    const std::vector<PacketFeedback>& packet_feedback_vector,
+    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()));
+  RTC_DCHECK_RUNS_SERIALIZED(&network_race_);
+
+  // TOOD(holmer): An empty feedback vector here likely means that
+  // all acks were too late and that the send time history had
+  // timed out. We should reduce the rate when this occurs.
+  if (packet_feedback_vector.empty()) {
+    RTC_LOG(LS_WARNING) << "Very late feedback received.";
+    return DelayBasedBwe::Result();
+  }
+
+  if (!uma_recorded_) {
+    RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
+                              BweNames::kSendSideTransportSeqNum,
+                              BweNames::kBweNamesMax);
+    uma_recorded_ = true;
+  }
+  bool delayed_feedback = true;
+  bool recovered_from_overuse = false;
+  BandwidthUsage prev_detector_state = delay_detector_->State();
+  for (const auto& packet_feedback : packet_feedback_vector) {
+    if (packet_feedback.send_time_ms < 0)
+      continue;
+    delayed_feedback = false;
+    IncomingPacketFeedback(packet_feedback, at_time_ms);
+    if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
+        delay_detector_->State() == BandwidthUsage::kBwNormal) {
+      recovered_from_overuse = true;
+    }
+    prev_detector_state = delay_detector_->State();
+  }
+
+  if (delayed_feedback) {
+    ++consecutive_delayed_feedbacks_;
+    if (consecutive_delayed_feedbacks_ >= kMaxConsecutiveFailedLookups) {
+      consecutive_delayed_feedbacks_ = 0;
+      return OnLongFeedbackDelay(packet_feedback_vector.back().arrival_time_ms);
+    }
+  } else {
+    consecutive_delayed_feedbacks_ = 0;
+    return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse,
+                               at_time_ms);
+  }
+  return Result();
+}
+
+DelayBasedBwe::Result DelayBasedBwe::OnLongFeedbackDelay(
+    int64_t arrival_time_ms) {
+  // Estimate should always be valid since a start bitrate always is set in the
+  // Call constructor. An alternative would be to return an empty Result here,
+  // or to estimate the throughput based on the feedback we received.
+  RTC_DCHECK(rate_control_.ValidEstimate());
+  rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2,
+                            arrival_time_ms);
+  Result result;
+  result.updated = true;
+  result.probe = false;
+  result.target_bitrate_bps = rate_control_.LatestEstimate();
+  RTC_LOG(LS_WARNING) << "Long feedback delay detected, reducing BWE to "
+                      << result.target_bitrate_bps;
+  return result;
+}
+
+void DelayBasedBwe::IncomingPacketFeedback(
+    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) {
+    inter_arrival_.reset(
+        new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
+                         kTimestampToMs, true));
+    delay_detector_.reset(new TrendlineEstimator(trendline_window_size_,
+                                                 trendline_smoothing_coeff_,
+                                                 trendline_threshold_gain_));
+  }
+  last_seen_packet_ms_ = now_ms;
+
+  uint32_t send_time_24bits =
+      static_cast<uint32_t>(
+          ((static_cast<uint64_t>(packet_feedback.send_time_ms)
+            << kAbsSendTimeFraction) +
+           500) /
+          1000) &
+      0x00FFFFFF;
+  // Shift up send time to use the full 32 bits that inter_arrival works with,
+  // so wrapping works properly.
+  uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
+
+  uint32_t ts_delta = 0;
+  int64_t t_delta = 0;
+  int size_delta = 0;
+  if (inter_arrival_->ComputeDeltas(timestamp, packet_feedback.arrival_time_ms,
+                                    now_ms, packet_feedback.payload_size,
+                                    &ts_delta, &t_delta, &size_delta)) {
+    double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
+    delay_detector_->Update(t_delta, ts_delta_ms,
+                            packet_feedback.arrival_time_ms);
+  }
+  if (packet_feedback.pacing_info.probe_cluster_id !=
+      PacedPacketInfo::kNotAProbe) {
+    probe_bitrate_estimator_.HandleProbeAndEstimateBitrate(packet_feedback);
+  }
+}
+
+DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
+    rtc::Optional<uint32_t> acked_bitrate_bps,
+    bool recovered_from_overuse,
+    int64_t at_time_ms) {
+  Result result;
+  int64_t now_ms = at_time_ms;
+
+  rtc::Optional<int> probe_bitrate_bps =
+      probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
+  // Currently overusing the bandwidth.
+  if (delay_detector_->State() == BandwidthUsage::kBwOverusing) {
+    if (acked_bitrate_bps &&
+        rate_control_.TimeToReduceFurther(now_ms, *acked_bitrate_bps)) {
+      result.updated =
+          UpdateEstimate(now_ms, acked_bitrate_bps, &result.target_bitrate_bps);
+    } else if (!acked_bitrate_bps && rate_control_.ValidEstimate() &&
+               rate_control_.TimeToReduceFurther(
+                   now_ms, rate_control_.LatestEstimate() / 2 - 1)) {
+      // Overusing before we have a measured acknowledged bitrate. We check
+      // TimeToReduceFurther (with a fake acknowledged bitrate) to avoid
+      // reducing too often.
+      // TODO(tschumim): Improve this and/or the acknowledged bitrate estimator
+      // so that we (almost) always have a bitrate estimate.
+      rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, now_ms);
+      result.updated = true;
+      result.probe = false;
+      result.target_bitrate_bps = rate_control_.LatestEstimate();
+    }
+  } else {
+    if (probe_bitrate_bps) {
+      result.probe = true;
+      result.updated = true;
+      result.target_bitrate_bps = *probe_bitrate_bps;
+      rate_control_.SetEstimate(*probe_bitrate_bps, now_ms);
+    } else {
+      result.updated =
+          UpdateEstimate(now_ms, acked_bitrate_bps, &result.target_bitrate_bps);
+      result.recovered_from_overuse = recovered_from_overuse;
+    }
+  }
+  BandwidthUsage detector_state = delay_detector_->State();
+  if ((result.updated && prev_bitrate_ != result.target_bitrate_bps) ||
+      detector_state != prev_state_) {
+    uint32_t bitrate_bps =
+        result.updated ? result.target_bitrate_bps : prev_bitrate_;
+
+    BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", now_ms, bitrate_bps);
+
+    if (event_log_) {
+      event_log_->Log(rtc::MakeUnique<RtcEventBweUpdateDelayBased>(
+          bitrate_bps, detector_state));
+    }
+
+    prev_bitrate_ = bitrate_bps;
+    prev_state_ = detector_state;
+  }
+  return result;
+}
+
+bool DelayBasedBwe::UpdateEstimate(int64_t now_ms,
+                                   rtc::Optional<uint32_t> acked_bitrate_bps,
+                                   uint32_t* target_bitrate_bps) {
+  // TODO(terelius): RateControlInput::noise_var is deprecated and will be
+  // removed. In the meantime, we set it to zero.
+  const RateControlInput input(delay_detector_->State(), acked_bitrate_bps, 0);
+  *target_bitrate_bps = rate_control_.Update(&input, now_ms);
+  return rate_control_.ValidEstimate();
+}
+
+void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms) {
+  rate_control_.SetRtt(avg_rtt_ms);
+}
+
+bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
+                                   uint32_t* bitrate_bps) const {
+  // Currently accessed from both the process thread (see
+  // ModuleRtpRtcpImpl::Process()) and the configuration thread (see
+  // Call::GetStats()). Should in the future only be accessed from a single
+  // thread.
+  RTC_DCHECK(ssrcs);
+  RTC_DCHECK(bitrate_bps);
+  if (!rate_control_.ValidEstimate())
+    return false;
+
+  *ssrcs = {kFixedSsrc};
+  *bitrate_bps = rate_control_.LatestEstimate();
+  return true;
+}
+
+void DelayBasedBwe::SetStartBitrate(int start_bitrate_bps) {
+  RTC_LOG(LS_WARNING) << "BWE Setting start bitrate to: " << start_bitrate_bps;
+  rate_control_.SetStartBitrate(start_bitrate_bps);
+}
+
+void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
+  // Called from both the configuration thread and the network thread. Shouldn't
+  // be called from the network thread in the future.
+  rate_control_.SetMinBitrate(min_bitrate_bps);
+}
+
+int64_t DelayBasedBwe::GetExpectedBwePeriodMs() const {
+  return rate_control_.GetExpectedBandwidthPeriodMs();
+}
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.h b/modules/congestion_controller/goog_cc/delay_based_bwe.h
new file mode 100644
index 0000000..485f687
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe.h
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2016 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_DELAY_BASED_BWE_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h"
+#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h"
+#include "modules/remote_bitrate_estimator/aimd_rate_control.h"
+#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
+#include "modules/remote_bitrate_estimator/inter_arrival.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/race_checker.h"
+
+namespace webrtc {
+class RtcEventLog;
+
+namespace webrtc_cc {
+
+class DelayBasedBwe {
+ public:
+  static const int64_t kStreamTimeOutMs = 2000;
+
+  struct Result {
+    Result();
+    Result(bool probe, uint32_t target_bitrate_bps);
+    ~Result();
+    bool updated;
+    bool probe;
+    uint32_t target_bitrate_bps;
+    bool recovered_from_overuse;
+  };
+
+  explicit DelayBasedBwe(RtcEventLog* event_log);
+  virtual ~DelayBasedBwe();
+
+  Result IncomingPacketFeedbackVector(
+      const std::vector<PacketFeedback>& packet_feedback_vector,
+      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);
+  void SetMinBitrate(int min_bitrate_bps);
+  int64_t GetExpectedBwePeriodMs() const;
+
+ private:
+  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,
+                             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,
+                      rtc::Optional<uint32_t> acked_bitrate_bps,
+                      uint32_t* target_bitrate_bps);
+
+  rtc::RaceChecker network_race_;
+  RtcEventLog* const event_log_;
+  std::unique_ptr<InterArrival> inter_arrival_;
+  std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_;
+  int64_t last_seen_packet_ms_;
+  bool uma_recorded_;
+  AimdRateControl rate_control_;
+  ProbeBitrateEstimator probe_bitrate_estimator_;
+  size_t trendline_window_size_;
+  double trendline_smoothing_coeff_;
+  double trendline_threshold_gain_;
+  int consecutive_delayed_feedbacks_;
+  uint32_t prev_bitrate_;
+  BandwidthUsage prev_state_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe);
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc
new file mode 100644
index 0000000..b19e8f9
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc
@@ -0,0 +1,239 @@
+/*
+ *  Copyright (c) 2016 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/delay_based_bwe.h"
+#include "modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h"
+#include "modules/pacing/paced_sender.h"
+#include "rtc_base/constructormagic.h"
+#include "system_wrappers/include/clock.h"
+#include "test/field_trial.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+constexpr int kNumProbesCluster0 = 5;
+constexpr int kNumProbesCluster1 = 8;
+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, kDummyTimestamp);
+}
+
+TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
+  std::vector<PacketFeedback> packet_feedback_vector;
+  packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
+                                                  PacketFeedback::kNoSendTime,
+                                                  0, 1500, PacedPacketInfo()));
+  packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
+                                                  PacketFeedback::kNoSendTime,
+                                                  1, 1500, PacedPacketInfo()));
+  bitrate_estimator_->IncomingPacketFeedbackVector(
+      packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
+}
+
+TEST_F(DelayBasedBweTest, ProbeDetection) {
+  int64_t now_ms = clock_.TimeInMilliseconds();
+  uint16_t seq_num = 0;
+
+  // First burst sent at 8 * 1000 / 10 = 800 kbps.
+  for (int i = 0; i < kNumProbesCluster0; ++i) {
+    clock_.AdvanceTimeMilliseconds(10);
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo0);
+  }
+  EXPECT_TRUE(bitrate_observer_.updated());
+
+  // Second burst sent at 8 * 1000 / 5 = 1600 kbps.
+  for (int i = 0; i < kNumProbesCluster1; ++i) {
+    clock_.AdvanceTimeMilliseconds(5);
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo1);
+  }
+
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_GT(bitrate_observer_.latest_bitrate(), 1500000u);
+}
+
+TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) {
+  int64_t now_ms = clock_.TimeInMilliseconds();
+  uint16_t seq_num = 0;
+  // First burst sent at 8 * 1000 / 10 = 800 kbps, but with every other packet
+  // not being paced which could mess things up.
+  for (int i = 0; i < kNumProbesCluster0; ++i) {
+    clock_.AdvanceTimeMilliseconds(5);
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo0);
+    // Non-paced packet, arriving 5 ms after.
+    clock_.AdvanceTimeMilliseconds(5);
+    IncomingFeedback(now_ms, now_ms, seq_num++, 100, PacedPacketInfo());
+  }
+
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_GT(bitrate_observer_.latest_bitrate(), 800000u);
+}
+
+TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) {
+  int64_t now_ms = clock_.TimeInMilliseconds();
+  uint16_t seq_num = 0;
+  // First burst sent at 8 * 1000 / 10 = 800 kbps.
+  // Arriving at 8 * 1000 / 5 = 1600 kbps.
+  int64_t send_time_ms = 0;
+  for (int i = 0; i < kNumProbesCluster0; ++i) {
+    clock_.AdvanceTimeMilliseconds(1);
+    send_time_ms += 10;
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo0);
+  }
+
+  EXPECT_FALSE(bitrate_observer_.updated());
+}
+
+TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) {
+  int64_t now_ms = clock_.TimeInMilliseconds();
+  uint16_t seq_num = 0;
+  // First burst sent at 8 * 1000 / 5 = 1600 kbps.
+  // Arriving at 8 * 1000 / 7 = 1142 kbps.
+  // Since the receive rate is significantly below the send rate, we expect to
+  // use 95% of the estimated capacity.
+  int64_t send_time_ms = 0;
+  for (int i = 0; i < kNumProbesCluster1; ++i) {
+    clock_.AdvanceTimeMilliseconds(7);
+    send_time_ms += 5;
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo1);
+  }
+
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_NEAR(bitrate_observer_.latest_bitrate(),
+              kTargetUtilizationFraction * 1140000u, 10000u);
+}
+
+TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) {
+  int64_t now_ms = clock_.TimeInMilliseconds();
+  uint16_t seq_num = 0;
+  // Burst sent at 8 * 1000 / 1 = 8000 kbps.
+  // Arriving at 8 * 1000 / 2 = 4000 kbps.
+  // Since the receive rate is significantly below the send rate, we expect to
+  // use 95% of the estimated capacity.
+  int64_t send_time_ms = 0;
+  for (int i = 0; i < kNumProbesCluster1; ++i) {
+    clock_.AdvanceTimeMilliseconds(2);
+    send_time_ms += 1;
+    now_ms = clock_.TimeInMilliseconds();
+    IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo1);
+  }
+
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_NEAR(bitrate_observer_.latest_bitrate(),
+              kTargetUtilizationFraction * 4000000u, 10000u);
+}
+
+TEST_F(DelayBasedBweTest, GetExpectedBwePeriodMs) {
+  int64_t default_interval_ms = bitrate_estimator_->GetExpectedBwePeriodMs();
+  EXPECT_GT(default_interval_ms, 0);
+  CapacityDropTestHelper(1, true, 333, 0);
+  int64_t interval_ms = bitrate_estimator_->GetExpectedBwePeriodMs();
+  EXPECT_GT(interval_ms, 0);
+  EXPECT_NE(interval_ms, default_interval_ms);
+}
+
+TEST_F(DelayBasedBweTest, InitialBehavior) {
+  InitialBehaviorTestHelper(730000);
+}
+
+TEST_F(DelayBasedBweTest, RateIncreaseReordering) {
+  RateIncreaseReorderingTestHelper(730000);
+}
+TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) {
+  RateIncreaseRtpTimestampsTestHelper(627);
+}
+
+TEST_F(DelayBasedBweTest, CapacityDropOneStream) {
+  CapacityDropTestHelper(1, false, 300, 0);
+}
+
+TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) {
+  CapacityDropTestHelper(1, false, 867, 30000);
+}
+
+TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) {
+  CapacityDropTestHelper(1, false, 933, -30000);
+}
+
+TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) {
+  CapacityDropTestHelper(1, true, 333, 0);
+}
+
+TEST_F(DelayBasedBweTest, TestTimestampGrouping) {
+  TestTimestampGroupingTestHelper();
+}
+
+TEST_F(DelayBasedBweTest, TestShortTimeoutAndWrap) {
+  // Simulate a client leaving and rejoining the call after 35 seconds. This
+  // will make abs send time wrap, so if streams aren't timed out properly
+  // the next 30 seconds of packets will be out of order.
+  TestWrappingHelper(35);
+}
+
+TEST_F(DelayBasedBweTest, TestLongTimeoutAndWrap) {
+  // Simulate a client leaving and rejoining the call after some multiple of
+  // 64 seconds later. This will cause a zero difference in abs send times due
+  // to the wrap, but a big difference in arrival time, if streams aren't
+  // properly timed out.
+  TestWrappingHelper(10 * 64);
+}
+
+TEST_F(DelayBasedBweTest, TestInitialOveruse) {
+  const uint32_t kStartBitrate = 300e3;
+  const uint32_t kInitialCapacityBps = 200e3;
+  const uint32_t kDummySsrc = 0;
+  // High FPS to ensure that we send a lot of packets in a short time.
+  const int kFps = 90;
+
+  stream_generator_->AddStream(new test::RtpStream(kFps, kStartBitrate));
+  stream_generator_->set_capacity_bps(kInitialCapacityBps);
+
+  // Needed to initialize the AimdRateControl.
+  bitrate_estimator_->SetStartBitrate(kStartBitrate);
+
+  // Produce 30 frames (in 1/3 second) and give them to the estimator.
+  uint32_t bitrate_bps = kStartBitrate;
+  bool seen_overuse = false;
+  for (int i = 0; i < 30; ++i) {
+    bool overuse = GenerateAndProcessFrame(kDummySsrc, bitrate_bps);
+    // The purpose of this test is to ensure that we back down even if we don't
+    // have any acknowledged bitrate estimate yet. Hence, if the test works
+    // as expected, we should not have a measured bitrate yet.
+    EXPECT_FALSE(acknowledged_bitrate_estimator_->bitrate_bps().has_value());
+    if (overuse) {
+      EXPECT_TRUE(bitrate_observer_.updated());
+      EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000);
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      seen_overuse = true;
+      break;
+    } else if (bitrate_observer_.updated()) {
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      bitrate_observer_.Reset();
+    }
+  }
+  EXPECT_TRUE(seen_overuse);
+  EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000);
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc
new file mode 100644
index 0000000..35019b0
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc
@@ -0,0 +1,517 @@
+/*
+ *  Copyright (c) 2016 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/delay_based_bwe_unittest_helper.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/ptr_util.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+constexpr size_t kMtu = 1200;
+constexpr uint32_t kAcceptedBitrateErrorBps = 50000;
+
+// Number of packets needed before we have a valid estimate.
+constexpr int kNumInitialPackets = 2;
+
+constexpr int kInitialProbingPackets = 5;
+
+namespace test {
+
+void TestBitrateObserver::OnReceiveBitrateChanged(
+    const std::vector<uint32_t>& ssrcs,
+    uint32_t bitrate) {
+  latest_bitrate_ = bitrate;
+  updated_ = true;
+}
+
+RtpStream::RtpStream(int fps, int bitrate_bps)
+    : fps_(fps),
+      bitrate_bps_(bitrate_bps),
+      next_rtp_time_(0),
+      sequence_number_(0) {
+  RTC_CHECK_GT(fps_, 0);
+}
+
+// Generates a new frame for this stream. If called too soon after the
+// previous frame, no frame will be generated. The frame is split into
+// packets.
+int64_t RtpStream::GenerateFrame(int64_t time_now_us,
+                                 std::vector<PacketFeedback>* packets) {
+  if (time_now_us < next_rtp_time_) {
+    return next_rtp_time_;
+  }
+  RTC_CHECK(packets != NULL);
+  size_t bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_;
+  size_t n_packets =
+      std::max<size_t>((bits_per_frame + 4 * kMtu) / (8 * kMtu), 1u);
+  size_t payload_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets);
+  for (size_t i = 0; i < n_packets; ++i) {
+    PacketFeedback packet(-1, sequence_number_++);
+    packet.send_time_ms = (time_now_us + kSendSideOffsetUs) / 1000;
+    packet.payload_size = payload_size;
+    packets->push_back(packet);
+  }
+  next_rtp_time_ = time_now_us + (1000000 + fps_ / 2) / fps_;
+  return next_rtp_time_;
+}
+
+// The send-side time when the next frame can be generated.
+int64_t RtpStream::next_rtp_time() const {
+  return next_rtp_time_;
+}
+
+void RtpStream::set_bitrate_bps(int bitrate_bps) {
+  ASSERT_GE(bitrate_bps, 0);
+  bitrate_bps_ = bitrate_bps;
+}
+
+int RtpStream::bitrate_bps() const {
+  return bitrate_bps_;
+}
+
+bool RtpStream::Compare(const std::unique_ptr<RtpStream>& lhs,
+                        const std::unique_ptr<RtpStream>& rhs) {
+  return lhs->next_rtp_time_ < rhs->next_rtp_time_;
+}
+
+StreamGenerator::StreamGenerator(int capacity, int64_t time_now)
+    : capacity_(capacity), prev_arrival_time_us_(time_now) {}
+
+// Add a new stream.
+void StreamGenerator::AddStream(RtpStream* stream) {
+  streams_.push_back(std::unique_ptr<RtpStream>(stream));
+}
+
+// Set the link capacity.
+void StreamGenerator::set_capacity_bps(int capacity_bps) {
+  ASSERT_GT(capacity_bps, 0);
+  capacity_ = capacity_bps;
+}
+
+// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
+// is decided by the current allocation ratios.
+void StreamGenerator::SetBitrateBps(int bitrate_bps) {
+  ASSERT_GE(streams_.size(), 0u);
+  int total_bitrate_before = 0;
+  for (const auto& stream : streams_) {
+    total_bitrate_before += stream->bitrate_bps();
+  }
+  int64_t bitrate_before = 0;
+  int total_bitrate_after = 0;
+  for (const auto& stream : streams_) {
+    bitrate_before += stream->bitrate_bps();
+    int64_t bitrate_after =
+        (bitrate_before * bitrate_bps + total_bitrate_before / 2) /
+        total_bitrate_before;
+    stream->set_bitrate_bps(bitrate_after - total_bitrate_after);
+    total_bitrate_after += stream->bitrate_bps();
+  }
+  ASSERT_EQ(bitrate_before, total_bitrate_before);
+  EXPECT_EQ(total_bitrate_after, bitrate_bps);
+}
+
+// TODO(holmer): Break out the channel simulation part from this class to make
+// it possible to simulate different types of channels.
+int64_t StreamGenerator::GenerateFrame(std::vector<PacketFeedback>* packets,
+                                       int64_t time_now_us) {
+  RTC_CHECK(packets != NULL);
+  RTC_CHECK(packets->empty());
+  RTC_CHECK_GT(capacity_, 0);
+  auto it =
+      std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
+  (*it)->GenerateFrame(time_now_us, packets);
+  int i = 0;
+  for (PacketFeedback& packet : *packets) {
+    int capacity_bpus = capacity_ / 1000;
+    int64_t required_network_time_us =
+        (8 * 1000 * packet.payload_size + capacity_bpus / 2) / capacity_bpus;
+    prev_arrival_time_us_ =
+        std::max(time_now_us + required_network_time_us,
+                 prev_arrival_time_us_ + required_network_time_us);
+    packet.arrival_time_ms = prev_arrival_time_us_ / 1000;
+    ++i;
+  }
+  it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
+  return std::max((*it)->next_rtp_time(), time_now_us);
+}
+}  // namespace test
+
+DelayBasedBweTest::DelayBasedBweTest()
+    : clock_(100000000),
+      acknowledged_bitrate_estimator_(
+          rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
+      bitrate_estimator_(new DelayBasedBwe(nullptr)),
+      stream_generator_(new test::StreamGenerator(1e6,  // Capacity.
+                                                  clock_.TimeInMicroseconds())),
+      arrival_time_offset_ms_(0),
+      first_update_(true) {}
+
+DelayBasedBweTest::~DelayBasedBweTest() {}
+
+void DelayBasedBweTest::AddDefaultStream() {
+  stream_generator_->AddStream(new test::RtpStream(30, 3e5));
+}
+
+const uint32_t DelayBasedBweTest::kDefaultSsrc = 0;
+
+void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms,
+                                         int64_t send_time_ms,
+                                         uint16_t sequence_number,
+                                         size_t payload_size) {
+  IncomingFeedback(arrival_time_ms, send_time_ms, sequence_number, payload_size,
+                   PacedPacketInfo());
+}
+
+void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms,
+                                         int64_t send_time_ms,
+                                         uint16_t sequence_number,
+                                         size_t payload_size,
+                                         const PacedPacketInfo& pacing_info) {
+  RTC_CHECK_GE(arrival_time_ms + arrival_time_offset_ms_, 0);
+  PacketFeedback packet(arrival_time_ms + arrival_time_offset_ms_, send_time_ms,
+                        sequence_number, payload_size, pacing_info);
+  std::vector<PacketFeedback> packets;
+  packets.push_back(packet);
+  acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
+  DelayBasedBwe::Result result =
+      bitrate_estimator_->IncomingPacketFeedbackVector(
+          packets, acknowledged_bitrate_estimator_->bitrate_bps(),
+          clock_.TimeInMilliseconds());
+  const uint32_t kDummySsrc = 0;
+  if (result.updated) {
+    bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
+                                              result.target_bitrate_bps);
+  }
+}
+
+// Generates a frame of packets belonging to a stream at a given bitrate and
+// with a given ssrc. The stream is pushed through a very simple simulated
+// network, and is then given to the receive-side bandwidth estimator.
+// Returns true if an over-use was seen, false otherwise.
+// The StreamGenerator::updated() should be used to check for any changes in
+// target bitrate after the call to this function.
+bool DelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc,
+                                                uint32_t bitrate_bps) {
+  stream_generator_->SetBitrateBps(bitrate_bps);
+  std::vector<PacketFeedback> packets;
+  int64_t next_time_us =
+      stream_generator_->GenerateFrame(&packets, clock_.TimeInMicroseconds());
+  if (packets.empty())
+    return false;
+
+  bool overuse = false;
+  bitrate_observer_.Reset();
+  clock_.AdvanceTimeMicroseconds(1000 * packets.back().arrival_time_ms -
+                                 clock_.TimeInMicroseconds());
+  for (auto& packet : packets) {
+    RTC_CHECK_GE(packet.arrival_time_ms + arrival_time_offset_ms_, 0);
+    packet.arrival_time_ms += arrival_time_offset_ms_;
+  }
+
+  acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
+  DelayBasedBwe::Result result =
+      bitrate_estimator_->IncomingPacketFeedbackVector(
+          packets, acknowledged_bitrate_estimator_->bitrate_bps(),
+          clock_.TimeInMilliseconds());
+  const uint32_t kDummySsrc = 0;
+  if (result.updated) {
+    bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
+                                              result.target_bitrate_bps);
+    if (!first_update_ && result.target_bitrate_bps < bitrate_bps)
+      overuse = true;
+    first_update_ = false;
+  }
+
+  clock_.AdvanceTimeMicroseconds(next_time_us - clock_.TimeInMicroseconds());
+  return overuse;
+}
+
+// Run the bandwidth estimator with a stream of |number_of_frames| frames, or
+// until it reaches |target_bitrate|.
+// Can for instance be used to run the estimator for some time to get it
+// into a steady state.
+uint32_t DelayBasedBweTest::SteadyStateRun(uint32_t ssrc,
+                                           int max_number_of_frames,
+                                           uint32_t start_bitrate,
+                                           uint32_t min_bitrate,
+                                           uint32_t max_bitrate,
+                                           uint32_t target_bitrate) {
+  uint32_t bitrate_bps = start_bitrate;
+  bool bitrate_update_seen = false;
+  // Produce |number_of_frames| frames and give them to the estimator.
+  for (int i = 0; i < max_number_of_frames; ++i) {
+    bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps);
+    if (overuse) {
+      EXPECT_LT(bitrate_observer_.latest_bitrate(), max_bitrate);
+      EXPECT_GT(bitrate_observer_.latest_bitrate(), min_bitrate);
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      bitrate_update_seen = true;
+    } else if (bitrate_observer_.updated()) {
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      bitrate_observer_.Reset();
+    }
+    if (bitrate_update_seen && bitrate_bps > target_bitrate) {
+      break;
+    }
+  }
+  EXPECT_TRUE(bitrate_update_seen);
+  return bitrate_bps;
+}
+
+void DelayBasedBweTest::InitialBehaviorTestHelper(
+    uint32_t expected_converge_bitrate) {
+  const int kFramerate = 50;  // 50 fps to avoid rounding errors.
+  const int kFrameIntervalMs = 1000 / kFramerate;
+  const PacedPacketInfo kPacingInfo(0, 5, 5000);
+  uint32_t bitrate_bps = 0;
+  int64_t send_time_ms = 0;
+  uint16_t sequence_number = 0;
+  std::vector<uint32_t> ssrcs;
+  EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
+  EXPECT_EQ(0u, ssrcs.size());
+  clock_.AdvanceTimeMilliseconds(1000);
+  EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
+  EXPECT_FALSE(bitrate_observer_.updated());
+  bitrate_observer_.Reset();
+  clock_.AdvanceTimeMilliseconds(1000);
+  // Inserting packets for 5 seconds to get a valid estimate.
+  for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) {
+    // NOTE!!! If the following line is moved under the if case then this test
+    //         wont work on windows realease bots.
+    PacedPacketInfo pacing_info =
+        i < kInitialProbingPackets ? kPacingInfo : PacedPacketInfo();
+
+    if (i == kNumInitialPackets) {
+      EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
+      EXPECT_EQ(0u, ssrcs.size());
+      EXPECT_FALSE(bitrate_observer_.updated());
+      bitrate_observer_.Reset();
+    }
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number++, kMtu, pacing_info);
+    clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
+    send_time_ms += kFrameIntervalMs;
+  }
+  EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
+  ASSERT_EQ(1u, ssrcs.size());
+  EXPECT_EQ(kDefaultSsrc, ssrcs.front());
+  EXPECT_NEAR(expected_converge_bitrate, bitrate_bps, kAcceptedBitrateErrorBps);
+  EXPECT_TRUE(bitrate_observer_.updated());
+  bitrate_observer_.Reset();
+  EXPECT_EQ(bitrate_observer_.latest_bitrate(), bitrate_bps);
+}
+
+void DelayBasedBweTest::RateIncreaseReorderingTestHelper(
+    uint32_t expected_bitrate_bps) {
+  const int kFramerate = 50;  // 50 fps to avoid rounding errors.
+  const int kFrameIntervalMs = 1000 / kFramerate;
+  const PacedPacketInfo kPacingInfo(0, 5, 5000);
+  int64_t send_time_ms = 0;
+  uint16_t sequence_number = 0;
+  // Inserting packets for five seconds to get a valid estimate.
+  for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) {
+    // NOTE!!! If the following line is moved under the if case then this test
+    //         wont work on windows realease bots.
+    PacedPacketInfo pacing_info =
+        i < kInitialProbingPackets ? kPacingInfo : PacedPacketInfo();
+
+    // TODO(sprang): Remove this hack once the single stream estimator is gone,
+    // as it doesn't do anything in Process().
+    if (i == kNumInitialPackets) {
+      // Process after we have enough frames to get a valid input rate estimate.
+
+      EXPECT_FALSE(bitrate_observer_.updated());  // No valid estimate.
+    }
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number++, kMtu, pacing_info);
+    clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+    send_time_ms += kFrameIntervalMs;
+  }
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_.latest_bitrate(),
+              kAcceptedBitrateErrorBps);
+  for (int i = 0; i < 10; ++i) {
+    clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
+    send_time_ms += 2 * kFrameIntervalMs;
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number + 2, 1000);
+    IncomingFeedback(clock_.TimeInMilliseconds(),
+                     send_time_ms - kFrameIntervalMs, sequence_number + 1,
+                     1000);
+    sequence_number += 2;
+  }
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_.latest_bitrate(),
+              kAcceptedBitrateErrorBps);
+}
+
+// Make sure we initially increase the bitrate as expected.
+void DelayBasedBweTest::RateIncreaseRtpTimestampsTestHelper(
+    int expected_iterations) {
+  // This threshold corresponds approximately to increasing linearly with
+  // bitrate(i) = 1.04 * bitrate(i-1) + 1000
+  // until bitrate(i) > 500000, with bitrate(1) ~= 30000.
+  uint32_t bitrate_bps = 30000;
+  int iterations = 0;
+  AddDefaultStream();
+  // Feed the estimator with a stream of packets and verify that it reaches
+  // 500 kbps at the expected time.
+  while (bitrate_bps < 5e5) {
+    bool overuse = GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
+    if (overuse) {
+      EXPECT_GT(bitrate_observer_.latest_bitrate(), bitrate_bps);
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      bitrate_observer_.Reset();
+    } else if (bitrate_observer_.updated()) {
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+      bitrate_observer_.Reset();
+    }
+    ++iterations;
+  }
+  ASSERT_EQ(expected_iterations, iterations);
+}
+
+void DelayBasedBweTest::CapacityDropTestHelper(
+    int number_of_streams,
+    bool wrap_time_stamp,
+    uint32_t expected_bitrate_drop_delta,
+    int64_t receiver_clock_offset_change_ms) {
+  const int kFramerate = 30;
+  const int kStartBitrate = 900e3;
+  const int kMinExpectedBitrate = 800e3;
+  const int kMaxExpectedBitrate = 1100e3;
+  const uint32_t kInitialCapacityBps = 1000e3;
+  const uint32_t kReducedCapacityBps = 500e3;
+
+  int steady_state_time = 0;
+  if (number_of_streams <= 1) {
+    steady_state_time = 10;
+    AddDefaultStream();
+  } else {
+    steady_state_time = 10 * number_of_streams;
+    int bitrate_sum = 0;
+    int kBitrateDenom = number_of_streams * (number_of_streams - 1);
+    for (int i = 0; i < number_of_streams; i++) {
+      // First stream gets half available bitrate, while the rest share the
+      // remaining half i.e.: 1/2 = Sum[n/(N*(N-1))] for n=1..N-1 (rounded up)
+      int bitrate = kStartBitrate / 2;
+      if (i > 0) {
+        bitrate = (kStartBitrate * i + kBitrateDenom / 2) / kBitrateDenom;
+      }
+      stream_generator_->AddStream(new test::RtpStream(kFramerate, bitrate));
+      bitrate_sum += bitrate;
+    }
+    ASSERT_EQ(bitrate_sum, kStartBitrate);
+  }
+
+  // Run in steady state to make the estimator converge.
+  stream_generator_->set_capacity_bps(kInitialCapacityBps);
+  uint32_t bitrate_bps = SteadyStateRun(
+      kDefaultSsrc, steady_state_time * kFramerate, kStartBitrate,
+      kMinExpectedBitrate, kMaxExpectedBitrate, kInitialCapacityBps);
+  EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 180000u);
+  bitrate_observer_.Reset();
+
+  // Add an offset to make sure the BWE can handle it.
+  arrival_time_offset_ms_ += receiver_clock_offset_change_ms;
+
+  // Reduce the capacity and verify the decrease time.
+  stream_generator_->set_capacity_bps(kReducedCapacityBps);
+  int64_t overuse_start_time = clock_.TimeInMilliseconds();
+  int64_t bitrate_drop_time = -1;
+  for (int i = 0; i < 100 * number_of_streams; ++i) {
+    GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
+    if (bitrate_drop_time == -1 &&
+        bitrate_observer_.latest_bitrate() <= kReducedCapacityBps) {
+      bitrate_drop_time = clock_.TimeInMilliseconds();
+    }
+    if (bitrate_observer_.updated())
+      bitrate_bps = bitrate_observer_.latest_bitrate();
+  }
+
+  EXPECT_NEAR(expected_bitrate_drop_delta,
+              bitrate_drop_time - overuse_start_time, 33);
+}
+
+void DelayBasedBweTest::TestTimestampGroupingTestHelper() {
+  const int kFramerate = 50;  // 50 fps to avoid rounding errors.
+  const int kFrameIntervalMs = 1000 / kFramerate;
+  int64_t send_time_ms = 0;
+  uint16_t sequence_number = 0;
+  // Initial set of frames to increase the bitrate. 6 seconds to have enough
+  // time for the first estimate to be generated and for Process() to be called.
+  for (int i = 0; i <= 6 * kFramerate; ++i) {
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number++, 1000);
+
+    clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+    send_time_ms += kFrameIntervalMs;
+  }
+  EXPECT_TRUE(bitrate_observer_.updated());
+  EXPECT_GE(bitrate_observer_.latest_bitrate(), 400000u);
+
+  // Insert batches of frames which were sent very close in time. Also simulate
+  // capacity over-use to see that we back off correctly.
+  const int kTimestampGroupLength = 15;
+  for (int i = 0; i < 100; ++i) {
+    for (int j = 0; j < kTimestampGroupLength; ++j) {
+      // Insert |kTimestampGroupLength| frames with just 1 timestamp ticks in
+      // between. Should be treated as part of the same group by the estimator.
+      IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                       sequence_number++, 100);
+      clock_.AdvanceTimeMilliseconds(kFrameIntervalMs / kTimestampGroupLength);
+      send_time_ms += 1;
+    }
+    // Increase time until next batch to simulate over-use.
+    clock_.AdvanceTimeMilliseconds(10);
+    send_time_ms += kFrameIntervalMs - kTimestampGroupLength;
+  }
+  EXPECT_TRUE(bitrate_observer_.updated());
+  // Should have reduced the estimate.
+  EXPECT_LT(bitrate_observer_.latest_bitrate(), 400000u);
+}
+
+void DelayBasedBweTest::TestWrappingHelper(int silence_time_s) {
+  const int kFramerate = 100;
+  const int kFrameIntervalMs = 1000 / kFramerate;
+  int64_t send_time_ms = 0;
+  uint16_t sequence_number = 0;
+
+  for (size_t i = 0; i < 3000; ++i) {
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number++, 1000);
+    clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
+    send_time_ms += kFrameIntervalMs;
+  }
+  uint32_t bitrate_before = 0;
+  std::vector<uint32_t> ssrcs;
+  bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_before);
+
+  clock_.AdvanceTimeMilliseconds(silence_time_s * 1000);
+  send_time_ms += silence_time_s * 1000;
+
+  for (size_t i = 0; i < 24; ++i) {
+    IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
+                     sequence_number++, 1000);
+    clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
+    send_time_ms += kFrameIntervalMs;
+  }
+  uint32_t bitrate_after = 0;
+  bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after);
+  EXPECT_LT(bitrate_after, bitrate_before);
+}
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h
new file mode 100644
index 0000000..4ccf228
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h
@@ -0,0 +1,180 @@
+/*
+ *  Copyright (c) 2016 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_DELAY_BASED_BWE_UNITTEST_HELPER_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_UNITTEST_HELPER_H_
+
+#include <list>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
+#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
+#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
+#include "rtc_base/constructormagic.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+namespace test {
+
+class TestBitrateObserver : public RemoteBitrateObserver {
+ public:
+  TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
+  virtual ~TestBitrateObserver() {}
+
+  void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
+                               uint32_t bitrate) override;
+
+  void Reset() { updated_ = false; }
+
+  bool updated() const { return updated_; }
+
+  uint32_t latest_bitrate() const { return latest_bitrate_; }
+
+ private:
+  bool updated_;
+  uint32_t latest_bitrate_;
+};
+
+class RtpStream {
+ public:
+  enum { kSendSideOffsetUs = 1000000 };
+
+  RtpStream(int fps, int bitrate_bps);
+
+  // Generates a new frame for this stream. If called too soon after the
+  // previous frame, no frame will be generated. The frame is split into
+  // packets.
+  int64_t GenerateFrame(int64_t time_now_us,
+                        std::vector<PacketFeedback>* packets);
+
+  // The send-side time when the next frame can be generated.
+  int64_t next_rtp_time() const;
+
+  void set_bitrate_bps(int bitrate_bps);
+
+  int bitrate_bps() const;
+
+  static bool Compare(const std::unique_ptr<RtpStream>& lhs,
+                      const std::unique_ptr<RtpStream>& rhs);
+
+ private:
+  int fps_;
+  int bitrate_bps_;
+  int64_t next_rtp_time_;
+  uint16_t sequence_number_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(RtpStream);
+};
+
+class StreamGenerator {
+ public:
+  StreamGenerator(int capacity, int64_t time_now);
+
+  // Add a new stream.
+  void AddStream(RtpStream* stream);
+
+  // Set the link capacity.
+  void set_capacity_bps(int capacity_bps);
+
+  // Divides |bitrate_bps| among all streams. The allocated bitrate per stream
+  // is decided by the initial allocation ratios.
+  void SetBitrateBps(int bitrate_bps);
+
+  // Set the RTP timestamp offset for the stream identified by |ssrc|.
+  void set_rtp_timestamp_offset(uint32_t ssrc, uint32_t offset);
+
+  // TODO(holmer): Break out the channel simulation part from this class to make
+  // it possible to simulate different types of channels.
+  int64_t GenerateFrame(std::vector<PacketFeedback>* packets,
+                        int64_t time_now_us);
+
+ private:
+  // Capacity of the simulated channel in bits per second.
+  int capacity_;
+  // The time when the last packet arrived.
+  int64_t prev_arrival_time_us_;
+  // All streams being transmitted on this simulated channel.
+  std::vector<std::unique_ptr<RtpStream>> streams_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(StreamGenerator);
+};
+}  // namespace test
+
+class DelayBasedBweTest : public ::testing::Test {
+ public:
+  DelayBasedBweTest();
+  virtual ~DelayBasedBweTest();
+
+ protected:
+  void AddDefaultStream();
+
+  // Helpers to insert a single packet into the delay-based BWE.
+  void IncomingFeedback(int64_t arrival_time_ms,
+                        int64_t send_time_ms,
+                        uint16_t sequence_number,
+                        size_t payload_size);
+  void IncomingFeedback(int64_t arrival_time_ms,
+                        int64_t send_time_ms,
+                        uint16_t sequence_number,
+                        size_t payload_size,
+                        const PacedPacketInfo& pacing_info);
+
+  // Generates a frame of packets belonging to a stream at a given bitrate and
+  // with a given ssrc. The stream is pushed through a very simple simulated
+  // network, and is then given to the receive-side bandwidth estimator.
+  // Returns true if an over-use was seen, false otherwise.
+  // The StreamGenerator::updated() should be used to check for any changes in
+  // target bitrate after the call to this function.
+  bool GenerateAndProcessFrame(uint32_t ssrc, uint32_t bitrate_bps);
+
+  // Run the bandwidth estimator with a stream of |number_of_frames| frames, or
+  // until it reaches |target_bitrate|.
+  // Can for instance be used to run the estimator for some time to get it
+  // into a steady state.
+  uint32_t SteadyStateRun(uint32_t ssrc,
+                          int number_of_frames,
+                          uint32_t start_bitrate,
+                          uint32_t min_bitrate,
+                          uint32_t max_bitrate,
+                          uint32_t target_bitrate);
+
+  void TestTimestampGroupingTestHelper();
+
+  void TestWrappingHelper(int silence_time_s);
+
+  void InitialBehaviorTestHelper(uint32_t expected_converge_bitrate);
+  void RateIncreaseReorderingTestHelper(uint32_t expected_bitrate);
+  void RateIncreaseRtpTimestampsTestHelper(int expected_iterations);
+  void CapacityDropTestHelper(int number_of_streams,
+                              bool wrap_time_stamp,
+                              uint32_t expected_bitrate_drop_delta,
+                              int64_t receiver_clock_offset_change_ms);
+
+  static const uint32_t kDefaultSsrc;
+
+  SimulatedClock clock_;  // Time at the receiver.
+  test::TestBitrateObserver bitrate_observer_;
+  std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
+  std::unique_ptr<DelayBasedBwe> bitrate_estimator_;
+  std::unique_ptr<test::StreamGenerator> stream_generator_;
+  int64_t arrival_time_offset_ms_;
+  bool first_update_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest);
+};
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_UNITTEST_HELPER_H_
diff --git a/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h b/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h
new file mode 100644
index 0000000..d748c28
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/delay_increase_detector_interface.h
@@ -0,0 +1,39 @@
+/*
+ *  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_DELAY_INCREASE_DETECTOR_INTERFACE_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_INCREASE_DETECTOR_INTERFACE_H_
+
+#include <stdint.h>
+
+#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+class DelayIncreaseDetectorInterface {
+ public:
+  DelayIncreaseDetectorInterface() {}
+  virtual ~DelayIncreaseDetectorInterface() {}
+
+  // Update the detector with a new sample. The deltas should represent deltas
+  // between timestamp groups as defined by the InterArrival class.
+  virtual void Update(double recv_delta_ms,
+                      double send_delta_ms,
+                      int64_t arrival_time_ms) = 0;
+
+  virtual BandwidthUsage State() const = 0;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(DelayIncreaseDetectorInterface);
+};
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_INCREASE_DETECTOR_INTERFACE_H_
diff --git a/modules/congestion_controller/goog_cc/goog_cc_factory.cc b/modules/congestion_controller/goog_cc/goog_cc_factory.cc
new file mode 100644
index 0000000..ad230bc
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/goog_cc_factory.cc
@@ -0,0 +1,30 @@
+/*
+ *  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/include/goog_cc_factory.h"
+
+#include "modules/congestion_controller/goog_cc/goog_cc_network_control.h"
+#include "rtc_base/ptr_util.h"
+namespace webrtc {
+GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
+    RtcEventLog* event_log)
+    : event_log_(event_log) {}
+
+NetworkControllerInterface::uptr GoogCcNetworkControllerFactory::Create(
+    NetworkControllerObserver* observer) {
+  return rtc::MakeUnique<webrtc_cc::GoogCcNetworkController>(event_log_,
+                                                             observer);
+}
+
+TimeDelta GoogCcNetworkControllerFactory::GetProcessInterval() const {
+  const int64_t kUpdateIntervalMs = 25;
+  return TimeDelta::ms(kUpdateIntervalMs);
+}
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc
new file mode 100644
index 0000000..a360e9c
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc
@@ -0,0 +1,413 @@
+/*
+ *  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/goog_cc_network_control.h"
+
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
+#include "modules/congestion_controller/goog_cc/alr_detector.h"
+#include "modules/congestion_controller/goog_cc/include/goog_cc_factory.h"
+#include "modules/congestion_controller/goog_cc/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 webrtc_cc {
+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
+
+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_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h
new file mode 100644
index 0000000..47ae084
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h
@@ -0,0 +1,94 @@
+/*
+ *  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_GOOG_CC_NETWORK_CONTROL_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_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/goog_cc/acknowledged_bitrate_estimator.h"
+#include "modules/congestion_controller/goog_cc/alr_detector.h"
+#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
+#include "modules/congestion_controller/goog_cc/probe_controller.h"
+#include "modules/congestion_controller/network_control/include/network_control.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+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_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_GOOG_CC_NETWORK_CONTROL_H_
diff --git a/modules/congestion_controller/goog_cc/include/goog_cc_factory.h b/modules/congestion_controller/goog_cc/include/goog_cc_factory.h
new file mode 100644
index 0000000..20717f9
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/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_GOOG_CC_INCLUDE_GOOG_CC_FACTORY_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_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_GOOG_CC_INCLUDE_GOOG_CC_FACTORY_H_
diff --git a/modules/congestion_controller/goog_cc/median_slope_estimator.cc b/modules/congestion_controller/goog_cc/median_slope_estimator.cc
new file mode 100644
index 0000000..3ad5e3f
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/median_slope_estimator.cc
@@ -0,0 +1,95 @@
+/*
+ *  Copyright (c) 2016 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/median_slope_estimator.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+constexpr unsigned int kDeltaCounterMax = 1000;
+
+MedianSlopeEstimator::MedianSlopeEstimator(size_t window_size,
+                                           double threshold_gain)
+    : window_size_(window_size),
+      threshold_gain_(threshold_gain),
+      num_of_deltas_(0),
+      accumulated_delay_(0),
+      delay_hist_(),
+      median_filter_(0.5),
+      trendline_(0) {}
+
+MedianSlopeEstimator::~MedianSlopeEstimator() {}
+
+MedianSlopeEstimator::DelayInfo::DelayInfo(int64_t time,
+                                           double delay,
+                                           size_t slope_count)
+    : time(time), delay(delay) {
+  slopes.reserve(slope_count);
+}
+
+MedianSlopeEstimator::DelayInfo::~DelayInfo() = default;
+
+void MedianSlopeEstimator::Update(double recv_delta_ms,
+                                  double send_delta_ms,
+                                  int64_t arrival_time_ms) {
+  const double delta_ms = recv_delta_ms - send_delta_ms;
+  ++num_of_deltas_;
+  if (num_of_deltas_ > kDeltaCounterMax)
+    num_of_deltas_ = kDeltaCounterMax;
+
+  accumulated_delay_ += delta_ms;
+  BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms,
+                        accumulated_delay_);
+
+  // If the window is full, remove the |window_size_| - 1 slopes that belong to
+  // the oldest point.
+  if (delay_hist_.size() == window_size_) {
+    for (double slope : delay_hist_.front().slopes) {
+      const bool success = median_filter_.Erase(slope);
+      RTC_CHECK(success);
+    }
+    delay_hist_.pop_front();
+  }
+  // Add |window_size_| - 1 new slopes.
+  for (auto& old_delay : delay_hist_) {
+    if (arrival_time_ms - old_delay.time != 0) {
+      // The C99 standard explicitly states that casts and assignments must
+      // perform the associated conversions. This means that |slope| will be
+      // a 64-bit double even if the division is computed using, e.g., 80-bit
+      // extended precision. I believe this also holds in C++ even though the
+      // C++11 standard isn't as explicit. Furthermore, there are good reasons
+      // to believe that compilers couldn't perform optimizations that break
+      // this assumption even if they wanted to.
+      double slope = (accumulated_delay_ - old_delay.delay) /
+                     static_cast<double>(arrival_time_ms - old_delay.time);
+      median_filter_.Insert(slope);
+      // We want to avoid issues with different rounding mode / precision
+      // which we might get if we recomputed the slope when we remove it.
+      old_delay.slopes.push_back(slope);
+    }
+  }
+  delay_hist_.emplace_back(arrival_time_ms, accumulated_delay_,
+                           window_size_ - 1);
+  // Recompute the median slope.
+  if (delay_hist_.size() == window_size_)
+    trendline_ = median_filter_.GetPercentileValue();
+
+  BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trendline_);
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/median_slope_estimator.h b/modules/congestion_controller/goog_cc/median_slope_estimator.h
new file mode 100644
index 0000000..acac830
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/median_slope_estimator.h
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2016 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_MEDIAN_SLOPE_ESTIMATOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_MEDIAN_SLOPE_ESTIMATOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <deque>
+#include <vector>
+
+#include "rtc_base/constructormagic.h"
+#include "rtc_base/numerics/percentile_filter.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+class MedianSlopeEstimator {
+ public:
+  // |window_size| is the number of points required to compute a trend line.
+  // |threshold_gain| is used to scale the trendline slope for comparison to
+  // the old threshold. Once the old estimator has been removed (or the
+  // thresholds been merged into the estimators), we can just set the
+  // threshold instead of setting a gain.
+  MedianSlopeEstimator(size_t window_size, double threshold_gain);
+  ~MedianSlopeEstimator();
+
+  // Update the estimator with a new sample. The deltas should represent deltas
+  // between timestamp groups as defined by the InterArrival class.
+  void Update(double recv_delta_ms,
+              double send_delta_ms,
+              int64_t arrival_time_ms);
+
+  // Returns the estimated trend k multiplied by some gain.
+  // 0 < k < 1   ->  the delay increases, queues are filling up
+  //   k == 0    ->  the delay does not change
+  //   k <  0    ->  the delay decreases, queues are being emptied
+  double trendline_slope() const { return trendline_ * threshold_gain_; }
+
+  // Returns the number of deltas which the current estimator state is based on.
+  unsigned int num_of_deltas() const { return num_of_deltas_; }
+
+ private:
+  struct DelayInfo {
+    DelayInfo(int64_t time, double delay, size_t slope_count);
+    ~DelayInfo();
+    int64_t time;
+    double delay;
+    std::vector<double> slopes;
+  };
+  // Parameters.
+  const size_t window_size_;
+  const double threshold_gain_;
+  // Used by the existing threshold.
+  unsigned int num_of_deltas_;
+  // Theil-Sen robust line fitting
+  double accumulated_delay_;
+  std::deque<DelayInfo> delay_hist_;
+  PercentileFilter<double> median_filter_;
+  double trendline_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(MedianSlopeEstimator);
+};
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_MEDIAN_SLOPE_ESTIMATOR_H_
diff --git a/modules/congestion_controller/goog_cc/median_slope_estimator_unittest.cc b/modules/congestion_controller/goog_cc/median_slope_estimator_unittest.cc
new file mode 100644
index 0000000..c1ead91
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/median_slope_estimator_unittest.cc
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (c) 2016 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/median_slope_estimator.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+constexpr size_t kWindowSize = 20;
+constexpr double kGain = 1;
+constexpr int64_t kAvgTimeBetweenPackets = 10;
+constexpr size_t kPacketCount = 2 * kWindowSize + 1;
+
+void TestEstimator(double slope, double jitter_stddev, double tolerance) {
+  MedianSlopeEstimator estimator(kWindowSize, kGain);
+  Random random(0x1234567);
+  int64_t send_times[kPacketCount];
+  int64_t recv_times[kPacketCount];
+  int64_t send_start_time = random.Rand(1000000);
+  int64_t recv_start_time = random.Rand(1000000);
+  for (size_t i = 0; i < kPacketCount; ++i) {
+    send_times[i] = send_start_time + i * kAvgTimeBetweenPackets;
+    double latency = i * kAvgTimeBetweenPackets / (1 - slope);
+    double jitter = random.Gaussian(0, jitter_stddev);
+    recv_times[i] = recv_start_time + latency + jitter;
+  }
+  for (size_t i = 1; i < kPacketCount; ++i) {
+    double recv_delta = recv_times[i] - recv_times[i - 1];
+    double send_delta = send_times[i] - send_times[i - 1];
+    estimator.Update(recv_delta, send_delta, recv_times[i]);
+    if (i < kWindowSize)
+      EXPECT_NEAR(estimator.trendline_slope(), 0, 0.001);
+    else
+      EXPECT_NEAR(estimator.trendline_slope(), slope, tolerance);
+  }
+}
+}  // namespace
+
+TEST(MedianSlopeEstimator, PerfectLineSlopeOneHalf) {
+  TestEstimator(0.5, 0, 0.001);
+}
+
+TEST(MedianSlopeEstimator, PerfectLineSlopeMinusOne) {
+  TestEstimator(-1, 0, 0.001);
+}
+
+TEST(MedianSlopeEstimator, PerfectLineSlopeZero) {
+  TestEstimator(0, 0, 0.001);
+}
+
+TEST(MedianSlopeEstimator, JitteryLineSlopeOneHalf) {
+  TestEstimator(0.5, kAvgTimeBetweenPackets / 3.0, 0.01);
+}
+
+TEST(MedianSlopeEstimator, JitteryLineSlopeMinusOne) {
+  TestEstimator(-1, kAvgTimeBetweenPackets / 3.0, 0.05);
+}
+
+TEST(MedianSlopeEstimator, JitteryLineSlopeZero) {
+  TestEstimator(0, kAvgTimeBetweenPackets / 3.0, 0.02);
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc
new file mode 100644
index 0000000..5effa2f
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.cc
@@ -0,0 +1,191 @@
+/*
+ *  Copyright (c) 2016 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/probe_bitrate_estimator.h"
+
+#include <algorithm>
+
+#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h"
+#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "rtc_base/ptr_util.h"
+
+namespace {
+// The minumum number of probes we need to receive feedback about in percent
+// in order to have a valid estimate.
+constexpr int kMinReceivedProbesPercent = 80;
+
+// The minumum number of bytes we need to receive feedback about in percent
+// in order to have a valid estimate.
+constexpr int kMinReceivedBytesPercent = 80;
+
+// The maximum |receive rate| / |send rate| ratio for a valid estimate.
+constexpr float kMaxValidRatio = 2.0f;
+
+// The minimum |receive rate| / |send rate| ratio assuming that the link is
+// not saturated, i.e. we assume that we will receive at least
+// kMinRatioForUnsaturatedLink * |send rate| if |send rate| is less than the
+// link capacity.
+constexpr float kMinRatioForUnsaturatedLink = 0.9f;
+
+// The target utilization of the link. If we know true link capacity
+// we'd like to send at 95% of that rate.
+constexpr float kTargetUtilizationFraction = 0.95f;
+
+// The maximum time period over which the cluster history is retained.
+// This is also the maximum time period beyond which a probing burst is not
+// expected to last.
+constexpr int kMaxClusterHistoryMs = 1000;
+
+// The maximum time interval between first and the last probe on a cluster
+// on the sender side as well as the receive side.
+constexpr int kMaxProbeIntervalMs = 1000;
+}  // namespace
+
+namespace webrtc {
+namespace webrtc_cc {
+
+ProbeBitrateEstimator::ProbeBitrateEstimator(RtcEventLog* event_log)
+    : event_log_(event_log) {}
+
+ProbeBitrateEstimator::~ProbeBitrateEstimator() = default;
+
+int ProbeBitrateEstimator::HandleProbeAndEstimateBitrate(
+    const PacketFeedback& packet_feedback) {
+  int cluster_id = packet_feedback.pacing_info.probe_cluster_id;
+  RTC_DCHECK_NE(cluster_id, PacedPacketInfo::kNotAProbe);
+
+  EraseOldClusters(packet_feedback.arrival_time_ms - kMaxClusterHistoryMs);
+
+  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) {
+    cluster->first_send_ms = packet_feedback.send_time_ms;
+  }
+  if (packet_feedback.send_time_ms > cluster->last_send_ms) {
+    cluster->last_send_ms = packet_feedback.send_time_ms;
+    cluster->size_last_send = payload_size_bits;
+  }
+  if (packet_feedback.arrival_time_ms < cluster->first_receive_ms) {
+    cluster->first_receive_ms = packet_feedback.arrival_time_ms;
+    cluster->size_first_receive = payload_size_bits;
+  }
+  if (packet_feedback.arrival_time_ms > cluster->last_receive_ms) {
+    cluster->last_receive_ms = packet_feedback.arrival_time_ms;
+  }
+  cluster->size_total += payload_size_bits;
+  cluster->num_probes += 1;
+
+  RTC_DCHECK_GT(packet_feedback.pacing_info.probe_cluster_min_probes, 0);
+  RTC_DCHECK_GT(packet_feedback.pacing_info.probe_cluster_min_bytes, 0);
+
+  int min_probes = packet_feedback.pacing_info.probe_cluster_min_probes *
+                   kMinReceivedProbesPercent / 100;
+  int min_bytes = packet_feedback.pacing_info.probe_cluster_min_bytes *
+                  kMinReceivedBytesPercent / 100;
+  if (cluster->num_probes < min_probes || cluster->size_total < min_bytes * 8)
+    return -1;
+
+  float send_interval_ms = cluster->last_send_ms - cluster->first_send_ms;
+  float receive_interval_ms =
+      cluster->last_receive_ms - cluster->first_receive_ms;
+
+  if (send_interval_ms <= 0 || send_interval_ms > kMaxProbeIntervalMs ||
+      receive_interval_ms <= 0 || receive_interval_ms > kMaxProbeIntervalMs) {
+    RTC_LOG(LS_INFO) << "Probing unsuccessful, invalid send/receive interval"
+                     << " [cluster id: " << cluster_id
+                     << "] [send interval: " << send_interval_ms << " ms]"
+                     << " [receive interval: " << receive_interval_ms << " ms]";
+    if (event_log_) {
+      event_log_->Log(rtc::MakeUnique<RtcEventProbeResultFailure>(
+          cluster_id, ProbeFailureReason::kInvalidSendReceiveInterval));
+    }
+    return -1;
+  }
+  // Since the |send_interval_ms| does not include the time it takes to actually
+  // send the last packet the size of the last sent packet should not be
+  // included when calculating the send bitrate.
+  RTC_DCHECK_GT(cluster->size_total, cluster->size_last_send);
+  float send_size = cluster->size_total - cluster->size_last_send;
+  float send_bps = send_size / send_interval_ms * 1000;
+
+  // Since the |receive_interval_ms| does not include the time it takes to
+  // actually receive the first packet the size of the first received packet
+  // should not be included when calculating the receive bitrate.
+  RTC_DCHECK_GT(cluster->size_total, cluster->size_first_receive);
+  float receive_size = cluster->size_total - cluster->size_first_receive;
+  float receive_bps = receive_size / receive_interval_ms * 1000;
+
+  float ratio = receive_bps / send_bps;
+  if (ratio > kMaxValidRatio) {
+    RTC_LOG(LS_INFO) << "Probing unsuccessful, receive/send ratio too high"
+                     << " [cluster id: " << cluster_id
+                     << "] [send: " << send_size << " bytes / "
+                     << send_interval_ms << " ms = " << send_bps / 1000
+                     << " kb/s]"
+                     << " [receive: " << receive_size << " bytes / "
+                     << receive_interval_ms << " ms = " << receive_bps / 1000
+                     << " kb/s]"
+                     << " [ratio: " << receive_bps / 1000 << " / "
+                     << send_bps / 1000 << " = " << ratio
+                     << " > kMaxValidRatio (" << kMaxValidRatio << ")]";
+    if (event_log_) {
+      event_log_->Log(rtc::MakeUnique<RtcEventProbeResultFailure>(
+          cluster_id, ProbeFailureReason::kInvalidSendReceiveRatio));
+    }
+    return -1;
+  }
+  RTC_LOG(LS_INFO) << "Probing successful"
+                   << " [cluster id: " << cluster_id << "] [send: " << send_size
+                   << " bytes / " << send_interval_ms
+                   << " ms = " << send_bps / 1000 << " kb/s]"
+                   << " [receive: " << receive_size << " bytes / "
+                   << receive_interval_ms << " ms = " << receive_bps / 1000
+                   << " kb/s]";
+
+  float res = std::min(send_bps, receive_bps);
+  // If we're receiving at significantly lower bitrate than we were sending at,
+  // it suggests that we've found the true capacity of the link. In this case,
+  // set the target bitrate slightly lower to not immediately overuse.
+  if (receive_bps < kMinRatioForUnsaturatedLink * send_bps) {
+    RTC_DCHECK_GT(send_bps, receive_bps);
+    res = kTargetUtilizationFraction * receive_bps;
+  }
+  if (event_log_) {
+    event_log_->Log(
+        rtc::MakeUnique<RtcEventProbeResultSuccess>(cluster_id, res));
+  }
+  estimated_bitrate_bps_ = res;
+  return *estimated_bitrate_bps_;
+}
+
+rtc::Optional<int>
+ProbeBitrateEstimator::FetchAndResetLastEstimatedBitrateBps() {
+  rtc::Optional<int> estimated_bitrate_bps = estimated_bitrate_bps_;
+  estimated_bitrate_bps_.reset();
+  return estimated_bitrate_bps;
+}
+
+void ProbeBitrateEstimator::EraseOldClusters(int64_t timestamp_ms) {
+  for (auto it = clusters_.begin(); it != clusters_.end();) {
+    if (it->second.last_receive_ms < timestamp_ms) {
+      it = clusters_.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h
new file mode 100644
index 0000000..23d61ee
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator.h
@@ -0,0 +1,57 @@
+/*
+ *  Copyright (c) 2016 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_PROBE_BITRATE_ESTIMATOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_BITRATE_ESTIMATOR_H_
+
+#include <limits>
+#include <map>
+
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+
+namespace webrtc {
+class RtcEventLog;
+namespace webrtc_cc {
+
+class ProbeBitrateEstimator {
+ public:
+  explicit ProbeBitrateEstimator(RtcEventLog* event_log);
+  ~ProbeBitrateEstimator();
+
+  // Should be called for every probe packet we receive feedback about.
+  // Returns the estimated bitrate if the probe completes a valid cluster.
+  int HandleProbeAndEstimateBitrate(const PacketFeedback& packet_feedback);
+
+  rtc::Optional<int> FetchAndResetLastEstimatedBitrateBps();
+
+ private:
+  struct AggregatedCluster {
+    int num_probes = 0;
+    int64_t first_send_ms = std::numeric_limits<int64_t>::max();
+    int64_t last_send_ms = 0;
+    int64_t first_receive_ms = std::numeric_limits<int64_t>::max();
+    int64_t last_receive_ms = 0;
+    int size_last_send = 0;
+    int size_first_receive = 0;
+    int size_total = 0;
+  };
+
+  // Erases old cluster data that was seen before |timestamp_ms|.
+  void EraseOldClusters(int64_t timestamp_ms);
+
+  std::map<int, AggregatedCluster> clusters_;
+  RtcEventLog* const event_log_;
+  rtc::Optional<int> estimated_bitrate_bps_;
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_BITRATE_ESTIMATOR_H_
diff --git a/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc b/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc
new file mode 100644
index 0000000..4a74778
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_bitrate_estimator_unittest.cc
@@ -0,0 +1,223 @@
+/*
+ *  Copyright (c) 2016 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/probe_bitrate_estimator.h"
+
+#include <utility>
+#include <vector>
+
+#include "modules/remote_bitrate_estimator/aimd_rate_control.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+constexpr int kInvalidBitrate = -1;
+constexpr int kDefaultMinProbes = 5;
+constexpr int kDefaultMinBytes = 5000;
+constexpr float kTargetUtilizationFraction = 0.95f;
+}  // anonymous namespace
+
+class TestProbeBitrateEstimator : public ::testing::Test {
+ public:
+  TestProbeBitrateEstimator() : probe_bitrate_estimator_(nullptr) {}
+
+  // TODO(philipel): Use PacedPacketInfo when ProbeBitrateEstimator is rewritten
+  //                 to use that information.
+  void AddPacketFeedback(int probe_cluster_id,
+                         size_t size_bytes,
+                         int64_t send_time_ms,
+                         int64_t arrival_time_ms,
+                         int min_probes = kDefaultMinProbes,
+                         int min_bytes = kDefaultMinBytes) {
+    PacedPacketInfo pacing_info(probe_cluster_id, min_probes, min_bytes);
+    PacketFeedback packet_feedback(arrival_time_ms, send_time_ms, 0, size_bytes,
+                                   pacing_info);
+    measured_bps_ =
+        probe_bitrate_estimator_.HandleProbeAndEstimateBitrate(packet_feedback);
+  }
+
+ protected:
+  int measured_bps_ = kInvalidBitrate;
+  ProbeBitrateEstimator probe_bitrate_estimator_;
+};
+
+TEST_F(TestProbeBitrateEstimator, OneCluster) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+  AddPacketFeedback(0, 1000, 30, 40);
+
+  EXPECT_NEAR(measured_bps_, 800000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, OneClusterTooFewProbes) {
+  AddPacketFeedback(0, 2000, 0, 10);
+  AddPacketFeedback(0, 2000, 10, 20);
+  AddPacketFeedback(0, 2000, 20, 30);
+
+  EXPECT_EQ(kInvalidBitrate, measured_bps_);
+}
+
+TEST_F(TestProbeBitrateEstimator, OneClusterTooFewBytes) {
+  const int kMinBytes = 6000;
+  AddPacketFeedback(0, 800, 0, 10, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 800, 10, 20, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 800, 20, 30, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 800, 30, 40, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 800, 40, 50, kDefaultMinProbes, kMinBytes);
+
+  EXPECT_EQ(kInvalidBitrate, measured_bps_);
+}
+
+TEST_F(TestProbeBitrateEstimator, SmallCluster) {
+  const int kMinBytes = 1000;
+  AddPacketFeedback(0, 150, 0, 10, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 150, 10, 20, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 150, 20, 30, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 150, 30, 40, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 150, 40, 50, kDefaultMinProbes, kMinBytes);
+  AddPacketFeedback(0, 150, 50, 60, kDefaultMinProbes, kMinBytes);
+  EXPECT_NEAR(measured_bps_, 120000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, LargeCluster) {
+  const int kMinProbes = 30;
+  const int kMinBytes = 312500;
+
+  int64_t send_time = 0;
+  int64_t receive_time = 5;
+  for (int i = 0; i < 25; ++i) {
+    AddPacketFeedback(0, 12500, send_time, receive_time, kMinProbes, kMinBytes);
+    ++send_time;
+    ++receive_time;
+  }
+  EXPECT_NEAR(measured_bps_, 100000000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, FastReceive) {
+  AddPacketFeedback(0, 1000, 0, 15);
+  AddPacketFeedback(0, 1000, 10, 30);
+  AddPacketFeedback(0, 1000, 20, 35);
+  AddPacketFeedback(0, 1000, 30, 40);
+
+  EXPECT_NEAR(measured_bps_, 800000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, TooFastReceive) {
+  AddPacketFeedback(0, 1000, 0, 19);
+  AddPacketFeedback(0, 1000, 10, 22);
+  AddPacketFeedback(0, 1000, 20, 25);
+  AddPacketFeedback(0, 1000, 40, 27);
+
+  EXPECT_EQ(measured_bps_, kInvalidBitrate);
+}
+
+TEST_F(TestProbeBitrateEstimator, SlowReceive) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 40);
+  AddPacketFeedback(0, 1000, 20, 70);
+  AddPacketFeedback(0, 1000, 30, 85);
+  // Expected send rate = 800 kbps, expected receive rate = 320 kbps.
+
+  EXPECT_NEAR(measured_bps_, kTargetUtilizationFraction * 320000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, BurstReceive) {
+  AddPacketFeedback(0, 1000, 0, 50);
+  AddPacketFeedback(0, 1000, 10, 50);
+  AddPacketFeedback(0, 1000, 20, 50);
+  AddPacketFeedback(0, 1000, 40, 50);
+
+  EXPECT_EQ(measured_bps_, kInvalidBitrate);
+}
+
+TEST_F(TestProbeBitrateEstimator, MultipleClusters) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+  AddPacketFeedback(0, 1000, 40, 60);
+  // Expected send rate = 600 kbps, expected receive rate = 480 kbps.
+  EXPECT_NEAR(measured_bps_, kTargetUtilizationFraction * 480000, 10);
+
+  AddPacketFeedback(0, 1000, 50, 60);
+  // Expected send rate = 640 kbps, expected receive rate = 640 kbps.
+  EXPECT_NEAR(measured_bps_, 640000, 10);
+
+  AddPacketFeedback(1, 1000, 60, 70);
+  AddPacketFeedback(1, 1000, 65, 77);
+  AddPacketFeedback(1, 1000, 70, 84);
+  AddPacketFeedback(1, 1000, 75, 90);
+  // Expected send rate = 1600 kbps, expected receive rate = 1200 kbps.
+
+  EXPECT_NEAR(measured_bps_, kTargetUtilizationFraction * 1200000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, IgnoreOldClusters) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+
+  AddPacketFeedback(1, 1000, 60, 70);
+  AddPacketFeedback(1, 1000, 65, 77);
+  AddPacketFeedback(1, 1000, 70, 84);
+  AddPacketFeedback(1, 1000, 75, 90);
+  // Expected send rate = 1600 kbps, expected receive rate = 1200 kbps.
+
+  EXPECT_NEAR(measured_bps_, kTargetUtilizationFraction * 1200000, 10);
+
+  // Coming in 6s later
+  AddPacketFeedback(0, 1000, 40 + 6000, 60 + 6000);
+
+  EXPECT_EQ(measured_bps_, kInvalidBitrate);
+}
+
+TEST_F(TestProbeBitrateEstimator, IgnoreSizeLastSendPacket) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+  AddPacketFeedback(0, 1000, 30, 40);
+  AddPacketFeedback(0, 1500, 40, 50);
+  // Expected send rate = 800 kbps, expected receive rate = 900 kbps.
+
+  EXPECT_NEAR(measured_bps_, 800000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, IgnoreSizeFirstReceivePacket) {
+  AddPacketFeedback(0, 1500, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+  AddPacketFeedback(0, 1000, 30, 40);
+  // Expected send rate = 933 kbps, expected receive rate = 800 kbps.
+
+  EXPECT_NEAR(measured_bps_, kTargetUtilizationFraction * 800000, 10);
+}
+
+TEST_F(TestProbeBitrateEstimator, NoLastEstimatedBitrateBps) {
+  EXPECT_FALSE(probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps());
+}
+
+TEST_F(TestProbeBitrateEstimator, FetchLastEstimatedBitrateBps) {
+  AddPacketFeedback(0, 1000, 0, 10);
+  AddPacketFeedback(0, 1000, 10, 20);
+  AddPacketFeedback(0, 1000, 20, 30);
+  AddPacketFeedback(0, 1000, 30, 40);
+
+  auto estimated_bitrate_bps =
+      probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
+  EXPECT_TRUE(estimated_bitrate_bps);
+  EXPECT_NEAR(*estimated_bitrate_bps, 800000, 10);
+  EXPECT_FALSE(probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps());
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc
new file mode 100644
index 0000000..b257032
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_controller.cc
@@ -0,0 +1,310 @@
+/*
+ *  Copyright (c) 2016 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/probe_controller.h"
+
+#include <algorithm>
+#include <initializer_list>
+
+#include "rtc_base/logging.h"
+#include "rtc_base/numerics/safe_conversions.h"
+#include "system_wrappers/include/field_trial.h"
+#include "system_wrappers/include/metrics.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+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;
+
+// Value of |min_bitrate_to_probe_further_bps_| that indicates
+// further probing is disabled.
+constexpr int kExponentialProbingDisabled = 0;
+
+// Default probing bitrate limit. Applied only when the application didn't
+// specify max bitrate.
+constexpr int64_t kDefaultMaxProbingBitrateBps = 5000000;
+
+// Interval between probes when ALR periodic probing is enabled.
+constexpr int64_t kAlrPeriodicProbingIntervalMs = 5000;
+
+// Minimum probe bitrate percentage to probe further for repeated probes,
+// relative to the previous probe. For example, if 1Mbps probe results in
+// 80kbps, then we'll probe again at 1.6Mbps. In that case second probe won't be
+// sent if we get 600kbps from the first one.
+constexpr int kRepeatedProbeMinPercentage = 70;
+
+// If the bitrate drops to a factor |kBitrateDropThreshold| or lower
+// and we recover within |kBitrateDropTimeoutMs|, then we'll send
+// a probe at a fraction |kProbeFractionAfterDrop| of the original bitrate.
+constexpr double kBitrateDropThreshold = 0.66;
+constexpr int kBitrateDropTimeoutMs = 5000;
+constexpr double kProbeFractionAfterDrop = 0.85;
+
+// Timeout for probing after leaving ALR. If the bitrate drops significantly,
+// (as determined by the delay based estimator) and we leave ALR, then we will
+// send a probe if we recover within |kLeftAlrTimeoutMs| ms.
+constexpr int kAlrEndedTimeoutMs = 3000;
+
+// The expected uncertainty of probe result (as a fraction of the target probe
+// This is a limit on how often probing can be done when there is a BW
+// drop detected in ALR.
+constexpr int64_t kMinTimeBetweenAlrProbesMs = 5000;
+
+// bitrate). Used to avoid probing if the probe bitrate is close to our current
+// estimate.
+constexpr double kProbeUncertainty = 0.05;
+
+// Use probing to recover faster after large bitrate estimate drops.
+constexpr char kBweRapidRecoveryExperiment[] =
+    "WebRTC-BweRapidRecoveryExperiment";
+
+}  // namespace
+
+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,
+                                  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) {
+    start_bitrate_bps_ = min_bitrate_bps;
+  }
+
+  // The reason we use the variable |old_max_bitrate_pbs| is because we
+  // need to set |max_bitrate_bps_| before we call InitiateProbing.
+  int64_t old_max_bitrate_bps = max_bitrate_bps_;
+  max_bitrate_bps_ = max_bitrate_bps;
+
+  switch (state_) {
+    case State::kInit:
+      if (network_available_)
+        InitiateExponentialProbing(at_time_ms);
+      break;
+
+    case State::kWaitingForProbingResult:
+      break;
+
+    case State::kProbingComplete:
+      // If the new max bitrate is higher than the old max bitrate and the
+      // estimate is lower than the new max bitrate then initiate probing.
+      if (estimated_bitrate_bps_ != 0 &&
+          old_max_bitrate_bps < max_bitrate_bps_ &&
+          estimated_bitrate_bps_ < max_bitrate_bps_) {
+        // The assumption is that if we jump more than 20% in the bandwidth
+        // estimate or if the bandwidth estimate is within 90% of the new
+        // max bitrate then the probing attempt was successful.
+        mid_call_probing_succcess_threshold_ =
+            std::min(estimated_bitrate_bps_ * 1.2, max_bitrate_bps_ * 0.9);
+        mid_call_probing_waiting_for_result_ = true;
+        mid_call_probing_bitrate_bps_ = max_bitrate_bps_;
+
+        RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated",
+                                   max_bitrate_bps_ / 1000);
+
+        InitiateProbing(at_time_ms, {max_bitrate_bps}, false);
+      }
+      break;
+  }
+}
+
+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(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(at_time_ms, {3 * start_bitrate_bps_, 6 * start_bitrate_bps_},
+                  true);
+}
+
+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_) {
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Success",
+                               mid_call_probing_bitrate_bps_ / 1000);
+    RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.ProbedKbps",
+                               bitrate_bps / 1000);
+    mid_call_probing_waiting_for_result_ = false;
+  }
+
+  if (state_ == State::kWaitingForProbingResult) {
+    // Continue probing if probing results indicate channel has greater
+    // capacity.
+    RTC_LOG(LS_INFO) << "Measured bitrate: " << bitrate_bps
+                     << " Minimum to probe further: "
+                     << min_bitrate_to_probe_further_bps_;
+
+    if (min_bitrate_to_probe_further_bps_ != kExponentialProbingDisabled &&
+        bitrate_bps > min_bitrate_to_probe_further_bps_) {
+      // Double the probing bitrate.
+      InitiateProbing(now_ms, {2 * bitrate_bps}, true);
+    }
+  }
+
+  if (bitrate_bps < kBitrateDropThreshold * estimated_bitrate_bps_) {
+    time_of_last_large_drop_ms_ = now_ms;
+    bitrate_before_last_large_drop_bps_ = estimated_bitrate_bps_;
+  }
+
+  estimated_bitrate_bps_ = bitrate_bps;
+}
+
+void ProbeController::EnablePeriodicAlrProbing(bool enable) {
+  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) {
+  alr_end_time_ms_.emplace(alr_end_time_ms);
+}
+
+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 = alr_start_time_ms_.has_value();
+  bool alr_ended_recently =
+      (alr_end_time_ms_.has_value() &&
+       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 = 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) {
+        RTC_LOG(LS_INFO) << "Detected big bandwidth drop, start probing.";
+        // Track how often we probe in response to bandwidth drop in ALR.
+        RTC_HISTOGRAM_COUNTS_10000(
+            "WebRTC.BWE.BweDropProbingIntervalInS",
+            (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(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 = at_time_ms;
+  last_bwe_drop_probing_time_ms_ = now_ms;
+  alr_end_time_ms_.reset();
+  mid_call_probing_waiting_for_result_ = false;
+  time_of_last_large_drop_ms_ = now_ms;
+  bitrate_before_last_large_drop_bps_ = 0;
+}
+
+void ProbeController::Process(int64_t at_time_ms) {
+  int64_t now_ms = at_time_ms;
+
+  if (now_ms - time_last_probing_initiated_ms_ >
+      kMaxWaitingTimeForProbingResultMs) {
+    mid_call_probing_waiting_for_result_ = false;
+
+    if (state_ == State::kWaitingForProbingResult) {
+      RTC_LOG(LS_INFO) << "kWaitingForProbingResult: timeout";
+      state_ = State::kProbingComplete;
+      min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
+    }
+  }
+
+  if (state_ != State::kProbingComplete || !enable_periodic_alr_probing_)
+    return;
+
+  // Probe bandwidth periodically when in ALR state.
+  if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) {
+    int64_t next_probe_time_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);
+    }
+  }
+}
+
+void ProbeController::InitiateProbing(
+    int64_t now_ms,
+    std::initializer_list<int64_t> bitrates_to_probe,
+    bool probe_further) {
+  for (int64_t bitrate : bitrates_to_probe) {
+    RTC_DCHECK_GT(bitrate, 0);
+    int64_t max_probe_bitrate_bps =
+        max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps;
+    if (bitrate > max_probe_bitrate_bps) {
+      bitrate = max_probe_bitrate_bps;
+      probe_further = false;
+    }
+
+    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) {
+    state_ = State::kWaitingForProbingResult;
+    min_bitrate_to_probe_further_bps_ =
+        (*(bitrates_to_probe.end() - 1)) * kRepeatedProbeMinPercentage / 100;
+  } else {
+    state_ = State::kProbingComplete;
+    min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
+  }
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h
new file mode 100644
index 0000000..23fc4f7
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_controller.h
@@ -0,0 +1,100 @@
+/*
+ *  Copyright (c) 2016 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_PROBE_CONTROLLER_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_CONTROLLER_H_
+
+#include <stdint.h>
+
+#include <initializer_list>
+
+#include "api/optional.h"
+#include "modules/congestion_controller/network_control/include/network_control.h"
+
+namespace webrtc {
+
+class Clock;
+
+namespace webrtc_cc {
+
+// This class controls initiation of probing to estimate initial channel
+// capacity. There is also support for probing during a session when max
+// bitrate is adjusted by an application.
+class ProbeController {
+ public:
+  explicit ProbeController(NetworkControllerObserver* observer);
+  ~ProbeController();
+
+  void SetBitrates(int64_t min_bitrate_bps,
+                   int64_t start_bitrate_bps,
+                   int64_t max_bitrate_bps,
+                   int64_t at_time_ms);
+
+  void OnNetworkAvailability(NetworkAvailability msg);
+
+  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(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(int64_t at_time_ms);
+
+  void Process(int64_t at_time_ms);
+
+ private:
+  enum class State {
+    // Initial state where no probing has been triggered yet.
+    kInit,
+    // Waiting for probing results to continue further probing.
+    kWaitingForProbingResult,
+    // Probing is complete.
+    kProbingComplete,
+  };
+
+  void InitiateExponentialProbing(int64_t at_time_ms);
+  void InitiateProbing(int64_t now_ms,
+                       std::initializer_list<int64_t> bitrates_to_probe,
+                       bool probe_further);
+
+  NetworkControllerObserver* const observer_;
+
+  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_;
+  int64_t mid_call_probing_bitrate_bps_;
+  int64_t mid_call_probing_succcess_threshold_;
+
+  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
+};
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_PROBE_CONTROLLER_H_
diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
new file mode 100644
index 0000000..7ac6b3f
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc
@@ -0,0 +1,292 @@
+/*
+ *  Copyright (c) 2016 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 <memory>
+
+#include "modules/congestion_controller/goog_cc/probe_controller.h"
+#include "modules/congestion_controller/network_control/include/network_types.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::Field;
+using testing::Matcher;
+using testing::NiceMock;
+using testing::Return;
+
+namespace webrtc {
+namespace webrtc_cc {
+namespace test {
+
+namespace {
+
+constexpr int kMinBitrateBps = 100;
+constexpr int kStartBitrateBps = 300;
+constexpr int kMaxBitrateBps = 10000;
+
+constexpr int kExponentialProbingTimeoutMs = 5000;
+
+constexpr int kAlrProbeInterval = 5000;
+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(&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<MockNetworkControllerObserver> cluster_handler_;
+  std::unique_ptr<ProbeController> probe_controller_;
+};
+
+TEST_F(ProbeControllerTest, InitiatesProbingAtStart) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+}
+
+TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
+  SetNetworkAvailable(false);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
+  SetNetworkAvailable(true);
+}
+
+TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+  // Long enough to time out exponential probing.
+  clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
+  probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
+  probe_controller_->Process(NowMs());
+
+  EXPECT_CALL(cluster_handler_,
+              OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps + 100, NowMs());
+}
+
+TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+  // Long enough to time out exponential probing.
+  clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
+  probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
+  probe_controller_->Process(NowMs());
+
+  probe_controller_->SetEstimatedBitrate(kMaxBitrateBps, NowMs());
+  EXPECT_CALL(cluster_handler_,
+              OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps + 100, NowMs());
+}
+
+TEST_F(ProbeControllerTest, TestExponentialProbing) {
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+
+  // Repeated probe should only be sent when estimated bitrate climbs above
+  // 0.7 * 6 * kStartBitrateBps = 1260.
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(1000, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(2 * 1800)));
+  probe_controller_->SetEstimatedBitrate(1800, NowMs());
+}
+
+TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) {
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+
+  // Advance far enough to cause a time out in waiting for probing result.
+  clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
+  probe_controller_->Process(NowMs());
+
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(1800, NowMs());
+}
+
+TEST_F(ProbeControllerTest, RequestProbeInAlr) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
+  probe_controller_->RequestProbe(NowMs());
+}
+
+TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
+  probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
+  clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
+  probe_controller_->RequestProbe(NowMs());
+}
+
+TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
+  probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
+  clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
+  probe_controller_->RequestProbe(NowMs());
+}
+
+TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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(NowMs());
+  probe_controller_->SetEstimatedBitrate(250, NowMs());
+  clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
+  probe_controller_->RequestProbe(NowMs());
+}
+
+TEST_F(ProbeControllerTest, PeriodicProbing) {
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->EnablePeriodicAlrProbing(true);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(1000)))
+      .Times(1);
+  probe_controller_->SetAlrStartTimeMs(start_time);
+  clock_.AdvanceTimeMilliseconds(5000);
+  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(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetAlrStartTimeMs(start_time);
+  clock_.AdvanceTimeMilliseconds(4000);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+
+  EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(1);
+  probe_controller_->SetAlrStartTimeMs(start_time);
+  clock_.AdvanceTimeMilliseconds(1000);
+  probe_controller_->Process(NowMs());
+  probe_controller_->SetEstimatedBitrate(500, NowMs());
+  testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
+}
+
+TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) {
+  NiceMock<MockNetworkControllerObserver> local_handler;
+  probe_controller_.reset(new ProbeController(&local_handler));
+  int64_t alr_start_time = clock_.TimeInMilliseconds();
+
+  probe_controller_->SetAlrStartTimeMs(alr_start_time);
+  EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->EnablePeriodicAlrProbing(true);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 kMaxBitrateBps, NowMs());
+  probe_controller_->Reset(NowMs());
+
+  clock_.AdvanceTimeMilliseconds(10000);
+  probe_controller_->Process(NowMs());
+
+  EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
+  probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
+                                 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_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, NowMs());
+
+  // 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(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
+  probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier, NowMs());
+}
+
+}  // namespace test
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.cc b/modules/congestion_controller/goog_cc/trendline_estimator.cc
new file mode 100644
index 0000000..0dfa822
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/trendline_estimator.cc
@@ -0,0 +1,185 @@
+/*
+ *  Copyright (c) 2016 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/trendline_estimator.h"
+
+#include <math.h>
+
+#include <algorithm>
+
+#include "api/optional.h"
+#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/numerics/safe_minmax.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+rtc::Optional<double> LinearFitSlope(
+    const std::deque<std::pair<double, double>>& points) {
+  RTC_DCHECK(points.size() >= 2);
+  // Compute the "center of mass".
+  double sum_x = 0;
+  double sum_y = 0;
+  for (const auto& point : points) {
+    sum_x += point.first;
+    sum_y += point.second;
+  }
+  double x_avg = sum_x / points.size();
+  double y_avg = sum_y / points.size();
+  // Compute the slope k = \sum (x_i-x_avg)(y_i-y_avg) / \sum (x_i-x_avg)^2
+  double numerator = 0;
+  double denominator = 0;
+  for (const auto& point : points) {
+    numerator += (point.first - x_avg) * (point.second - y_avg);
+    denominator += (point.first - x_avg) * (point.first - x_avg);
+  }
+  if (denominator == 0)
+    return rtc::nullopt;
+  return numerator / denominator;
+}
+
+constexpr double kMaxAdaptOffsetMs = 15.0;
+constexpr double kOverUsingTimeThreshold = 10;
+constexpr int kMinNumDeltas = 60;
+
+}  // namespace
+
+enum { kDeltaCounterMax = 1000 };
+
+TrendlineEstimator::TrendlineEstimator(size_t window_size,
+                                       double smoothing_coef,
+                                       double threshold_gain)
+    : window_size_(window_size),
+      smoothing_coef_(smoothing_coef),
+      threshold_gain_(threshold_gain),
+      num_of_deltas_(0),
+      first_arrival_time_ms_(-1),
+      accumulated_delay_(0),
+      smoothed_delay_(0),
+      delay_hist_(),
+      trendline_(0),
+      k_up_(0.0087),
+      k_down_(0.039),
+      overusing_time_threshold_(kOverUsingTimeThreshold),
+      threshold_(12.5),
+      last_update_ms_(-1),
+      prev_offset_(0.0),
+      time_over_using_(-1),
+      overuse_counter_(0),
+      hypothesis_(BandwidthUsage::kBwNormal) {}
+
+TrendlineEstimator::~TrendlineEstimator() {}
+
+void TrendlineEstimator::Update(double recv_delta_ms,
+                                double send_delta_ms,
+                                int64_t arrival_time_ms) {
+  const double delta_ms = recv_delta_ms - send_delta_ms;
+  ++num_of_deltas_;
+  if (num_of_deltas_ > kDeltaCounterMax)
+    num_of_deltas_ = kDeltaCounterMax;
+  if (first_arrival_time_ms_ == -1)
+    first_arrival_time_ms_ = arrival_time_ms;
+
+  // Exponential backoff filter.
+  accumulated_delay_ += delta_ms;
+  BWE_TEST_LOGGING_PLOT(1, "accumulated_delay_ms", arrival_time_ms,
+                        accumulated_delay_);
+  smoothed_delay_ = smoothing_coef_ * smoothed_delay_ +
+                    (1 - smoothing_coef_) * accumulated_delay_;
+  BWE_TEST_LOGGING_PLOT(1, "smoothed_delay_ms", arrival_time_ms,
+                        smoothed_delay_);
+
+  // Simple linear regression.
+  delay_hist_.push_back(std::make_pair(
+      static_cast<double>(arrival_time_ms - first_arrival_time_ms_),
+      smoothed_delay_));
+  if (delay_hist_.size() > window_size_)
+    delay_hist_.pop_front();
+  if (delay_hist_.size() == window_size_) {
+    // Only update trendline_ if it is possible to fit a line to the data.
+    trendline_ = LinearFitSlope(delay_hist_).value_or(trendline_);
+  }
+
+  BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trendline_);
+
+  Detect(trendline_slope(), send_delta_ms, num_of_deltas(), arrival_time_ms);
+}
+
+BandwidthUsage TrendlineEstimator::State() const {
+  return hypothesis_;
+}
+
+void TrendlineEstimator::Detect(double offset,
+                                double ts_delta,
+                                int num_of_deltas,
+                                int64_t now_ms) {
+  if (num_of_deltas < 2) {
+    hypothesis_ = BandwidthUsage::kBwNormal;
+    return;
+  }
+  const double T = std::min(num_of_deltas, kMinNumDeltas) * offset;
+  BWE_TEST_LOGGING_PLOT(1, "T", now_ms, T);
+  BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
+  if (T > threshold_) {
+    if (time_over_using_ == -1) {
+      // Initialize the timer. Assume that we've been
+      // over-using half of the time since the previous
+      // sample.
+      time_over_using_ = ts_delta / 2;
+    } else {
+      // Increment timer
+      time_over_using_ += ts_delta;
+    }
+    overuse_counter_++;
+    if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {
+      if (offset >= prev_offset_) {
+        time_over_using_ = 0;
+        overuse_counter_ = 0;
+        hypothesis_ = BandwidthUsage::kBwOverusing;
+      }
+    }
+  } else if (T < -threshold_) {
+    time_over_using_ = -1;
+    overuse_counter_ = 0;
+    hypothesis_ = BandwidthUsage::kBwUnderusing;
+  } else {
+    time_over_using_ = -1;
+    overuse_counter_ = 0;
+    hypothesis_ = BandwidthUsage::kBwNormal;
+  }
+  prev_offset_ = offset;
+
+  UpdateThreshold(T, now_ms);
+}
+
+void TrendlineEstimator::UpdateThreshold(double modified_offset,
+                                         int64_t now_ms) {
+  if (last_update_ms_ == -1)
+    last_update_ms_ = now_ms;
+
+  if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {
+    // Avoid adapting the threshold to big latency spikes, caused e.g.,
+    // by a sudden capacity drop.
+    last_update_ms_ = now_ms;
+    return;
+  }
+
+  const double k = fabs(modified_offset) < threshold_ ? k_down_ : k_up_;
+  const int64_t kMaxTimeDeltaMs = 100;
+  int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
+  threshold_ += k * (fabs(modified_offset) - threshold_) * time_delta_ms;
+  threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);
+  last_update_ms_ = now_ms;
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/trendline_estimator.h b/modules/congestion_controller/goog_cc/trendline_estimator.h
new file mode 100644
index 0000000..162c174
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/trendline_estimator.h
@@ -0,0 +1,94 @@
+/*
+ *  Copyright (c) 2016 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_TRENDLINE_ESTIMATOR_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <deque>
+#include <utility>
+
+#include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h"
+#include "rtc_base/constructormagic.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+class TrendlineEstimator : public DelayIncreaseDetectorInterface {
+ public:
+  // |window_size| is the number of points required to compute a trend line.
+  // |smoothing_coef| controls how much we smooth out the delay before fitting
+  // the trend line. |threshold_gain| is used to scale the trendline slope for
+  // comparison to the old threshold. Once the old estimator has been removed
+  // (or the thresholds been merged into the estimators), we can just set the
+  // threshold instead of setting a gain.
+  TrendlineEstimator(size_t window_size,
+                     double smoothing_coef,
+                     double threshold_gain);
+
+  ~TrendlineEstimator() override;
+
+  // Update the estimator with a new sample. The deltas should represent deltas
+  // between timestamp groups as defined by the InterArrival class.
+  void Update(double recv_delta_ms,
+              double send_delta_ms,
+              int64_t arrival_time_ms) override;
+
+  BandwidthUsage State() const override;
+
+  // Returns the estimated trend k multiplied by some gain.
+  // 0 < k < 1   ->  the delay increases, queues are filling up
+  //   k == 0    ->  the delay does not change
+  //   k < 0     ->  the delay decreases, queues are being emptied
+  double trendline_slope() const { return trendline_ * threshold_gain_; }
+
+  // Returns the number of deltas which the current estimator state is based on.
+  unsigned int num_of_deltas() const { return num_of_deltas_; }
+
+ private:
+  void Detect(double offset,
+              double ts_delta,
+              int num_of_deltas,
+              int64_t now_ms);
+
+  void UpdateThreshold(double modified_offset, int64_t now_ms);
+
+  // Parameters.
+  const size_t window_size_;
+  const double smoothing_coef_;
+  const double threshold_gain_;
+  // Used by the existing threshold.
+  unsigned int num_of_deltas_;
+  // Keep the arrival times small by using the change from the first packet.
+  int64_t first_arrival_time_ms_;
+  // Exponential backoff filtering.
+  double accumulated_delay_;
+  double smoothed_delay_;
+  // Linear least squares regression.
+  std::deque<std::pair<double, double>> delay_hist_;
+  double trendline_;
+
+  const double k_up_;
+  const double k_down_;
+  double overusing_time_threshold_;
+  double threshold_;
+  int64_t last_update_ms_;
+  double prev_offset_;
+  double time_over_using_;
+  int overuse_counter_;
+  BandwidthUsage hypothesis_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(TrendlineEstimator);
+};
+}  // namespace webrtc_cc
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_TRENDLINE_ESTIMATOR_H_
diff --git a/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc b/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc
new file mode 100644
index 0000000..376f277
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/trendline_estimator_unittest.cc
@@ -0,0 +1,75 @@
+/*
+ *  Copyright (c) 2016 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/trendline_estimator.h"
+#include "rtc_base/random.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace webrtc_cc {
+
+namespace {
+constexpr size_t kWindowSize = 20;
+constexpr double kSmoothing = 0.0;
+constexpr double kGain = 1;
+constexpr int64_t kAvgTimeBetweenPackets = 10;
+constexpr size_t kPacketCount = 2 * kWindowSize + 1;
+
+void TestEstimator(double slope, double jitter_stddev, double tolerance) {
+  TrendlineEstimator estimator(kWindowSize, kSmoothing, kGain);
+  Random random(0x1234567);
+  int64_t send_times[kPacketCount];
+  int64_t recv_times[kPacketCount];
+  int64_t send_start_time = random.Rand(1000000);
+  int64_t recv_start_time = random.Rand(1000000);
+  for (size_t i = 0; i < kPacketCount; ++i) {
+    send_times[i] = send_start_time + i * kAvgTimeBetweenPackets;
+    double latency = i * kAvgTimeBetweenPackets / (1 - slope);
+    double jitter = random.Gaussian(0, jitter_stddev);
+    recv_times[i] = recv_start_time + latency + jitter;
+  }
+  for (size_t i = 1; i < kPacketCount; ++i) {
+    double recv_delta = recv_times[i] - recv_times[i - 1];
+    double send_delta = send_times[i] - send_times[i - 1];
+    estimator.Update(recv_delta, send_delta, recv_times[i]);
+    if (i < kWindowSize)
+      EXPECT_NEAR(estimator.trendline_slope(), 0, 0.001);
+    else
+      EXPECT_NEAR(estimator.trendline_slope(), slope, tolerance);
+  }
+}
+}  // namespace
+
+TEST(TrendlineEstimator, PerfectLineSlopeOneHalf) {
+  TestEstimator(0.5, 0, 0.001);
+}
+
+TEST(TrendlineEstimator, PerfectLineSlopeMinusOne) {
+  TestEstimator(-1, 0, 0.001);
+}
+
+TEST(TrendlineEstimator, PerfectLineSlopeZero) {
+  TestEstimator(0, 0, 0.001);
+}
+
+TEST(TrendlineEstimator, JitteryLineSlopeOneHalf) {
+  TestEstimator(0.5, kAvgTimeBetweenPackets / 3.0, 0.01);
+}
+
+TEST(TrendlineEstimator, JitteryLineSlopeMinusOne) {
+  TestEstimator(-1, kAvgTimeBetweenPackets / 3.0, 0.075);
+}
+
+TEST(TrendlineEstimator, JitteryLineSlopeZero) {
+  TestEstimator(0, kAvgTimeBetweenPackets / 3.0, 0.02);
+}
+
+}  // namespace webrtc_cc
+}  // namespace webrtc