Improve TCP implementation by adding ssthresh and make it possible to start it with an offset.

Add a propagation delay to tests and make the run-time configurable for the fairness tests.

Handle losses in-between feedback messages.

BUG=4549
R=pbos@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/49819004

Cr-Commit-Position: refs/heads/master@{#9099}
diff --git a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc
index 7eb126d..f32c4ff 100644
--- a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc
+++ b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc
@@ -87,7 +87,7 @@
   PacketReceiver receiver2(&downlink_, kFlowIds[1], GetParam(), true, false);
 
   choke2.SetCapacity(500);
-  delay.SetDelay(0);
+  delay.SetDelayMs(0);
 
   choke.SetCapacity(1000);
   choke.SetMaxDelay(500);
@@ -240,13 +240,33 @@
 TEST_P(BweSimulation, PacedSelfFairnessTest) {
   VerboseLogging(true);
   srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
-  RunFairnessTest(GetParam(), 4, 0, 2000);
+  RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 50);
 }
 
 TEST_P(BweSimulation, PacedTcpFairnessTest) {
   VerboseLogging(true);
   srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
-  RunFairnessTest(GetParam(), 1, 1, 3000);
+  RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 500);
+}
+
+TEST_P(BweSimulation, PacedSelfFairness1000msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 4, 0, 1000, 3000, 1000);
+}
+
+TEST_P(BweSimulation, TcpFairness50msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 1000, 2000, 50);
+}
+
+TEST_P(BweSimulation, TcpFairness500msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 1000, 2000, 500);
+}
+
+TEST_P(BweSimulation, TcpFairness1000msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 1000, 2000, 1000);
 }
 #endif  // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
 }  // namespace bwe
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc
index dffd036..0d9418e 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimators_test.cc
@@ -65,7 +65,7 @@
   VideoSender sender(&uplink_, &source, GetParam());
   DelayFilter delay(&uplink_, 0);
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
-  delay.SetDelay(1000);
+  delay.SetDelayMs(1000);
   RunFor(10 * 60 * 1000);
 }
 
@@ -76,7 +76,7 @@
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
   RunFor(10 * 60 * 1000);
   for (int i = 0; i < 30 * 2; ++i) {
-    delay.SetDelay(i);
+    delay.SetDelayMs(i);
     RunFor(10 * 1000);
   }
   RunFor(10 * 60 * 1000);
@@ -90,10 +90,10 @@
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
   RunFor(1 * 60 * 1000);
   for (int i = 1; i < 51; ++i) {
-    delay.SetDelay(10.0f * i);
+    delay.SetDelayMs(10.0f * i);
     RunFor(10 * 1000);
   }
-  delay.SetDelay(0.0f);
+  delay.SetDelayMs(0.0f);
   RunFor(10 * 60 * 1000);
 }
 
@@ -104,12 +104,12 @@
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
   RunFor(10 * 60 * 1000);
   for (int i = 1; i < 200; ++i) {
-    delay.SetDelay((10 * i) % 500);
+    delay.SetDelayMs((10 * i) % 500);
     RunFor(1000);
-    delay.SetDelay(1.0f);
+    delay.SetDelayMs(1.0f);
     RunFor(1000);
   }
-  delay.SetDelay(0.0f);
+  delay.SetDelayMs(0.0f);
   RunFor(10 * 60 * 1000);
 }
 
@@ -211,11 +211,11 @@
   choke.SetCapacity(1000);
   RunFor(1 * 60 * 1000);
   for (int i = 1; i < 51; ++i) {
-    delay.SetDelay(100.0f * i);
+    delay.SetDelayMs(100.0f * i);
     RunFor(10 * 1000);
   }
   RunFor(500 * 1000);
-  delay.SetDelay(0.0f);
+  delay.SetDelayMs(0.0f);
   RunFor(5 * 60 * 1000);
 }
 
@@ -254,7 +254,7 @@
 
 TEST_P(BweFeedbackTest, Choke1000kbps500kbps1000kbps) {
   AdaptiveVideoSource source(0, 30, 300, 0, 0);
-  VideoSender sender(&uplink_, &source, GetParam());
+  PacedVideoSender sender(&uplink_, &source, GetParam());
   ChokeFilter filter(&uplink_, 0);
   RateCounterFilter counter(&uplink_, 0, "receiver_input");
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
@@ -274,7 +274,7 @@
 
 TEST_P(BweFeedbackTest, Choke200kbps30kbps200kbps) {
   AdaptiveVideoSource source(0, 30, 300, 0, 0);
-  VideoSender sender(&uplink_, &source, GetParam());
+  PacedVideoSender sender(&uplink_, &source, GetParam());
   ChokeFilter filter(&uplink_, 0);
   RateCounterFilter counter(&uplink_, 0, "receiver_input");
   PacketReceiver receiver(&uplink_, 0, GetParam(), false, false);
@@ -323,12 +323,27 @@
 
 TEST_P(BweFeedbackTest, PacedSelfFairnessTest) {
   srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
-  RunFairnessTest(GetParam(), 4, 0, 3000);
+  RunFairnessTest(GetParam(), 4, 0, 300, 3000, 50);
 }
 
-TEST_P(BweFeedbackTest, TcpFairnessTest) {
+TEST_P(BweFeedbackTest, PacedSelfFairness1000msTest) {
   srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
-  RunFairnessTest(GetParam(), 1, 1, 2000);
+  RunFairnessTest(GetParam(), 4, 0, 300, 3000, 1000);
+}
+
+TEST_P(BweFeedbackTest, TcpFairness50msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 300, 2000, 50);
+}
+
+TEST_P(BweFeedbackTest, TcpFairness500msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 300, 2000, 500);
+}
+
+TEST_P(BweFeedbackTest, TcpFairness1000msTest) {
+  srand(Clock::GetRealTimeClock()->TimeInMicroseconds());
+  RunFairnessTest(GetParam(), 1, 1, 300, 2000, 1000);
 }
 }  // namespace bwe
 }  // namespace testing
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe.h b/webrtc/modules/remote_bitrate_estimator/test/bwe.h
index a82235f..0c79bf2 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe.h
@@ -21,7 +21,7 @@
 namespace bwe {
 
 const int kMinBitrateKbps = 150;
-const int kMaxBitrateKbps = 2000;
+const int kMaxBitrateKbps = 3000;
 
 class BweSender : public Module {
  public:
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
index c9d7af7..83c76a5 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.cc
@@ -192,14 +192,16 @@
   webrtc::test::PrintResultMeanAndError("BwePerformance", GetTestName(),
                                         "Average delay", delay_ms.AsString(),
                                         "ms", false);
-  double fairness_index = 0.0;
-  double squared_bitrate_sum = 0.0;
-  for (Stats<double> flow : flow_throughput_kbps) {
-    squared_bitrate_sum += flow.GetMean() * flow.GetMean();
-    fairness_index += flow.GetMean();
+  double fairness_index = 1.0;
+  if (!flow_throughput_kbps.empty()) {
+    double squared_bitrate_sum = 0.0;
+    for (Stats<double> flow : flow_throughput_kbps) {
+      squared_bitrate_sum += flow.GetMean() * flow.GetMean();
+      fairness_index += flow.GetMean();
+    }
+    fairness_index *= fairness_index;
+    fairness_index /= flow_throughput_kbps.size() * squared_bitrate_sum;
   }
-  fairness_index *= fairness_index;
-  fairness_index /= flow_throughput_kbps.size() * squared_bitrate_sum;
   webrtc::test::PrintResult("BwePerformance", GetTestName(), "Fairness",
                             fairness_index * 100, "%", false);
 }
@@ -207,7 +209,9 @@
 void BweTest::RunFairnessTest(BandwidthEstimatorType bwe_type,
                               size_t num_media_flows,
                               size_t num_tcp_flows,
-                              int capacity_kbps) {
+                              int64_t run_time_seconds,
+                              int capacity_kbps,
+                              int max_delay_ms) {
   std::set<int> all_flow_ids;
   std::set<int> media_flow_ids;
   std::set<int> tcp_flow_ids;
@@ -230,17 +234,22 @@
   for (int media_flow : media_flow_ids) {
     // Streams started 20 seconds apart to give them different advantage when
     // competing for the bandwidth.
+    const int64_t kFlowStartOffsetMs = i++ * (rand() % 40000);
     sources.push_back(new AdaptiveVideoSource(media_flow, 30, 300, 0,
-                                              i++ * (rand() % 40000)));
+                                              kFlowStartOffsetMs));
     senders.push_back(new PacedVideoSender(&uplink_, sources.back(), bwe_type));
   }
 
+  const int64_t kTcpStartOffsetMs = 20000;
   for (int tcp_flow : tcp_flow_ids)
-    senders.push_back(new TcpSender(&uplink_, tcp_flow));
+    senders.push_back(new TcpSender(&uplink_, tcp_flow, kTcpStartOffsetMs));
 
   ChokeFilter choke(&uplink_, all_flow_ids);
   choke.SetCapacity(capacity_kbps);
-  choke.SetMaxDelay(1000);
+  choke.SetMaxDelay(max_delay_ms);
+
+  DelayFilter delay_uplink(&uplink_, all_flow_ids);
+  delay_uplink.SetDelayMs(25);
 
   std::vector<RateCounterFilter*> rate_counters;
   for (int flow : all_flow_ids) {
@@ -262,7 +271,10 @@
         new PacketReceiver(&uplink_, tcp_flow, kTcpEstimator, false, false));
   }
 
-  RunFor(15 * 60 * 1000);
+  DelayFilter delay_downlink(&downlink_, all_flow_ids);
+  delay_downlink.SetDelayMs(25);
+
+  RunFor(run_time_seconds * 1000);
 
   std::vector<Stats<double>> flow_throughput_kbps;
   for (i = 0; i < all_flow_ids.size(); ++i)
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h
index 158d423..2de5ac6 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test.h
@@ -84,7 +84,9 @@
   void RunFairnessTest(BandwidthEstimatorType bwe_type,
                        size_t num_media_flows,
                        size_t num_tcp_flows,
-                       int capacity_kbps);
+                       int64_t run_time_seconds,
+                       int capacity_kbps,
+                       int max_delay_ms);
 
   Link downlink_;
   Link uplink_;
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
index 95835e3..f9df06f 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc
@@ -341,7 +341,7 @@
       last_send_time_us_(0) {
 }
 
-void DelayFilter::SetDelay(int64_t delay_ms) {
+void DelayFilter::SetDelayMs(int64_t delay_ms) {
   BWE_TEST_LOGGING_ENABLE(false);
   BWE_TEST_LOGGING_LOG1("Delay", "%d ms", static_cast<int>(delay_ms));
   assert(delay_ms >= 0);
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h
index 69dc8e1..9fb219d 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h
@@ -254,7 +254,7 @@
   DelayFilter(PacketProcessorListener* listener, const FlowIds& flow_ids);
   virtual ~DelayFilter() {}
 
-  void SetDelay(int64_t delay_ms);
+  void SetDelayMs(int64_t delay_ms);
   virtual void RunFor(int64_t time_ms, Packets* in_out);
 
  private:
diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc
index b92b39e..9ed29b5 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework_unittest.cc
@@ -333,7 +333,7 @@
   }
 
   void TestDelayFilter(int64_t delay_ms) {
-    filter_.SetDelay(delay_ms);
+    filter_.SetDelayMs(delay_ms);
     TestDelayFilter(1, 0, 0);    // No input should yield no output
 
     // Single packet
@@ -341,7 +341,7 @@
     TestDelayFilter(delay_ms, 0, 0);
 
     for (int i = 0; i < delay_ms; ++i) {
-      filter_.SetDelay(i);
+      filter_.SetDelayMs(i);
       TestDelayFilter(1, 10, 10);
     }
     TestDelayFilter(0, 0, 0);
@@ -351,11 +351,11 @@
     TestDelayFilter(delay_ms, 0, 0);
 
     for (int i = 1; i < delay_ms + 1; ++i) {
-      filter_.SetDelay(i);
+      filter_.SetDelayMs(i);
       TestDelayFilter(1, 5, 5);
     }
     TestDelayFilter(0, 0, 0);
-    filter_.SetDelay(2 * delay_ms);
+    filter_.SetDelayMs(2 * delay_ms);
     TestDelayFilter(1, 0, 0);
     TestDelayFilter(delay_ms, 13, 13);
     TestDelayFilter(delay_ms, 0, 0);
@@ -364,11 +364,11 @@
     TestDelayFilter(delay_ms, 0, 0);
 
     for (int i = 0; i < 2 * delay_ms; ++i) {
-      filter_.SetDelay(2 * delay_ms - i - 1);
+      filter_.SetDelayMs(2 * delay_ms - i - 1);
       TestDelayFilter(1, 5, 5);
     }
     TestDelayFilter(0, 0, 0);
-    filter_.SetDelay(0);
+    filter_.SetDelayMs(0);
     TestDelayFilter(0, 7, 7);
 
     ASSERT_TRUE(IsTimeSorted(accumulated_packets_));
@@ -389,7 +389,7 @@
   TestDelayFilter(1, 0, 0);    // No input should yield no output
   TestDelayFilter(1, 10, 10);  // Expect no delay (delay time is zero)
   TestDelayFilter(1, 0, 0);    // Check no packets are still in buffer
-  filter_.SetDelay(0);
+  filter_.SetDelayMs(0);
   TestDelayFilter(1, 5, 5);    // Expect no delay (delay time is zero)
   TestDelayFilter(1, 0, 0);    // Check no packets are still in buffer
 }
@@ -416,7 +416,7 @@
   Packets packets;
 
   // Delay a bunch of packets, accumulate them to the 'acc' list.
-  delay.SetDelay(100.0f);
+  delay.SetDelayMs(100.0f);
   for (uint32_t i = 0; i < 10; ++i) {
     packets.push_back(new MediaPacket(i * 100, i));
   }
@@ -427,7 +427,7 @@
 
   // Drop delay to zero, send a few more packets through the delay, append them
   // to the 'acc' list and verify that it is all sorted.
-  delay.SetDelay(0.0f);
+  delay.SetDelayMs(0.0f);
   for (uint32_t i = 10; i < 50; ++i) {
     packets.push_back(new MediaPacket(i * 100, i));
   }
@@ -446,12 +446,12 @@
     TestDelayFilter(i);
   }
   // Reach a steady state.
-  filter_.SetDelay(100);
+  filter_.SetDelayMs(100);
   TestDelayFilter(1, 20, 20);
   TestDelayFilter(2, 0, 0);
   TestDelayFilter(99, 20, 20);
   // Drop delay back down to zero.
-  filter_.SetDelay(0);
+  filter_.SetDelayMs(0);
   TestDelayFilter(1, 100, 100);
   TestDelayFilter(23010, 0, 0);
   ASSERT_TRUE(IsTimeSorted(accumulated_packets_));
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 d501868..b33534b 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc
@@ -11,6 +11,7 @@
 #include "webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h"
 
 #include "webrtc/base/logging.h"
+#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
 
 namespace webrtc {
 namespace testing {
@@ -23,7 +24,9 @@
                .Create(this, clock, kAimdControl, 1000 * kMinBitrateKbps)),
       feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
       clock_(clock),
-      send_time_history_(10000) {
+      send_time_history_(10000),
+      has_received_ack_(false),
+      last_acked_seq_num_(0) {
   assert(kbps >= kMinBitrateKbps);
   assert(kbps <= kMaxBitrateKbps);
   bitrate_controller_->SetStartBitrate(1000 * kbps);
@@ -51,23 +54,32 @@
       LOG(LS_WARNING) << "Ack arrived too late.";
     }
   }
+
   rbe_->IncomingPacketFeedbackVector(packet_feedback_vector);
-  // TODO(holmer): Handle losses in between feedback packets.
-  int expected_packets = fb.packet_feedback_vector().back().sequence_number -
-                         fb.packet_feedback_vector().front().sequence_number +
-                         1;
-  // Assuming no reordering for now.
-  if (expected_packets <= 0)
-    return;
-  int lost_packets =
-      expected_packets - static_cast<int>(fb.packet_feedback_vector().size());
-  report_block_.fractionLost = (lost_packets << 8) / expected_packets;
-  report_block_.cumulativeLost += lost_packets;
-  ReportBlockList report_blocks;
-  report_blocks.push_back(report_block_);
-  feedback_observer_->OnReceivedRtcpReceiverReport(
-      report_blocks, 0, clock_->TimeInMilliseconds());
-  bitrate_controller_->Process();
+  if (has_received_ack_) {
+    int expected_packets = fb.packet_feedback_vector().back().sequence_number -
+                           last_acked_seq_num_;
+    // Assuming no reordering for now.
+    if (expected_packets > 0) {
+      int lost_packets = expected_packets -
+                         static_cast<int>(fb.packet_feedback_vector().size());
+      report_block_.fractionLost = (lost_packets << 8) / expected_packets;
+      report_block_.cumulativeLost += lost_packets;
+      report_block_.extendedHighSeqNum =
+          packet_feedback_vector.back().sequence_number;
+      ReportBlockList report_blocks;
+      report_blocks.push_back(report_block_);
+      feedback_observer_->OnReceivedRtcpReceiverReport(
+          report_blocks, 0, clock_->TimeInMilliseconds());
+    }
+    bitrate_controller_->Process();
+
+    last_acked_seq_num_ = LatestSequenceNumber(
+        packet_feedback_vector.back().sequence_number, last_acked_seq_num_);
+  } else {
+    last_acked_seq_num_ = packet_feedback_vector.back().sequence_number;
+    has_received_ack_ = true;
+  }
 }
 
 void FullBweSender::OnPacketsSent(const Packets& packets) {
diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
index 007ea4e..c76e360 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
@@ -42,6 +42,8 @@
   Clock* const clock_;
   RTCPReportBlock report_block_;
   SendTimeHistory send_time_history_;
+  bool has_received_ack_;
+  uint16_t last_acked_seq_num_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(FullBweSender);
 };
diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc
index 3e0073a..480f185 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc
+++ b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.cc
@@ -138,8 +138,10 @@
     int64_t time_until_process_ms = TimeUntilNextProcess(modules_);
     int64_t time_until_feedback_ms = time_ms;
     if (!feedbacks.empty())
-      time_until_feedback_ms = feedbacks.front()->send_time_us() / 1000 -
-                               clock_.TimeInMilliseconds();
+      time_until_feedback_ms =
+          std::max<int64_t>(feedbacks.front()->send_time_us() / 1000 -
+                                clock_.TimeInMilliseconds(),
+                            0);
 
     int64_t time_until_next_event_ms =
         std::min(time_until_feedback_ms, time_until_process_ms);
@@ -265,6 +267,10 @@
 }
 
 void TcpSender::RunFor(int64_t time_ms, Packets* in_out) {
+  if (now_ms_ + time_ms < offset_ms_) {
+    now_ms_ += time_ms;
+    return;
+  }
   BWE_TEST_LOGGING_CONTEXT("Sender");
   BWE_TEST_LOGGING_CONTEXT(*flow_ids().begin());
   std::list<FeedbackPacket*> feedbacks =
@@ -277,13 +283,6 @@
     SendPackets(in_out);
   }
 
-  for (auto it = in_flight_.begin(); it != in_flight_.end();) {
-    if (it->time_ms < now_ms_ - 1000)
-      in_flight_.erase(it++);
-    else
-      ++it;
-  }
-
   SendPackets(in_out);
   now_ms_ += time_ms;
 }
@@ -291,6 +290,10 @@
 void TcpSender::SendPackets(Packets* in_out) {
   int cwnd = ceil(cwnd_);
   int packets_to_send = std::max(cwnd - static_cast<int>(in_flight_.size()), 0);
+  int timed_out = TriggerTimeouts();
+  if (timed_out > 0) {
+    HandleLoss();
+  }
   if (packets_to_send > 0) {
     Packets generated = GeneratePackets(packets_to_send);
     for (Packet* packet : generated)
@@ -312,9 +315,8 @@
     in_flight_.erase(InFlight(ack_seq_num, now_ms_));
 
   if (missing > 0) {
-    cwnd_ /= 2.0f;
-    in_slow_start_ = false;
-  } else if (in_slow_start_) {
+    HandleLoss();
+  } else if (cwnd_ <= ssthresh_) {
     cwnd_ += tcp_fb->acked_packets().size();
   } else {
     cwnd_ += 1.0f / cwnd_;
@@ -324,6 +326,24 @@
       LatestSequenceNumber(tcp_fb->acked_packets().back(), last_acked_seq_num_);
 }
 
+int TcpSender::TriggerTimeouts() {
+  int timed_out = 0;
+  for (auto it = in_flight_.begin(); it != in_flight_.end();) {
+    if (it->time_ms < now_ms_ - 1000) {
+      in_flight_.erase(it++);
+      ++timed_out;
+    } else {
+      ++it;
+    }
+  }
+  return timed_out;
+}
+
+void TcpSender::HandleLoss() {
+  ssthresh_ = std::max(static_cast<int>(in_flight_.size() / 2), 2);
+  cwnd_ = ssthresh_;
+}
+
 Packets TcpSender::GeneratePackets(size_t num_packets) {
   Packets generated;
   for (size_t i = 0; i < num_packets; ++i) {
diff --git a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h
index 0c579ed..82a6229 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/packet_sender.h
@@ -12,6 +12,7 @@
 #define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_TEST_PACKET_SENDER_H_
 
 #include <list>
+#include <limits>
 #include <string>
 
 #include "webrtc/base/constructormagic.h"
@@ -104,14 +105,15 @@
 
 class TcpSender : public PacketSender {
  public:
-  TcpSender(PacketProcessorListener* listener, int flow_id)
+  TcpSender(PacketProcessorListener* listener, int flow_id, int64_t offset_ms)
       : PacketSender(listener, flow_id),
         now_ms_(0),
-        in_slow_start_(false),
         cwnd_(10),
+        ssthresh_(std::numeric_limits<int>::max()),
         ack_received_(false),
         last_acked_seq_num_(0),
-        next_sequence_number_(0) {}
+        next_sequence_number_(0),
+        offset_ms_(offset_ms) {}
 
   virtual ~TcpSender() {}
 
@@ -140,15 +142,18 @@
 
   void SendPackets(Packets* in_out);
   void UpdateCongestionControl(const FeedbackPacket* fb);
+  int TriggerTimeouts();
+  void HandleLoss();
   Packets GeneratePackets(size_t num_packets);
 
   int64_t now_ms_;
-  bool in_slow_start_;
   float cwnd_;
+  int ssthresh_;
   std::set<InFlight> in_flight_;
   bool ack_received_;
   uint16_t last_acked_seq_num_;
   uint16_t next_sequence_number_;
+  int64_t offset_ms_;
 };
 }  // namespace bwe
 }  // namespace testing