Fix suspend below min bitrate in new API by making it possible to set min bitrate at the receive-side.

In addition to this the ramp-up tests are refactored to use a receive call instead of only a remote bitrate estimator, and to make use of BaseTest.

BUG=webrtc:4836

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

Cr-Commit-Position: refs/heads/master@{#10087}
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index 21109c2..2c80ccf 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -85,9 +85,6 @@
                             size_t length,
                             const PacketTime& packet_time);
 
-  void SetBitrateControllerConfig(
-      const webrtc::Call::Config::BitrateConfig& bitrate_config);
-
   void ConfigureSync(const std::string& sync_group)
       EXCLUSIVE_LOCKS_REQUIRED(receive_crit_);
 
@@ -159,7 +156,9 @@
   Trace::CreateTrace();
   module_process_thread_->Start();
 
-  SetBitrateControllerConfig(config_.bitrate_config);
+  channel_group_->SetBweBitrates(config_.bitrate_config.min_bitrate_bps,
+                                 config_.bitrate_config.start_bitrate_bps,
+                                 config_.bitrate_config.max_bitrate_bps);
 }
 
 Call::~Call() {
@@ -387,17 +386,9 @@
     return;
   }
   config_.bitrate_config = bitrate_config;
-  SetBitrateControllerConfig(bitrate_config);
-}
-
-void Call::SetBitrateControllerConfig(
-    const webrtc::Call::Config::BitrateConfig& bitrate_config) {
-  BitrateController* bitrate_controller =
-      channel_group_->GetBitrateController();
-  if (bitrate_config.start_bitrate_bps > 0)
-    bitrate_controller->SetStartBitrate(bitrate_config.start_bitrate_bps);
-  bitrate_controller->SetMinMaxBitrate(bitrate_config.min_bitrate_bps,
-                                       bitrate_config.max_bitrate_bps);
+  channel_group_->SetBweBitrates(bitrate_config.min_bitrate_bps,
+                                 bitrate_config.start_bitrate_bps,
+                                 bitrate_config.max_bitrate_bps);
 }
 
 void Call::SignalNetworkState(NetworkState state) {
diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
index 6771c45..2d55732 100644
--- a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
+++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.cc
@@ -15,7 +15,9 @@
 #include <cmath>
 
 #include "webrtc/base/checks.h"
+
 #include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
 
 namespace webrtc {
@@ -25,8 +27,9 @@
 static const double kWithinIncomingBitrateHysteresis = 1.05;
 static const int64_t kMaxFeedbackIntervalMs = 1000;
 
-AimdRateControl::AimdRateControl(uint32_t min_bitrate_bps)
-    : min_configured_bitrate_bps_(min_bitrate_bps),
+AimdRateControl::AimdRateControl()
+    : min_configured_bitrate_bps_(
+          RemoteBitrateEstimator::kDefaultMinBitrateBps),
       max_configured_bitrate_bps_(30000000),
       current_bitrate_bps_(max_configured_bitrate_bps_),
       avg_max_bitrate_kbps_(-1.0f),
@@ -41,11 +44,11 @@
       beta_(0.85f),
       rtt_(kDefaultRttMs),
       time_of_last_log_(-1),
-      in_experiment_(AdaptiveThresholdExperimentIsEnabled()) {
-}
+      in_experiment_(AdaptiveThresholdExperimentIsEnabled()) {}
 
-uint32_t AimdRateControl::GetMinBitrate() const {
-  return min_configured_bitrate_bps_;
+void AimdRateControl::SetMinBitrate(int min_bitrate_bps) {
+  min_configured_bitrate_bps_ = min_bitrate_bps;
+  current_bitrate_bps_ = std::max<int>(min_bitrate_bps, current_bitrate_bps_);
 }
 
 bool AimdRateControl::ValidEstimate() const {
diff --git a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h
index 696b780..bc5ca41 100644
--- a/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h
+++ b/webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h
@@ -23,13 +23,13 @@
 // multiplicatively.
 class AimdRateControl {
  public:
-  explicit AimdRateControl(uint32_t min_bitrate_bps);
+  AimdRateControl();
   virtual ~AimdRateControl() {}
 
   // Returns true if there is a valid estimate of the incoming bitrate, false
   // otherwise.
   bool ValidEstimate() const;
-  uint32_t GetMinBitrate() const;
+  void SetMinBitrate(int min_bitrate_bps);
   int64_t GetFeedbackInterval() const;
   // Returns true if the bitrate estimate hasn't been changed for more than
   // an RTT, or if the incoming_bitrate is more than 5% above the current
@@ -81,8 +81,6 @@
   int64_t rtt_;
   int64_t time_of_last_log_;
   bool in_experiment_;
-
-  RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AimdRateControl);
 };
 }  // namespace webrtc
 
diff --git a/webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h b/webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h
index 7890fb7..91a8ac8 100644
--- a/webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h
+++ b/webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h
@@ -34,6 +34,7 @@
   // From Module.
   MOCK_METHOD0(TimeUntilNextProcess, int64_t());
   MOCK_METHOD0(Process, int32_t());
+  MOCK_METHOD1(SetMinBitrate, void(int));
 };
 
 }  // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h b/webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h
index f201aeb..4bd9d8c 100644
--- a/webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h
+++ b/webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h
@@ -91,6 +91,8 @@
   // Returns true if the statistics are available.
   virtual bool GetStats(ReceiveBandwidthEstimatorStats* output) const = 0;
 
+  virtual void SetMinBitrate(int min_bitrate_bps) = 0;
+
  protected:
   static const int64_t kProcessIntervalMs = 500;
   static const int64_t kStreamTimeOutMs = 2000;
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
index 46dc230..56a309c 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc
@@ -89,8 +89,7 @@
 
   RemoteBitrateEstimatorAbsSendTime::RemoteBitrateEstimatorAbsSendTime(
       RemoteBitrateObserver* observer,
-      Clock* clock,
-      uint32_t min_bitrate_bps)
+      Clock* clock)
       : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
         observer_(observer),
         clock_(clock),
@@ -99,7 +98,6 @@
         estimator_(OverUseDetectorOptions()),
         detector_(OverUseDetectorOptions()),
         incoming_bitrate_(kBitrateWindowMs, 8000),
-        remote_rate_(min_bitrate_bps),
         last_process_time_(-1),
         process_interval_ms_(kProcessIntervalMs),
         total_propagation_delta_ms_(0),
@@ -437,4 +435,9 @@
   total_propagation_delta_ms_ =
       std::max(total_propagation_delta_ms_ + propagation_delta_ms, 0);
 }
+
+void RemoteBitrateEstimatorAbsSendTime::SetMinBitrate(int min_bitrate_bps) {
+  CriticalSectionScoped cs(crit_sect_.get());
+  remote_rate_.SetMinBitrate(min_bitrate_bps);
+}
 }  // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h
index a7086f3..b5ec815 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h
@@ -66,8 +66,7 @@
 class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator {
  public:
   RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer,
-                                    Clock* clock,
-                                    uint32_t min_bitrate_bps);
+                                    Clock* clock);
   virtual ~RemoteBitrateEstimatorAbsSendTime() {}
 
   void IncomingPacketFeedbackVector(
@@ -88,6 +87,7 @@
   bool LatestEstimate(std::vector<unsigned int>* ssrcs,
                       unsigned int* bitrate_bps) const override;
   bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
+  void SetMinBitrate(int min_bitrate_bps) override;
 
  private:
   typedef std::map<unsigned int, int64_t> Ssrcs;
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc
index 692f882..195c95a 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc
@@ -17,13 +17,11 @@
 class RemoteBitrateEstimatorAbsSendTimeTest :
     public RemoteBitrateEstimatorTest {
  public:
-  static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
 
   RemoteBitrateEstimatorAbsSendTimeTest() {}
   virtual void SetUp() {
     bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime(
-        bitrate_observer_.get(), &clock_,
-        kRemoteBitrateEstimatorMinBitrateBps));
+        bitrate_observer_.get(), &clock_));
   }
  protected:
   RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorAbsSendTimeTest);
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
index 6fd54e9..08e076e 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc
@@ -44,11 +44,10 @@
 
   RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream(
       RemoteBitrateObserver* observer,
-      Clock* clock,
-      uint32_t min_bitrate_bps)
+      Clock* clock)
       : clock_(clock),
         incoming_bitrate_(kBitrateWindowMs, 8000),
-        remote_rate_(new AimdRateControl(min_bitrate_bps)),
+        remote_rate_(new AimdRateControl()),
         observer_(observer),
         crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
         last_process_time_(-1),
@@ -164,7 +163,7 @@
   }
   // We can't update the estimate if we don't have any active streams.
   if (overuse_detectors_.empty()) {
-    remote_rate_.reset(new AimdRateControl(remote_rate_->GetMinBitrate()));
+    remote_rate_.reset(new AimdRateControl());
     return;
   }
   double mean_noise_var = sum_var_noise /
@@ -230,4 +229,9 @@
   }
 }
 
+void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) {
+  CriticalSectionScoped cs(crit_sect_.get());
+  remote_rate_->SetMinBitrate(min_bitrate_bps);
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h
index 6d07ad1..2816f8d 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h
@@ -24,8 +24,7 @@
 class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
  public:
   RemoteBitrateEstimatorSingleStream(RemoteBitrateObserver* observer,
-                                     Clock* clock,
-                                     uint32_t min_bitrate_bps);
+                                     Clock* clock);
   virtual ~RemoteBitrateEstimatorSingleStream();
 
   void IncomingPacket(int64_t arrival_time_ms,
@@ -39,6 +38,7 @@
   bool LatestEstimate(std::vector<unsigned int>* ssrcs,
                       unsigned int* bitrate_bps) const override;
   bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
+  void SetMinBitrate(int min_bitrate_bps) override;
 
  private:
   struct Detector;
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
index b0d0fe7..a6c182a 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc
@@ -17,13 +17,11 @@
 class RemoteBitrateEstimatorSingleTest :
     public RemoteBitrateEstimatorTest {
  public:
-  static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
 
   RemoteBitrateEstimatorSingleTest() {}
   virtual void SetUp() {
     bitrate_estimator_.reset(new RemoteBitrateEstimatorSingleStream(
-        bitrate_observer_.get(), &clock_,
-        kRemoteBitrateEstimatorMinBitrateBps));
+        bitrate_observer_.get(), &clock_));
   }
  protected:
   RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorSingleTest);
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
index e91f1c0..73b7b15 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
@@ -63,8 +63,6 @@
   return false;
 }
 
-void RemoteEstimatorProxy::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
-}
 
 int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
   int64_t now = clock_->TimeInMilliseconds();
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h
index 6d7390e..e867ff7 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h
+++ b/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h
@@ -45,7 +45,8 @@
   bool LatestEstimate(std::vector<unsigned int>* ssrcs,
                       unsigned int* bitrate_bps) const override;
   bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
-  void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
+  void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override {}
+  void SetMinBitrate(int min_bitrate_bps) override {}
   int64_t TimeUntilNextProcess() override;
   int32_t Process() override;
 
diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc b/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc
index 8ec2b72..b18b9f0 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc
@@ -69,15 +69,13 @@
       recv_stats_(ReceiveStatistics::Create(&clock_)),
       latest_estimate_bps_(-1),
       last_feedback_ms_(-1),
-      estimator_(new RemoteBitrateEstimatorAbsSendTime(
-          this,
-          &clock_,
-          kRemoteBitrateEstimatorMinBitrateBps)) {
+      estimator_(new RemoteBitrateEstimatorAbsSendTime(this, &clock_)) {
   std::stringstream ss;
   ss << "Estimate_" << flow_id_ << "#1";
   estimate_log_prefix_ = ss.str();
   // Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
   estimator_->OnRttUpdate(50, 50);
+  estimator_->SetMinBitrate(kRemoteBitrateEstimatorMinBitrateBps);
 }
 
 RembReceiver::~RembReceiver() {
diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc
index 37b604d..250d0c1 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc
@@ -23,9 +23,7 @@
 FullBweSender::FullBweSender(int kbps, BitrateObserver* observer, Clock* clock)
     : bitrate_controller_(
           BitrateController::CreateBitrateController(clock, observer)),
-      rbe_(new RemoteBitrateEstimatorAbsSendTime(this,
-                                                 clock,
-                                                 1000 * kMinBitrateKbps)),
+      rbe_(new RemoteBitrateEstimatorAbsSendTime(this, clock)),
       feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
       clock_(clock),
       send_time_history_(10000),
@@ -36,6 +34,7 @@
   bitrate_controller_->SetStartBitrate(1000 * kbps);
   bitrate_controller_->SetMinMaxBitrate(1000 * kMinBitrateKbps,
                                         1000 * kMaxBitrateKbps);
+  rbe_->SetMinBitrate(1000 * kMinBitrateKbps);
 }
 
 FullBweSender::~FullBweSender() {
diff --git a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc
index 7728873..9493805 100644
--- a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc
+++ b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc
@@ -21,8 +21,6 @@
 #include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
 #include "webrtc/test/rtp_file_reader.h"
 
-const int kMinBitrateBps = 30000;
-
 namespace flags {
 
 DEFINE_string(extension_type,
@@ -116,14 +114,14 @@
   if (estimator) {
     switch (extension) {
       case webrtc::kRtpExtensionAbsoluteSendTime: {
-        *estimator = new webrtc::RemoteBitrateEstimatorAbsSendTime(
-            observer, clock, kMinBitrateBps);
+        *estimator =
+            new webrtc::RemoteBitrateEstimatorAbsSendTime(observer, clock);
           *estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator";
           break;
         }
       case webrtc::kRtpExtensionTransmissionTimeOffset: {
-        *estimator = new webrtc::RemoteBitrateEstimatorSingleStream(
-            observer, clock, kMinBitrateBps);
+        *estimator =
+            new webrtc::RemoteBitrateEstimatorSingleStream(observer, clock);
           *estimator_used = "RemoteBitrateEstimator";
           break;
         }
diff --git a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h
index 2969c29..56b2c73 100644
--- a/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h
+++ b/webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h
@@ -39,6 +39,10 @@
 
   void SetBitrateEstimator(RemoteBitrateEstimator* rbe);
 
+  RemoteBitrateEstimator* GetBitrateEstimator() const {
+    return bitrate_estimator_.get();
+  }
+
  private:
   void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
                                unsigned int bitrate) override;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
index eb6d35e..ad7d66b 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc
@@ -55,8 +55,6 @@
 
 class RtcpFormatRembTest : public ::testing::Test {
  protected:
-  static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
-
   RtcpFormatRembTest()
       : over_use_detector_options_(),
         system_clock_(Clock::GetRealTimeClock()),
@@ -66,10 +64,9 @@
         rtcp_receiver_(nullptr),
         test_transport_(nullptr),
         remote_bitrate_observer_(),
-        remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream(
-            &remote_bitrate_observer_,
-            system_clock_,
-            kRemoteBitrateEstimatorMinBitrateBps)) {}
+        remote_bitrate_estimator_(
+            new RemoteBitrateEstimatorSingleStream(&remote_bitrate_observer_,
+                                                   system_clock_)) {}
   void SetUp() override;
   void TearDown() override;
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index e09c29d..2e99009 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -58,16 +58,13 @@
 
 class RtcpReceiverTest : public ::testing::Test {
  protected:
-  static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
-
   RtcpReceiverTest()
       : over_use_detector_options_(),
         system_clock_(1335900000),
         remote_bitrate_observer_(),
-        remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream(
-            &remote_bitrate_observer_,
-            &system_clock_,
-            kRemoteBitrateEstimatorMinBitrateBps)) {
+        remote_bitrate_estimator_(
+            new RemoteBitrateEstimatorSingleStream(&remote_bitrate_observer_,
+                                                   &system_clock_)) {
     test_transport_ = new TestTransport();
 
     RtpRtcp::Configuration configuration;
diff --git a/webrtc/test/rtp_rtcp_observer.h b/webrtc/test/rtp_rtcp_observer.h
index 8e88716..38e2fa7 100644
--- a/webrtc/test/rtp_rtcp_observer.h
+++ b/webrtc/test/rtp_rtcp_observer.h
@@ -171,9 +171,9 @@
   rtc::CriticalSection crit_;
   const rtc::scoped_ptr<EventWrapper> observation_complete_;
   const rtc::scoped_ptr<RtpHeaderParser> parser_;
+  PacketTransport send_transport_, receive_transport_;
 
  private:
-  PacketTransport send_transport_, receive_transport_;
   unsigned int timeout_ms_;
 };
 }  // namespace test
diff --git a/webrtc/video/rampup_tests.cc b/webrtc/video/rampup_tests.cc
index f69f8ce..ec01420 100644
--- a/webrtc/video/rampup_tests.cc
+++ b/webrtc/video/rampup_tests.cc
@@ -29,8 +29,7 @@
 namespace webrtc {
 namespace {
 
-static const int kMaxPacketSize = 1500;
-const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
+static const int64_t kPollIntervalMs = 250;
 
 std::vector<uint32_t> GenerateSsrcs(size_t num_streams,
                                     uint32_t ssrc_offset) {
@@ -41,294 +40,298 @@
 }
 }  // namespace
 
-StreamObserver::StreamObserver(const SsrcMap& rtx_media_ssrcs,
-                               newapi::Transport* feedback_transport,
-                               Clock* clock)
-    : clock_(clock),
-      test_done_(EventWrapper::Create()),
-      rtp_parser_(RtpHeaderParser::Create()),
-      feedback_transport_(feedback_transport),
-      receive_stats_(ReceiveStatistics::Create(clock)),
-      payload_registry_(
-          new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(false))),
-      remote_bitrate_estimator_(nullptr),
+RampUpTester::RampUpTester(size_t num_streams,
+                           unsigned int start_bitrate_bps,
+                           const std::string& extension_type,
+                           bool rtx,
+                           bool red)
+    : EndToEndTest(test::CallTest::kLongTimeoutMs),
+      event_(false, false),
+      clock_(Clock::GetRealTimeClock()),
+      num_streams_(num_streams),
+      rtx_(rtx),
+      red_(red),
+      send_stream_(nullptr),
+      start_bitrate_bps_(start_bitrate_bps),
+      start_bitrate_verified_(false),
       expected_bitrate_bps_(0),
-      start_bitrate_bps_(0),
-      rtx_media_ssrcs_(rtx_media_ssrcs),
-      total_sent_(0),
-      padding_sent_(0),
-      rtx_media_sent_(0),
-      total_packets_sent_(0),
-      padding_packets_sent_(0),
-      rtx_media_packets_sent_(0),
       test_start_ms_(clock_->TimeInMilliseconds()),
-      ramp_up_finished_ms_(0) {
-  // Ideally we would only have to instantiate an RtcpSender, an
-  // RtpHeaderParser and a RemoteBitrateEstimator here, but due to the current
-  // state of the RTP module we need a full module and receive statistics to
-  // be able to produce an RTCP with REMB.
-  RtpRtcp::Configuration config;
-  config.receive_statistics = receive_stats_.get();
-  feedback_transport_.Enable();
-  config.outgoing_transport = &feedback_transport_;
-  rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
-  rtp_rtcp_->SetREMBStatus(true);
-  rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
-  packet_router_.reset(new PacketRouter());
-  packet_router_->AddRtpModule(rtp_rtcp_.get());
-  rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
-                                          kAbsSendTimeExtensionId);
-  rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
-                                          kTransmissionTimeOffsetExtensionId);
-  rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
-                                          kTransportSequenceNumberExtensionId);
-  payload_registry_->SetRtxPayloadType(RampUpTest::kSendRtxPayloadType,
-                                       RampUpTest::kFakeSendPayloadType);
-}
-
-StreamObserver::~StreamObserver() {
-  packet_router_->RemoveRtpModule(rtp_rtcp_.get());
-}
-
-void StreamObserver::set_expected_bitrate_bps(
-    unsigned int expected_bitrate_bps) {
-  rtc::CritScope lock(&crit_);
-  expected_bitrate_bps_ = expected_bitrate_bps;
-}
-
-void StreamObserver::set_start_bitrate_bps(unsigned int start_bitrate_bps) {
-  rtc::CritScope lock(&crit_);
-  start_bitrate_bps_ = start_bitrate_bps;
-}
-
-void StreamObserver::OnReceiveBitrateChanged(
-    const std::vector<unsigned int>& ssrcs, unsigned int bitrate) {
-  rtc::CritScope lock(&crit_);
-  RTC_DCHECK_GT(expected_bitrate_bps_, 0u);
-  if (start_bitrate_bps_ != 0) {
-    // For tests with an explicitly set start bitrate, verify the first
-    // bitrate estimate is close to the start bitrate and lower than the
-    // test target bitrate. This is to verify a call respects the configured
-    // start bitrate, but due to the BWE implementation we can't guarantee the
-    // first estimate really is as high as the start bitrate.
-    EXPECT_GT(bitrate, 0.9 * start_bitrate_bps_);
-    start_bitrate_bps_ = 0;
+      ramp_up_finished_ms_(-1),
+      extension_type_(extension_type),
+      ssrcs_(GenerateSsrcs(num_streams, 100)),
+      rtx_ssrcs_(GenerateSsrcs(num_streams, 200)),
+      poller_thread_(ThreadWrapper::CreateThread(&BitrateStatsPollingThread,
+                                                 this,
+                                                 "BitrateStatsPollingThread")),
+      sender_call_(nullptr) {
+  if (rtx_) {
+    for (size_t i = 0; i < ssrcs_.size(); ++i)
+      rtx_ssrc_map_[rtx_ssrcs_[i]] = ssrcs_[i];
   }
-  if (bitrate >= expected_bitrate_bps_) {
-    ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
-    // Just trigger if there was any rtx padding packet.
-    if (rtx_media_ssrcs_.empty() || rtx_media_sent_ > 0) {
-      TriggerTestDone();
+  poller_thread_->Start();
+}
+
+RampUpTester::~RampUpTester() {
+  event_.Set();
+  poller_thread_->Stop();
+}
+
+Call::Config RampUpTester::GetSenderCallConfig() {
+  Call::Config call_config;
+  if (start_bitrate_bps_ != 0) {
+    call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps_;
+  }
+  call_config.bitrate_config.min_bitrate_bps = 10000;
+  return call_config;
+}
+
+void RampUpTester::OnStreamsCreated(
+    VideoSendStream* send_stream,
+    const std::vector<VideoReceiveStream*>& receive_streams) {
+  send_stream_ = send_stream;
+}
+
+size_t RampUpTester::GetNumStreams() const {
+  return num_streams_;
+}
+
+void RampUpTester::ModifyConfigs(
+    VideoSendStream::Config* send_config,
+    std::vector<VideoReceiveStream::Config>* receive_configs,
+    VideoEncoderConfig* encoder_config) {
+  send_config->suspend_below_min_bitrate = true;
+
+  if (num_streams_ == 1) {
+    encoder_config->streams[0].target_bitrate_bps =
+        encoder_config->streams[0].max_bitrate_bps = 2000000;
+    // For single stream rampup until 1mbps
+    expected_bitrate_bps_ = kSingleStreamTargetBps;
+  } else {
+    // For multi stream rampup until all streams are being sent. That means
+    // enough birate to send all the target streams plus the min bitrate of
+    // the last one.
+    expected_bitrate_bps_ = encoder_config->streams.back().min_bitrate_bps;
+    for (size_t i = 0; i < encoder_config->streams.size() - 1; ++i) {
+      expected_bitrate_bps_ += encoder_config->streams[i].target_bitrate_bps;
     }
   }
-  rtp_rtcp_->SetREMBData(bitrate, ssrcs);
-  rtp_rtcp_->Process();
-}
 
-bool StreamObserver::SendRtp(const uint8_t* packet, size_t length) {
-  rtc::CritScope lock(&crit_);
-  RTPHeader header;
-  EXPECT_TRUE(rtp_parser_->Parse(packet, length, &header));
-  receive_stats_->IncomingPacket(header, length, false);
-  payload_registry_->SetIncomingPayloadType(header);
-  RTC_DCHECK(remote_bitrate_estimator_ != nullptr);
-  remote_bitrate_estimator_->IncomingPacket(
-      clock_->TimeInMilliseconds(), length - header.headerLength, header, true);
-  if (remote_bitrate_estimator_->TimeUntilNextProcess() <= 0) {
-    remote_bitrate_estimator_->Process();
-    rtp_rtcp_->Process();
-  }
-  total_sent_ += length;
-  padding_sent_ += header.paddingLength;
-  ++total_packets_sent_;
-  if (header.paddingLength > 0)
-    ++padding_packets_sent_;
-  // Handle RTX retransmission, but only for non-padding-only packets.
-  if (rtx_media_ssrcs_.find(header.ssrc) != rtx_media_ssrcs_.end() &&
-      header.headerLength + header.paddingLength != length) {
-    rtx_media_sent_ += length - header.headerLength - header.paddingLength;
-    if (header.paddingLength == 0)
-      ++rtx_media_packets_sent_;
-    uint8_t restored_packet[kMaxPacketSize];
-    uint8_t* restored_packet_ptr = restored_packet;
-    size_t restored_length = length;
-    EXPECT_TRUE(payload_registry_->RestoreOriginalPacket(
-        &restored_packet_ptr, packet, &restored_length,
-        rtx_media_ssrcs_[header.ssrc], header));
-    EXPECT_TRUE(
-        rtp_parser_->Parse(restored_packet_ptr, restored_length, &header));
+  send_config->rtp.extensions.clear();
+
+  bool remb;
+  if (extension_type_ == RtpExtension::kAbsSendTime) {
+    remb = true;
+    send_config->rtp.extensions.push_back(
+        RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
+  } else if (extension_type_ == RtpExtension::kTransportSequenceNumber) {
+    remb = false;
+    send_config->rtp.extensions.push_back(RtpExtension(
+        extension_type_.c_str(), kTransportSequenceNumberExtensionId));
   } else {
-    rtp_rtcp_->SetRemoteSSRC(header.ssrc);
+    remb = true;
+    send_config->rtp.extensions.push_back(RtpExtension(
+        extension_type_.c_str(), kTransmissionTimeOffsetExtensionId));
   }
-  return true;
+
+  send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
+  send_config->rtp.ssrcs = ssrcs_;
+  if (rtx_) {
+    send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
+    send_config->rtp.rtx.ssrcs = rtx_ssrcs_;
+  }
+  if (red_) {
+    send_config->rtp.fec.ulpfec_payload_type =
+        test::CallTest::kUlpfecPayloadType;
+    send_config->rtp.fec.red_payload_type = test::CallTest::kRedPayloadType;
+  }
+
+  size_t i = 0;
+  for (VideoReceiveStream::Config& recv_config : *receive_configs) {
+    recv_config.rtp.remb = remb;
+    recv_config.rtp.extensions = send_config->rtp.extensions;
+
+    recv_config.rtp.remote_ssrc = ssrcs_[i];
+    recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms;
+
+    if (red_) {
+      recv_config.rtp.fec.red_payload_type =
+          send_config->rtp.fec.red_payload_type;
+      recv_config.rtp.fec.ulpfec_payload_type =
+          send_config->rtp.fec.ulpfec_payload_type;
+    }
+
+    if (rtx_) {
+      recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc =
+          rtx_ssrcs_[i];
+      recv_config.rtp.rtx[send_config->encoder_settings.payload_type]
+          .payload_type = send_config->rtp.rtx.payload_type;
+    }
+    ++i;
+  }
 }
 
-bool StreamObserver::SendRtcp(const uint8_t* packet, size_t length) {
-  return true;
+void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) {
+  sender_call_ = sender_call;
 }
 
-EventTypeWrapper StreamObserver::Wait() {
-  return test_done_->Wait(test::CallTest::kLongTimeoutMs);
+bool RampUpTester::BitrateStatsPollingThread(void* obj) {
+  return static_cast<RampUpTester*>(obj)->PollStats();
 }
 
-void StreamObserver::SetRemoteBitrateEstimator(RemoteBitrateEstimator* rbe) {
-  remote_bitrate_estimator_.reset(rbe);
+bool RampUpTester::PollStats() {
+  if (sender_call_) {
+    Call::Stats stats = sender_call_->GetStats();
+
+    RTC_DCHECK_GT(expected_bitrate_bps_, 0);
+    if (!start_bitrate_verified_ && start_bitrate_bps_ != 0) {
+      // For tests with an explicitly set start bitrate, verify the first
+      // bitrate estimate is close to the start bitrate and lower than the
+      // test target bitrate. This is to verify a call respects the configured
+      // start bitrate, but due to the BWE implementation we can't guarantee the
+      // first estimate really is as high as the start bitrate.
+      EXPECT_GT(stats.send_bandwidth_bps, 0.9 * start_bitrate_bps_);
+      start_bitrate_verified_ = true;
+    }
+    if (stats.send_bandwidth_bps >= expected_bitrate_bps_) {
+      ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
+      observation_complete_->Set();
+    }
+  }
+
+  return !event_.Wait(kPollIntervalMs);
 }
 
-PacketRouter* StreamObserver::GetPacketRouter() {
-  return packet_router_.get();
-}
-
-void StreamObserver::ReportResult(const std::string& measurement,
-                  size_t value,
-                  const std::string& units) {
+void RampUpTester::ReportResult(const std::string& measurement,
+                                size_t value,
+                                const std::string& units) const {
   webrtc::test::PrintResult(
       measurement, "",
       ::testing::UnitTest::GetInstance()->current_test_info()->name(),
       value, units, false);
 }
 
-void StreamObserver::TriggerTestDone() EXCLUSIVE_LOCKS_REQUIRED(crit_) {
-  ReportResult("ramp-up-total-sent", total_sent_, "bytes");
-  ReportResult("ramp-up-padding-sent", padding_sent_, "bytes");
-  ReportResult("ramp-up-rtx-media-sent", rtx_media_sent_, "bytes");
-  ReportResult("ramp-up-total-packets-sent", total_packets_sent_, "packets");
-  ReportResult("ramp-up-padding-packets-sent",
-               padding_packets_sent_,
-               "packets");
-  ReportResult("ramp-up-rtx-packets-sent",
-               rtx_media_packets_sent_,
-               "packets");
-  ReportResult("ramp-up-time",
-               ramp_up_finished_ms_ - test_start_ms_,
-               "milliseconds");
-  test_done_->Set();
+void RampUpTester::GetStats(const VideoSendStream::StreamStats& stream,
+                            size_t* total_packets_sent,
+                            size_t* total_sent,
+                            size_t* padding_sent,
+                            size_t* media_sent) const {
+  *total_packets_sent += stream.rtp_stats.transmitted.packets +
+                         stream.rtp_stats.retransmitted.packets +
+                         stream.rtp_stats.fec.packets;
+  *total_sent += stream.rtp_stats.transmitted.TotalBytes() +
+                 stream.rtp_stats.retransmitted.TotalBytes() +
+                 stream.rtp_stats.fec.TotalBytes();
+  *padding_sent += stream.rtp_stats.transmitted.padding_bytes +
+                   stream.rtp_stats.retransmitted.padding_bytes +
+                   stream.rtp_stats.fec.padding_bytes;
+  *media_sent += stream.rtp_stats.MediaPayloadBytes();
 }
 
-LowRateStreamObserver::LowRateStreamObserver(
-    newapi::Transport* feedback_transport,
-    Clock* clock,
-    size_t number_of_streams,
-    bool rtx_used)
-    : clock_(clock),
-      number_of_streams_(number_of_streams),
-      rtx_used_(rtx_used),
-      test_done_(EventWrapper::Create()),
-      rtp_parser_(RtpHeaderParser::Create()),
-      feedback_transport_(feedback_transport),
-      receive_stats_(ReceiveStatistics::Create(clock)),
-      send_stream_(nullptr),
+void RampUpTester::TriggerTestDone() {
+  VideoSendStream::Stats send_stats = send_stream_->GetStats();
+
+  size_t total_packets_sent = 0;
+  size_t total_sent = 0;
+  size_t padding_sent = 0;
+  size_t media_sent = 0;
+  for (uint32_t ssrc : ssrcs_) {
+    GetStats(send_stats.substreams[ssrc], &total_packets_sent, &total_sent,
+             &padding_sent, &media_sent);
+  }
+
+  size_t rtx_total_packets_sent = 0;
+  size_t rtx_total_sent = 0;
+  size_t rtx_padding_sent = 0;
+  size_t rtx_media_sent = 0;
+  for (uint32_t rtx_ssrc : rtx_ssrcs_) {
+    GetStats(send_stats.substreams[rtx_ssrc], &total_packets_sent, &total_sent,
+             &padding_sent, &media_sent);
+  }
+
+  ReportResult("ramp-up-total-packets-sent", total_packets_sent, "packets");
+  ReportResult("ramp-up-total-sent", total_sent, "bytes");
+  ReportResult("ramp-up-media-sent", media_sent, "bytes");
+  ReportResult("ramp-up-padding-sent", padding_sent, "bytes");
+  ReportResult("ramp-up-rtx-total-packets-sent", rtx_total_packets_sent,
+               "packets");
+  ReportResult("ramp-up-rtx-total-sent", rtx_total_sent, "bytes");
+  ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, "bytes");
+  ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, "bytes");
+  if (ramp_up_finished_ms_ >= 0) {
+    ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_,
+                 "milliseconds");
+  }
+}
+
+void RampUpTester::PerformTest() {
+  if (Wait() != kEventSignaled) {
+    printf("Timed out while waiting for ramp-up to complete.");
+    return;
+  }
+  TriggerTestDone();
+}
+
+RampUpDownUpTester::RampUpDownUpTester(size_t num_streams,
+                                       unsigned int start_bitrate_bps,
+                                       const std::string& extension_type,
+                                       bool rtx,
+                                       bool red)
+    : RampUpTester(num_streams, start_bitrate_bps, extension_type, rtx, red),
       test_state_(kFirstRampup),
       state_start_ms_(clock_->TimeInMilliseconds()),
-      interval_start_ms_(state_start_ms_),
-      last_remb_bps_(0),
-      sent_bytes_(0),
-      total_overuse_bytes_(0),
-      suspended_in_stats_(false) {
-  RtpRtcp::Configuration config;
-  config.receive_statistics = receive_stats_.get();
-  feedback_transport_.Enable();
-  config.outgoing_transport = &feedback_transport_;
-  rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
-  rtp_rtcp_->SetREMBStatus(true);
-  rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
-  rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
-                                          kAbsSendTimeExtensionId);
-  const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 10000;
-  remote_bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime(
-      this, clock, kRemoteBitrateEstimatorMinBitrateBps));
+      interval_start_ms_(clock_->TimeInMilliseconds()),
+      sent_bytes_(0) {
   forward_transport_config_.link_capacity_kbps =
       kHighBandwidthLimitBps / 1000;
-  forward_transport_config_.queue_length_packets = 100;  // Something large.
-  test::DirectTransport::SetConfig(forward_transport_config_);
-  test::DirectTransport::SetReceiver(this);
+  send_transport_.SetConfig(forward_transport_config_);
 }
 
-void LowRateStreamObserver::SetSendStream(VideoSendStream* send_stream) {
-  rtc::CritScope lock(&crit_);
-  send_stream_ = send_stream;
-}
+RampUpDownUpTester::~RampUpDownUpTester() {}
 
-void LowRateStreamObserver::OnReceiveBitrateChanged(
-    const std::vector<unsigned int>& ssrcs,
-    unsigned int bitrate) {
-  rtc::CritScope lock(&crit_);
-  rtp_rtcp_->SetREMBData(bitrate, ssrcs);
-  rtp_rtcp_->Process();
-  last_remb_bps_ = bitrate;
-}
-
-bool LowRateStreamObserver::SendRtp(const uint8_t* data, size_t length) {
-  rtc::CritScope lock(&crit_);
-  sent_bytes_ += length;
-  int64_t now_ms = clock_->TimeInMilliseconds();
-  if (now_ms > interval_start_ms_ + 1000) {  // Let at least 1 second pass.
-    // Verify that the send rate was about right.
-    unsigned int average_rate_bps = static_cast<unsigned int>(sent_bytes_) *
-                                    8 * 1000 / (now_ms - interval_start_ms_);
-    // TODO(holmer): Why is this failing?
-    // EXPECT_LT(average_rate_bps, last_remb_bps_ * 1.1);
-    if (average_rate_bps > last_remb_bps_ * 1.1) {
-      total_overuse_bytes_ +=
-          sent_bytes_ -
-          last_remb_bps_ / 8 * (now_ms - interval_start_ms_) / 1000;
+bool RampUpDownUpTester::PollStats() {
+  if (send_stream_) {
+    webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
+    int transmit_bitrate_bps = 0;
+    for (auto it : stats.substreams) {
+      transmit_bitrate_bps += it.second.total_bitrate_bps;
     }
-    EvolveTestState(average_rate_bps);
-    interval_start_ms_ = now_ms;
-    sent_bytes_ = 0;
+
+    EvolveTestState(transmit_bitrate_bps, stats.suspended);
   }
-  return test::DirectTransport::SendRtp(data, length);
+
+  return !event_.Wait(kPollIntervalMs);
 }
 
-PacketReceiver::DeliveryStatus LowRateStreamObserver::DeliverPacket(
-    MediaType media_type,
-    const uint8_t* packet,
-    size_t length,
-    const PacketTime& packet_time) {
-  rtc::CritScope lock(&crit_);
-  RTPHeader header;
-  EXPECT_TRUE(rtp_parser_->Parse(packet, length, &header));
-  receive_stats_->IncomingPacket(header, length, false);
-  remote_bitrate_estimator_->IncomingPacket(
-      clock_->TimeInMilliseconds(), length - header.headerLength, header, true);
-  if (remote_bitrate_estimator_->TimeUntilNextProcess() <= 0) {
-    remote_bitrate_estimator_->Process();
-  }
-  suspended_in_stats_ = send_stream_->GetStats().suspended;
-  return DELIVERY_OK;
+Call::Config RampUpDownUpTester::GetReceiverCallConfig() {
+  Call::Config config;
+  config.bitrate_config.min_bitrate_bps = 10000;
+  return config;
 }
 
-bool LowRateStreamObserver::SendRtcp(const uint8_t* packet, size_t length) {
-  return true;
-}
-
-std::string LowRateStreamObserver::GetModifierString() {
+std::string RampUpDownUpTester::GetModifierString() const {
   std::string str("_");
   char temp_str[5];
-  sprintf(temp_str, "%i",
-      static_cast<int>(number_of_streams_));
+  sprintf(temp_str, "%i", static_cast<int>(num_streams_));
   str += std::string(temp_str);
   str += "stream";
-  str += (number_of_streams_ > 1 ? "s" : "");
+  str += (num_streams_ > 1 ? "s" : "");
   str += "_";
-  str += (rtx_used_ ? "" : "no");
+  str += (rtx_ ? "" : "no");
   str += "rtx";
   return str;
 }
 
-void LowRateStreamObserver::EvolveTestState(unsigned int bitrate_bps) {
+void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) {
   int64_t now = clock_->TimeInMilliseconds();
-  rtc::CritScope lock(&crit_);
-  RTC_DCHECK(send_stream_ != nullptr);
   switch (test_state_) {
     case kFirstRampup: {
-      EXPECT_FALSE(suspended_in_stats_);
+      EXPECT_FALSE(suspended);
       if (bitrate_bps > kExpectedHighBitrateBps) {
         // The first ramp-up has reached the target bitrate. Change the
         // channel limit, and move to the next test state.
         forward_transport_config_.link_capacity_kbps =
             kLowBandwidthLimitBps / 1000;
-        test::DirectTransport::SetConfig(forward_transport_config_);
+        send_transport_.SetConfig(forward_transport_config_);
         test_state_ = kLowRate;
         webrtc::test::PrintResult("ramp_up_down_up",
                                   GetModifierString(),
@@ -343,12 +346,12 @@
       break;
     }
     case kLowRate: {
-      if (bitrate_bps < kExpectedLowBitrateBps && suspended_in_stats_) {
+      if (bitrate_bps < kExpectedLowBitrateBps && suspended) {
         // The ramp-down was successful. Change the channel limit back to a
         // high value, and move to the next test state.
         forward_transport_config_.link_capacity_kbps =
             kHighBandwidthLimitBps / 1000;
-        test::DirectTransport::SetConfig(forward_transport_config_);
+        send_transport_.SetConfig(forward_transport_config_);
         test_state_ = kSecondRampup;
         webrtc::test::PrintResult("ramp_up_down_up",
                                   GetModifierString(),
@@ -363,299 +366,135 @@
       break;
     }
     case kSecondRampup: {
-      if (bitrate_bps > kExpectedHighBitrateBps && !suspended_in_stats_) {
+      if (bitrate_bps > kExpectedHighBitrateBps && !suspended) {
         webrtc::test::PrintResult("ramp_up_down_up",
                                   GetModifierString(),
                                   "second_rampup",
                                   now - state_start_ms_,
                                   "ms",
                                   false);
-        webrtc::test::PrintResult("ramp_up_down_up",
-                                  GetModifierString(),
-                                  "total_overuse",
-                                  total_overuse_bytes_,
-                                  "bytes",
-                                  false);
-        test_done_->Set();
+        observation_complete_->Set();
       }
       break;
     }
   }
 }
 
-EventTypeWrapper LowRateStreamObserver::Wait() {
-  return test_done_->Wait(test::CallTest::kLongTimeoutMs);
-}
-
-class SendBitrateAdapter {
+class RampUpTest : public test::CallTest {
  public:
-  static const int64_t kPollIntervalMs = 250;
+  RampUpTest() {}
 
-  SendBitrateAdapter(const Call& call,
-                     const std::vector<uint32_t>& ssrcs,
-                     RemoteBitrateObserver* bitrate_observer)
-      : event_(false, false),
-        call_(call),
-        ssrcs_(ssrcs),
-        bitrate_observer_(bitrate_observer) {
-    RTC_DCHECK(bitrate_observer != nullptr);
-    poller_thread_ = ThreadWrapper::CreateThread(&SendBitrateAdapterThread,
-                                                 this, "SendBitratePoller");
-    bool thread_start_ok = poller_thread_->Start();
-    RTC_DCHECK(thread_start_ok);
+  virtual ~RampUpTest() {
+    EXPECT_EQ(nullptr, send_stream_);
+    EXPECT_TRUE(receive_streams_.empty());
   }
-
-  virtual ~SendBitrateAdapter() {
-    event_.Set();
-    poller_thread_->Stop();
-  }
-
- private:
-  static bool SendBitrateAdapterThread(void* obj) {
-    return static_cast<SendBitrateAdapter*>(obj)->PollStats();
-  }
-
-  bool PollStats() {
-    Call::Stats stats = call_.GetStats();
-
-    bitrate_observer_->OnReceiveBitrateChanged(ssrcs_,
-                                               stats.send_bandwidth_bps);
-    return !event_.Wait(kPollIntervalMs);
-  }
-
-  rtc::Event event_;
-  rtc::scoped_ptr<ThreadWrapper> poller_thread_;
-  const Call& call_;
-  const std::vector<uint32_t> ssrcs_;
-  RemoteBitrateObserver* const bitrate_observer_;
 };
 
-void RampUpTest::RunRampUpTest(size_t num_streams,
-                               unsigned int start_bitrate_bps,
-                               const std::string& extension_type,
-                               bool rtx,
-                               bool red) {
-  std::vector<uint32_t> ssrcs(GenerateSsrcs(num_streams, 100));
-  std::vector<uint32_t> rtx_ssrcs(GenerateSsrcs(num_streams, 200));
-  StreamObserver::SsrcMap rtx_ssrc_map;
-  if (rtx) {
-    for (size_t i = 0; i < ssrcs.size(); ++i)
-      rtx_ssrc_map[rtx_ssrcs[i]] = ssrcs[i];
-  }
-
-  test::DirectTransport receiver_transport;
-  StreamObserver stream_observer(rtx_ssrc_map, &receiver_transport,
-                                 Clock::GetRealTimeClock());
-
-  CreateSendConfig(num_streams, &stream_observer);
-  send_config_.rtp.extensions.clear();
-
-  rtc::scoped_ptr<SendBitrateAdapter> send_bitrate_adapter_;
-
-  if (extension_type == RtpExtension::kAbsSendTime) {
-    stream_observer.SetRemoteBitrateEstimator(
-        new RemoteBitrateEstimatorAbsSendTime(
-            &stream_observer, Clock::GetRealTimeClock(),
-            kRemoteBitrateEstimatorMinBitrateBps));
-    send_config_.rtp.extensions.push_back(RtpExtension(
-        extension_type.c_str(), kAbsSendTimeExtensionId));
-  } else if (extension_type == RtpExtension::kTransportSequenceNumber) {
-    stream_observer.SetRemoteBitrateEstimator(new RemoteEstimatorProxy(
-        Clock::GetRealTimeClock(), stream_observer.GetPacketRouter()));
-    send_config_.rtp.extensions.push_back(RtpExtension(
-        extension_type.c_str(), kTransportSequenceNumberExtensionId));
-  } else {
-    stream_observer.SetRemoteBitrateEstimator(
-        new RemoteBitrateEstimatorSingleStream(
-            &stream_observer, Clock::GetRealTimeClock(),
-            kRemoteBitrateEstimatorMinBitrateBps));
-    send_config_.rtp.extensions.push_back(RtpExtension(
-        extension_type.c_str(), kTransmissionTimeOffsetExtensionId));
-  }
-
-  Call::Config call_config;
-  if (start_bitrate_bps != 0) {
-    call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps;
-    stream_observer.set_start_bitrate_bps(start_bitrate_bps);
-  }
-  CreateSenderCall(call_config);
-
-  receiver_transport.SetReceiver(sender_call_->Receiver());
-
-  if (num_streams == 1) {
-    encoder_config_.streams[0].target_bitrate_bps = 2000000;
-    encoder_config_.streams[0].max_bitrate_bps = 2000000;
-  }
-
-  send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
-  send_config_.rtp.ssrcs = ssrcs;
-  if (rtx) {
-    send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
-    send_config_.rtp.rtx.ssrcs = rtx_ssrcs;
-  }
-  if (red) {
-    send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
-    send_config_.rtp.fec.red_payload_type = kRedPayloadType;
-  }
-
-  if (num_streams == 1) {
-    // For single stream rampup until 1mbps
-    stream_observer.set_expected_bitrate_bps(kSingleStreamTargetBps);
-  } else {
-    // For multi stream rampup until all streams are being sent. That means
-    // enough birate to send all the target streams plus the min bitrate of
-    // the last one.
-    int expected_bitrate_bps = encoder_config_.streams.back().min_bitrate_bps;
-    for (size_t i = 0; i < encoder_config_.streams.size() - 1; ++i) {
-      expected_bitrate_bps += encoder_config_.streams[i].target_bitrate_bps;
-    }
-    stream_observer.set_expected_bitrate_bps(expected_bitrate_bps);
-  }
-
-  CreateStreams();
-  CreateFrameGeneratorCapturer();
-
-  if (extension_type == RtpExtension::kTransportSequenceNumber) {
-    send_bitrate_adapter_.reset(
-        new SendBitrateAdapter(*sender_call_.get(), ssrcs, &stream_observer));
-  }
-  Start();
-
-  EXPECT_EQ(kEventSignaled, stream_observer.Wait());
-
-  // Destroy the SendBitrateAdapter (if any) to stop the poller thread in it,
-  // otherwise we might get a data race with the destruction of the call.
-  send_bitrate_adapter_.reset();
-
-  Stop();
-  DestroyStreams();
-}
-
-void RampUpTest::RunRampUpDownUpTest(size_t number_of_streams,
-                                     bool rtx,
-                                     bool red) {
-  test::DirectTransport receiver_transport;
-  LowRateStreamObserver stream_observer(
-      &receiver_transport, Clock::GetRealTimeClock(), number_of_streams, rtx);
-
-  Call::Config call_config;
-  call_config.bitrate_config.start_bitrate_bps = 60000;
-  CreateSenderCall(call_config);
-  receiver_transport.SetReceiver(sender_call_->Receiver());
-
-  CreateSendConfig(number_of_streams, &stream_observer);
-
-  send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
-  send_config_.rtp.extensions.push_back(RtpExtension(
-      RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
-  send_config_.suspend_below_min_bitrate = true;
-
-  if (rtx) {
-    send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
-    send_config_.rtp.rtx.ssrcs = GenerateSsrcs(number_of_streams, 200);
-  }
-  if (red) {
-    send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
-    send_config_.rtp.fec.red_payload_type = kRedPayloadType;
-  }
-
-  CreateStreams();
-  stream_observer.SetSendStream(send_stream_);
-
-  CreateFrameGeneratorCapturer();
-
-  Start();
-
-  EXPECT_EQ(kEventSignaled, stream_observer.Wait());
-
-  Stop();
-  DestroyStreams();
-}
-
 TEST_F(RampUpTest, SingleStream) {
-  RunRampUpTest(1, 0, RtpExtension::kTOffset, false, false);
+  RampUpTester test(1, 0, RtpExtension::kTOffset, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, Simulcast) {
-  RunRampUpTest(3, 0, RtpExtension::kTOffset, false, false);
+  RampUpTester test(3, 0, RtpExtension::kTOffset, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, SimulcastWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kTOffset, true, false);
+  RampUpTester test(3, 0, RtpExtension::kTOffset, true, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, SimulcastByRedWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kTOffset, true, true);
+  RampUpTester test(3, 0, RtpExtension::kTOffset, true, true);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) {
-  RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset, false,
-                false);
+  RampUpTester test(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset,
+                    false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpOneStream) {
-  RunRampUpDownUpTest(1, false, false);
+  RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpThreeStreams) {
-  RunRampUpDownUpTest(3, false, false);
+  RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpOneStreamRtx) {
-  RunRampUpDownUpTest(1, true, false);
+  RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, true, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) {
-  RunRampUpDownUpTest(3, true, false);
+  RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, true, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpOneStreamByRedRtx) {
-  RunRampUpDownUpTest(1, true, true);
+  RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, true, true);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, UpDownUpThreeStreamsByRedRtx) {
-  RunRampUpDownUpTest(3, true, true);
+  RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, true, true);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, AbsSendTimeSingleStream) {
-  RunRampUpTest(1, 0, RtpExtension::kAbsSendTime, false, false);
+  RampUpTester test(1, 0, RtpExtension::kAbsSendTime, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, AbsSendTimeSimulcast) {
-  RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, false, false);
+  RampUpTester test(3, 0, RtpExtension::kAbsSendTime, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, AbsSendTimeSimulcastWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, false);
+  RampUpTester test(3, 0, RtpExtension::kAbsSendTime, true, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, AbsSendTimeSimulcastByRedWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, true);
+  RampUpTester test(3, 0, RtpExtension::kAbsSendTime, true, true);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, AbsSendTimeSingleStreamWithHighStartBitrate) {
-  RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
-                false, false);
+  RampUpTester test(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
+                    false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, TransportSequenceNumberSingleStream) {
-  RunRampUpTest(1, 0, RtpExtension::kTransportSequenceNumber, false, false);
+  RampUpTester test(1, 0, RtpExtension::kTransportSequenceNumber, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
-  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, false, false);
+  RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, false, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, TransportSequenceNumberSimulcastWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, false);
+  RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, true, false);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, TransportSequenceNumberSimulcastByRedWithRtx) {
-  RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, true);
+  RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, true, true);
+  RunBaseTest(&test);
 }
 
 TEST_F(RampUpTest, TransportSequenceNumberSingleStreamWithHighStartBitrate) {
-  RunRampUpTest(1, 0.9 * kSingleStreamTargetBps,
-                RtpExtension::kTransportSequenceNumber, false, false);
+  RampUpTester test(1, 0.9 * kSingleStreamTargetBps,
+                    RtpExtension::kTransportSequenceNumber, false, false);
+  RunBaseTest(&test);
 }
 }  // namespace webrtc
diff --git a/webrtc/video/rampup_tests.h b/webrtc/video/rampup_tests.h
index 62edda3..ddab712 100644
--- a/webrtc/video/rampup_tests.h
+++ b/webrtc/video/rampup_tests.h
@@ -36,133 +36,97 @@
 class RTPPayloadRegistry;
 class RtpRtcp;
 
-class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
+class RampUpTester : public test::EndToEndTest {
  public:
-  typedef std::map<uint32_t, int> BytesSentMap;
-  typedef std::map<uint32_t, uint32_t> SsrcMap;
-  StreamObserver(const SsrcMap& rtx_media_ssrcs,
-                 newapi::Transport* feedback_transport,
-                 Clock* clock);
-  virtual ~StreamObserver();
+  RampUpTester(size_t num_streams,
+               unsigned int start_bitrate_bps,
+               const std::string& extension_type,
+               bool rtx,
+               bool red);
+  ~RampUpTester() override;
 
-  void set_expected_bitrate_bps(unsigned int expected_bitrate_bps);
+  void PerformTest() override;
 
-  void set_start_bitrate_bps(unsigned int start_bitrate_bps);
+ protected:
+  virtual bool PollStats();
 
-  void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
-                               unsigned int bitrate) override;
+  void GetStats(const VideoSendStream::StreamStats& stream,
+                size_t* total_packets_sent,
+                size_t* total_sent,
+                size_t* padding_sent,
+                size_t* media_sent) const;
 
-  bool SendRtp(const uint8_t* packet, size_t length) override;
-
-  bool SendRtcp(const uint8_t* packet, size_t length) override;
-
-  EventTypeWrapper Wait();
-
-  void SetRemoteBitrateEstimator(RemoteBitrateEstimator* rbe);
-
-  PacketRouter* GetPacketRouter();
-
- private:
   void ReportResult(const std::string& measurement,
                     size_t value,
-                    const std::string& units);
-  void TriggerTestDone() EXCLUSIVE_LOCKS_REQUIRED(crit_);
+                    const std::string& units) const;
+  void TriggerTestDone();
 
+  rtc::Event event_;
   Clock* const clock_;
-  const rtc::scoped_ptr<EventWrapper> test_done_;
-  const rtc::scoped_ptr<RtpHeaderParser> rtp_parser_;
-  rtc::scoped_ptr<RtpRtcp> rtp_rtcp_;
-  rtc::scoped_ptr<PacketRouter> packet_router_;
-  internal::TransportAdapter feedback_transport_;
-  const rtc::scoped_ptr<ReceiveStatistics> receive_stats_;
-  const rtc::scoped_ptr<RTPPayloadRegistry> payload_registry_;
-  rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
-
-  rtc::CriticalSection crit_;
-  unsigned int expected_bitrate_bps_ GUARDED_BY(crit_);
-  unsigned int start_bitrate_bps_ GUARDED_BY(crit_);
-  SsrcMap rtx_media_ssrcs_ GUARDED_BY(crit_);
-  size_t total_sent_ GUARDED_BY(crit_);
-  size_t padding_sent_ GUARDED_BY(crit_);
-  size_t rtx_media_sent_ GUARDED_BY(crit_);
-  int total_packets_sent_ GUARDED_BY(crit_);
-  int padding_packets_sent_ GUARDED_BY(crit_);
-  int rtx_media_packets_sent_ GUARDED_BY(crit_);
-  int64_t test_start_ms_ GUARDED_BY(crit_);
-  int64_t ramp_up_finished_ms_ GUARDED_BY(crit_);
-};
-
-class LowRateStreamObserver : public test::DirectTransport,
-                              public RemoteBitrateObserver,
-                              public PacketReceiver {
- public:
-  LowRateStreamObserver(newapi::Transport* feedback_transport,
-                        Clock* clock,
-                        size_t number_of_streams,
-                        bool rtx_used);
-
-  virtual void SetSendStream(VideoSendStream* send_stream);
-
-  virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
-                                       unsigned int bitrate);
-
-  bool SendRtp(const uint8_t* data, size_t length) override;
-
-  DeliveryStatus DeliverPacket(MediaType media_type,
-                               const uint8_t* packet,
-                               size_t length,
-                               const PacketTime& packet_time) override;
-
-  bool SendRtcp(const uint8_t* packet, size_t length) override;
-
-  // Produces a string similar to "1stream_nortx", depending on the values of
-  // number_of_streams_ and rtx_used_;
-  std::string GetModifierString();
-
-  // This method defines the state machine for the ramp up-down-up test.
-  void EvolveTestState(unsigned int bitrate_bps);
-
-  EventTypeWrapper Wait();
+  const size_t num_streams_;
+  const bool rtx_;
+  const bool red_;
+  VideoSendStream* send_stream_;
 
  private:
-  static const unsigned int kHighBandwidthLimitBps = 80000;
-  static const unsigned int kExpectedHighBitrateBps = 60000;
-  static const unsigned int kLowBandwidthLimitBps = 20000;
-  static const unsigned int kExpectedLowBitrateBps = 20000;
-  enum TestStates { kFirstRampup, kLowRate, kSecondRampup };
+  typedef std::map<uint32_t, uint32_t> SsrcMap;
 
-  Clock* const clock_;
-  const size_t number_of_streams_;
-  const bool rtx_used_;
-  const rtc::scoped_ptr<EventWrapper> test_done_;
-  const rtc::scoped_ptr<RtpHeaderParser> rtp_parser_;
-  const rtc::scoped_ptr<RTPPayloadRegistry> payload_registry_;
-  rtc::scoped_ptr<RtpRtcp> rtp_rtcp_;
-  internal::TransportAdapter feedback_transport_;
-  const rtc::scoped_ptr<ReceiveStatistics> receive_stats_;
-  rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
+  Call::Config GetSenderCallConfig() override;
+  void OnStreamsCreated(
+      VideoSendStream* send_stream,
+      const std::vector<VideoReceiveStream*>& receive_streams) override;
+  size_t GetNumStreams() const;
+  void ModifyConfigs(VideoSendStream::Config* send_config,
+                     std::vector<VideoReceiveStream::Config>* receive_configs,
+                     VideoEncoderConfig* encoder_config) override;
+  void OnCallsCreated(Call* sender_call, Call* receiver_call) override;
 
-  rtc::CriticalSection crit_;
-  VideoSendStream* send_stream_ GUARDED_BY(crit_);
-  FakeNetworkPipe::Config forward_transport_config_ GUARDED_BY(crit_);
-  TestStates test_state_ GUARDED_BY(crit_);
-  int64_t state_start_ms_ GUARDED_BY(crit_);
-  int64_t interval_start_ms_ GUARDED_BY(crit_);
-  unsigned int last_remb_bps_ GUARDED_BY(crit_);
-  size_t sent_bytes_ GUARDED_BY(crit_);
-  size_t total_overuse_bytes_ GUARDED_BY(crit_);
-  bool suspended_in_stats_ GUARDED_BY(crit_);
+  static bool BitrateStatsPollingThread(void* obj);
+
+  const int start_bitrate_bps_;
+  bool start_bitrate_verified_;
+  int expected_bitrate_bps_;
+  int64_t test_start_ms_;
+  int64_t ramp_up_finished_ms_;
+
+  const std::string extension_type_;
+  std::vector<uint32_t> ssrcs_;
+  std::vector<uint32_t> rtx_ssrcs_;
+  SsrcMap rtx_ssrc_map_;
+
+  rtc::scoped_ptr<ThreadWrapper> poller_thread_;
+  Call* sender_call_;
 };
 
-class RampUpTest : public test::CallTest {
- protected:
-  void RunRampUpTest(size_t num_streams,
+class RampUpDownUpTester : public RampUpTester {
+ public:
+  RampUpDownUpTester(size_t num_streams,
                      unsigned int start_bitrate_bps,
                      const std::string& extension_type,
                      bool rtx,
                      bool red);
+  ~RampUpDownUpTester() override;
 
-  void RunRampUpDownUpTest(size_t number_of_streams, bool rtx, bool red);
+ protected:
+  bool PollStats() override;
+
+ private:
+  static const int kHighBandwidthLimitBps = 80000;
+  static const int kExpectedHighBitrateBps = 60000;
+  static const int kLowBandwidthLimitBps = 20000;
+  static const int kExpectedLowBitrateBps = 20000;
+  enum TestStates { kFirstRampup, kLowRate, kSecondRampup };
+
+  Call::Config GetReceiverCallConfig() override;
+
+  std::string GetModifierString() const;
+  void EvolveTestState(int bitrate_bps, bool suspended);
+
+  FakeNetworkPipe::Config forward_transport_config_;
+  TestStates test_state_;
+  int64_t state_start_ms_;
+  int64_t interval_start_ms_;
+  int sent_bytes_;
 };
 }  // namespace webrtc
 #endif  // WEBRTC_VIDEO_RAMPUP_TESTS_H_
diff --git a/webrtc/video_engine/vie_channel_group.cc b/webrtc/video_engine/vie_channel_group.cc
index 6553ce2..ed4332a 100644
--- a/webrtc/video_engine/vie_channel_group.cc
+++ b/webrtc/video_engine/vie_channel_group.cc
@@ -43,12 +43,10 @@
       : observer_(observer),
         clock_(clock),
         crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
-        min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps),
-        rbe_(new RemoteBitrateEstimatorSingleStream(observer_,
-                                                    clock_,
-                                                    min_bitrate_bps_)),
+        rbe_(new RemoteBitrateEstimatorSingleStream(observer_, clock_)),
         using_absolute_send_time_(false),
-        packets_since_absolute_send_time_(0) {}
+        packets_since_absolute_send_time_(0),
+        min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) {}
 
   virtual ~WrappingBitrateEstimator() {}
 
@@ -92,6 +90,12 @@
     return rbe_->GetStats(output);
   }
 
+  void SetMinBitrate(int min_bitrate_bps) {
+    CriticalSectionScoped cs(crit_sect_.get());
+    rbe_->SetMinBitrate(min_bitrate_bps);
+    min_bitrate_bps_ = min_bitrate_bps;
+  }
+
  private:
   void PickEstimatorFromHeader(const RTPHeader& header)
       EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
@@ -121,21 +125,20 @@
   // Instantiate RBE for Time Offset or Absolute Send Time extensions.
   void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
     if (using_absolute_send_time_) {
-      rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_,
-                                                       min_bitrate_bps_));
+      rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_));
     } else {
-      rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_,
-                                                        min_bitrate_bps_));
+      rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_));
     }
+    rbe_->SetMinBitrate(min_bitrate_bps_);
   }
 
   RemoteBitrateObserver* observer_;
   Clock* clock_;
   rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
-  const uint32_t min_bitrate_bps_;
   rtc::scoped_ptr<RemoteBitrateEstimator> rbe_;
   bool using_absolute_send_time_;
   uint32_t packets_since_absolute_send_time_;
+  int min_bitrate_bps_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator);
 };
@@ -165,7 +168,8 @@
       // construction.
       bitrate_controller_(
           BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
-                                                     this)) {
+                                                     this)),
+      min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) {
   call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
 
   pacer_thread_->RegisterModule(pacer_.get());
@@ -213,8 +217,9 @@
           Clock::GetRealTimeClock(), process_thread_));
       transport_feedback_adapter_->SetBitrateEstimator(
           new RemoteBitrateEstimatorAbsSendTime(
-              transport_feedback_adapter_.get(), Clock::GetRealTimeClock(),
-              RemoteBitrateEstimator::kDefaultMinBitrateBps));
+              transport_feedback_adapter_.get(), Clock::GetRealTimeClock()));
+      transport_feedback_adapter_->GetBitrateEstimator()->SetMinBitrate(
+          min_bitrate_bps_);
       call_stats_->RegisterStatsObserver(transport_feedback_adapter_.get());
     }
     transport_feedback_observer = transport_feedback_adapter_.get();
@@ -364,6 +369,20 @@
     channel.second->SetVoiceChannel(-1, sync_interface);
 }
 
+void ChannelGroup::SetBweBitrates(int min_bitrate_bps,
+                                  int start_bitrate_bps,
+                                  int max_bitrate_bps) {
+  if (start_bitrate_bps > 0)
+    bitrate_controller_->SetStartBitrate(start_bitrate_bps);
+  bitrate_controller_->SetMinMaxBitrate(min_bitrate_bps, max_bitrate_bps);
+  if (remote_bitrate_estimator_.get())
+    remote_bitrate_estimator_->SetMinBitrate(min_bitrate_bps);
+  if (transport_feedback_adapter_.get())
+    transport_feedback_adapter_->GetBitrateEstimator()->SetMinBitrate(
+        min_bitrate_bps);
+  min_bitrate_bps_ = min_bitrate_bps;
+}
+
 BitrateController* ChannelGroup::GetBitrateController() const {
   return bitrate_controller_.get();
 }
diff --git a/webrtc/video_engine/vie_channel_group.h b/webrtc/video_engine/vie_channel_group.h
index e133d1a..374bd00 100644
--- a/webrtc/video_engine/vie_channel_group.h
+++ b/webrtc/video_engine/vie_channel_group.h
@@ -63,6 +63,9 @@
   ViEChannel* GetChannel(int channel_id) const;
   ViEEncoder* GetEncoder(int channel_id) const;
   void SetSyncInterface(VoEVideoSync* sync_interface);
+  void SetBweBitrates(int min_bitrate_bps,
+                      int start_bitrate_bps,
+                      int max_bitrate_bps);
 
   void SetChannelRembStatus(bool sender, bool receiver, ViEChannel* channel);
 
@@ -110,6 +113,7 @@
 
   rtc::scoped_ptr<BitrateController> bitrate_controller_;
   rtc::scoped_ptr<TransportFeedbackAdapter> transport_feedback_adapter_;
+  int min_bitrate_bps_;
 };
 
 }  // namespace webrtc