Merge QUIC InterArrival congestion control code to chromium.


Review URL: https://chromiumcodereview.appspot.com/13660002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193483 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/quic/congestion_control/available_channel_estimator.cc b/net/quic/congestion_control/available_channel_estimator.cc
new file mode 100644
index 0000000..ef091ab
--- /dev/null
+++ b/net/quic/congestion_control/available_channel_estimator.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/available_channel_estimator.h"
+
+static const int kNumberOfSamples = 9;
+
+namespace net {
+
+AvailableChannelEstimator::AvailableChannelEstimator(
+    QuicPacketSequenceNumber sequence_number,
+    QuicTime first_send_time,
+    QuicTime first_receive_time)
+    : first_sequence_number_(sequence_number),
+      first_send_time_(first_send_time),
+      first_receive_time_(first_receive_time),
+      last_incorporated_sequence_number_(sequence_number),
+      last_time_sent_(QuicTime::Zero()),
+      last_receive_time_(QuicTime::Zero()),
+      number_of_sequence_numbers_(0),
+      received_bytes_(0) {
+}
+
+void AvailableChannelEstimator::OnIncomingFeedback(
+    QuicPacketSequenceNumber sequence_number,
+    QuicByteCount packet_size,
+    QuicTime sent_time,
+    QuicTime receive_time) {
+  if (sequence_number <= first_sequence_number_) {
+    // Ignore pre-probe feedback.
+    return;
+  }
+  if (sequence_number <= last_incorporated_sequence_number_) {
+    // Ignore old feedback; will remove duplicates.
+    return;
+  }
+  // Remember the highest received sequence number.
+  last_incorporated_sequence_number_ = sequence_number;
+  if (number_of_sequence_numbers_ < kNumberOfSamples) {
+    // We don't care how many sequence numbers we have after we pass
+    // kNumberOfSamples.
+    number_of_sequence_numbers_++;
+  }
+  last_receive_time_ = receive_time;
+  last_time_sent_ = sent_time;
+  received_bytes_ += packet_size;
+  // TODO(pwestin): the variance here should give us information about accuracy.
+}
+
+AvailableChannelEstimateState
+    AvailableChannelEstimator::GetAvailableChannelEstimate(
+        QuicBandwidth* bandwidth) const {
+  if (number_of_sequence_numbers_ < 2) {
+    return kAvailableChannelEstimateUnknown;
+  }
+  QuicTime::Delta send_delta = last_time_sent_.Subtract(first_send_time_);
+  QuicTime::Delta receive_delta =
+      last_receive_time_.Subtract(first_receive_time_);
+
+  // TODO(pwestin): room for improvement here. Keeping it simple for now.
+  *bandwidth = QuicBandwidth::FromBytesAndTimeDelta(received_bytes_,
+                                                    receive_delta);
+
+  QuicTime::Delta diff = receive_delta.Subtract(send_delta);
+  QuicTime::Delta ten_percent_of_send_time =
+      QuicTime::Delta::FromMicroseconds(send_delta.ToMicroseconds() / 10);
+
+  if (diff < ten_percent_of_send_time) {
+    return kAvailableChannelEstimateSenderLimited;
+  }
+  if (number_of_sequence_numbers_ < kNumberOfSamples) {
+    return kAvailableChannelEstimateUncertain;
+  }
+  return kAvailableChannelEstimateGood;
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/available_channel_estimator.h b/net/quic/congestion_control/available_channel_estimator.h
new file mode 100644
index 0000000..e2ad19a
--- /dev/null
+++ b/net/quic/congestion_control/available_channel_estimator.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on the inter arrival time of the received packets relative to the time
+// those packets where sent we can estimate the available capacity of the
+// channel.
+// We can only use packet trains that are sent out faster than the acctual
+// available channel capacity.
+// Note 1: this is intended to be a temporary class created when you send out a
+// channel probing burst. Once the last packet have arrived you ask it for an
+// estimate.
+// Note 2: During this phase we should not update the overuse detector.
+#ifndef NET_QUIC_CONGESTION_CONTROL_AVAILABLE_CHANNEL_ESTIMATOR_H_
+#define NET_QUIC_CONGESTION_CONTROL_AVAILABLE_CHANNEL_ESTIMATOR_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+#include "net/quic/quic_bandwidth.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+enum NET_EXPORT_PRIVATE AvailableChannelEstimateState {
+  kAvailableChannelEstimateUnknown = 0,
+  kAvailableChannelEstimateUncertain = 1,
+  kAvailableChannelEstimateGood = 2,
+  kAvailableChannelEstimateSenderLimited = 3,
+};
+
+class NET_EXPORT_PRIVATE AvailableChannelEstimator {
+ public:
+  explicit AvailableChannelEstimator(
+      QuicPacketSequenceNumber first_sequence_number,
+      QuicTime first_send_time,
+      QuicTime first_receive_time);
+
+  // Update the statistics with each receive time, for every packet we get a
+  // feedback message for.
+  void OnIncomingFeedback(QuicPacketSequenceNumber sequence_number,
+                          QuicByteCount packet_size,
+                          QuicTime sent_time,
+                          QuicTime receive_time);
+
+  // Get the current estimated available channel capacity.
+  // bandwidth_estimate is invalid if kAvailableChannelEstimateUnknown
+  // is returned.
+  AvailableChannelEstimateState GetAvailableChannelEstimate(
+      QuicBandwidth* bandwidth_estimate) const;
+
+ private:
+  const QuicPacketSequenceNumber first_sequence_number_;
+  const QuicTime first_send_time_;
+  const QuicTime first_receive_time_;
+  QuicPacketSequenceNumber last_incorporated_sequence_number_;
+  QuicTime last_time_sent_;
+  QuicTime last_receive_time_;
+  int number_of_sequence_numbers_;
+  QuicByteCount received_bytes_;
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_AVAILABLE_CHANNEL_ESTIMATOR_H_
diff --git a/net/quic/congestion_control/available_channel_estimator_test.cc b/net/quic/congestion_control/available_channel_estimator_test.cc
new file mode 100644
index 0000000..8c1c69e9
--- /dev/null
+++ b/net/quic/congestion_control/available_channel_estimator_test.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/available_channel_estimator.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class AvailableChannelEstimatorTest : public ::testing::Test {
+ protected:
+  void SetUp() {
+    srand(1234);
+    packet_size_ = 1200;
+    sequence_number_ = 1;
+    QuicTime receive_time = receive_clock_.Now();
+    QuicTime sent_time = send_clock_.Now();
+    estimator_.reset(new AvailableChannelEstimator(sequence_number_,
+                                                   sent_time,
+                                                   receive_time));
+  }
+
+  MockClock send_clock_;
+  MockClock receive_clock_;
+  QuicPacketSequenceNumber sequence_number_;
+  QuicByteCount packet_size_;
+  scoped_ptr<AvailableChannelEstimator> estimator_;
+};
+
+TEST_F(AvailableChannelEstimatorTest, SimpleBasic) {
+  QuicBandwidth bandwidth = QuicBandwidth::Zero();
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(1);
+  receive_clock_.AdvanceTime(received_delta);
+  send_clock_.AdvanceTime(send_delta);
+  QuicTime receive_time = receive_clock_.Now();
+  QuicTime sent_time = send_clock_.Now();
+  estimator_->OnIncomingFeedback(++sequence_number_,
+                                 packet_size_,
+                                 sent_time,
+                                 receive_time);
+  EXPECT_EQ(kAvailableChannelEstimateUnknown,
+            estimator_->GetAvailableChannelEstimate(&bandwidth));
+
+  receive_clock_.AdvanceTime(received_delta);
+  receive_time = receive_clock_.Now();
+  send_clock_.AdvanceTime(send_delta);
+  sent_time = send_clock_.Now();
+
+  estimator_->OnIncomingFeedback(++sequence_number_,
+                                 packet_size_,
+                                 sent_time,
+                                 receive_time);
+  EXPECT_EQ(kAvailableChannelEstimateUncertain,
+            estimator_->GetAvailableChannelEstimate(&bandwidth));
+
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_, received_delta),
+            bandwidth);
+}
+
+// TODO(pwestin): simulate cross traffic.
+TEST_F(AvailableChannelEstimatorTest, SimpleUncertainEstimate) {
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(1);
+
+  for (int i = 0; i < 8; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.Now();
+    send_clock_.AdvanceTime(send_delta);
+    QuicTime sent_time = send_clock_.Now();
+    estimator_->OnIncomingFeedback(++sequence_number_,
+                                   packet_size_,
+                                   sent_time,
+                                   receive_time);
+  }
+  QuicBandwidth bandwidth = QuicBandwidth::Zero();
+  EXPECT_EQ(kAvailableChannelEstimateUncertain,
+            estimator_->GetAvailableChannelEstimate(&bandwidth));
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_, received_delta),
+            bandwidth);
+}
+
+TEST_F(AvailableChannelEstimatorTest, SimpleGoodEstimate) {
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(1);
+
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.Now();
+    send_clock_.AdvanceTime(send_delta);
+    QuicTime sent_time = send_clock_.Now();
+    estimator_->OnIncomingFeedback(++sequence_number_,
+                                   packet_size_,
+                                   sent_time,
+                                   receive_time);
+  }
+  QuicBandwidth bandwidth = QuicBandwidth::Zero();
+  EXPECT_EQ(kAvailableChannelEstimateGood,
+            estimator_->GetAvailableChannelEstimate(&bandwidth));
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_, received_delta),
+            bandwidth);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/channel_estimator.cc b/net/quic/congestion_control/channel_estimator.cc
new file mode 100644
index 0000000..54b96ae
--- /dev/null
+++ b/net/quic/congestion_control/channel_estimator.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/channel_estimator.h"
+
+// To get information about bandwidth, our send rate for a pair of packets must
+// be much faster (ideally back to back) than the receive rate. In that
+// scenario, the arriving packet pair will tend to arrive at the max bandwidth
+// of the channel. Said another way, when our inter-departure time is a small
+// fraction of the inter-arrival time for the same pair of packets, then we can
+// get an estimate of bandwidth from that interarrival time. The following
+// constant is the threshold ratio for deriving bandwidth information.
+static const int kInterarrivalRatioThresholdForBandwidthEstimation = 5;
+static const size_t kMinNumberOfSamples = 10;
+static const size_t kMaxNumberOfSamples = 100;
+
+namespace net {
+
+ChannelEstimator::ChannelEstimator()
+    : last_sequence_number_(0),
+      last_send_time_(QuicTime::Zero()),
+      last_receive_time_(QuicTime::Zero()),
+      sorted_bitrate_estimates_(kMaxNumberOfSamples) {
+}
+
+ChannelEstimator::~ChannelEstimator() {
+}
+
+void ChannelEstimator::OnAcknowledgedPacket(
+    QuicPacketSequenceNumber sequence_number,
+    QuicByteCount packet_size,
+    QuicTime send_time,
+    QuicTime receive_time) {
+  if (last_sequence_number_ > sequence_number) {
+    // Old packet. The sequence_number use the full 64 bits even though it's
+    // less on the wire.
+    return;
+  }
+  if (last_sequence_number_ != sequence_number - 1) {
+    DLOG(INFO) << "Skip channel estimator due to lost packet(s)";
+  } else if (last_send_time_.IsInitialized()) {
+    QuicTime::Delta sent_delta = send_time.Subtract(last_send_time_);
+    QuicTime::Delta received_delta = receive_time.Subtract(last_receive_time_);
+    if (received_delta.ToMicroseconds() >
+        kInterarrivalRatioThresholdForBandwidthEstimation *
+            sent_delta.ToMicroseconds()) {
+      UpdateFilter(received_delta, packet_size, sequence_number);
+    }
+  }
+  last_sequence_number_ = sequence_number;
+  last_send_time_ = send_time;
+  last_receive_time_ = receive_time;
+}
+
+ChannelEstimateState ChannelEstimator::GetChannelEstimate(
+    QuicBandwidth* estimate) const {
+  if (sorted_bitrate_estimates_.Size() < kMinNumberOfSamples) {
+    // Not enough data to make an estimate.
+    return kChannelEstimateUnknown;
+  }
+  // Our data is stored in a sorted map, we need to iterate through our map to
+  // find the estimated bitrates at our targeted percentiles.
+
+  // Calculate 25th percentile.
+  size_t beginning_window = sorted_bitrate_estimates_.Size() / 4;
+  // Calculate 50th percentile.
+  size_t median = sorted_bitrate_estimates_.Size() / 2;
+  // Calculate 75th percentile.
+  size_t end_window = sorted_bitrate_estimates_.Size() - beginning_window;
+
+  QuicBandwidth bitrate_25th_percentile = QuicBandwidth::Zero();
+  QuicBandwidth median_bitrate = QuicBandwidth::Zero();
+  QuicBandwidth bitrate_75th_percentile = QuicBandwidth::Zero();
+  QuicMaxSizedMap<QuicBandwidth, QuicPacketSequenceNumber>::ConstIterator it =
+      sorted_bitrate_estimates_.Begin();
+
+  for (size_t i = 0; i <= end_window; ++i, ++it) {
+    DCHECK(it != sorted_bitrate_estimates_.End());
+    if (i == beginning_window) {
+      bitrate_25th_percentile = it->first;
+    }
+    if (i == median) {
+      median_bitrate = it->first;
+    }
+    if (i == end_window) {
+      bitrate_75th_percentile = it->first;
+    }
+  }
+  *estimate = median_bitrate;
+  DLOG(INFO) << "Channel estimate is:"
+             << median_bitrate.ToKBitsPerSecond() << " Kbit/s";
+  // If the bitrates in our 25th to 75th percentile window varies more than
+  // 25% of the median bitrate we consider the estimate to be uncertain.
+  if (bitrate_75th_percentile.Subtract(bitrate_25th_percentile) >
+      median_bitrate.Scale(0.25f)) {
+    return kChannelEstimateUncertain;
+  }
+  return kChannelEstimateGood;
+}
+
+void ChannelEstimator::UpdateFilter(QuicTime::Delta received_delta,
+                                    QuicByteCount size_delta,
+                                    QuicPacketSequenceNumber sequence_number) {
+  QuicBandwidth estimate =
+      QuicBandwidth::FromBytesAndTimeDelta(size_delta, received_delta);
+  sorted_bitrate_estimates_.Insert(estimate, sequence_number);
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/channel_estimator.h b/net/quic/congestion_control/channel_estimator.h
new file mode 100644
index 0000000..9be8031
--- /dev/null
+++ b/net/quic/congestion_control/channel_estimator.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Based on the inter arrival time of the received packets relative to the time
+// those packets where sent we can estimate the max capacity of the channel.
+// We can only use packet pair that are sent out faster than the acctual
+// channel capacity.
+#ifndef NET_QUIC_CONGESTION_CONTROL_CHANNEL_ESTIMATOR_H_
+#define NET_QUIC_CONGESTION_CONTROL_CHANNEL_ESTIMATOR_H_
+
+#include <list>
+#include <map>
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+#include "net/quic/congestion_control/quic_max_sized_map.h"
+#include "net/quic/quic_bandwidth.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+enum ChannelEstimateState {
+  kChannelEstimateUnknown = 0,
+  kChannelEstimateUncertain = 1,
+  kChannelEstimateGood = 2
+};
+
+class NET_EXPORT_PRIVATE ChannelEstimator {
+ public:
+  ChannelEstimator();
+  ~ChannelEstimator();
+
+  // This method should be called each time we acquire a receive time for a
+  // packet we previously sent.  It calculates deltas between consecutive
+  // receive times, and may use that to update the channel bandwidth estimate.
+  void OnAcknowledgedPacket(QuicPacketSequenceNumber sequence_number,
+                            QuicByteCount packet_size,
+                            QuicTime send_time,
+                            QuicTime receive_time);
+
+  // Get the current estimated state and channel capacity.
+  // Note: estimate will not be valid when kChannelEstimateUnknown is returned.
+  ChannelEstimateState GetChannelEstimate(QuicBandwidth* estimate) const;
+
+ private:
+  void UpdateFilter(QuicTime::Delta received_delta, QuicByteCount size_delta,
+                    QuicPacketSequenceNumber sequence_number);
+
+  QuicPacketSequenceNumber last_sequence_number_;
+  QuicTime last_send_time_;
+  QuicTime last_receive_time_;
+  QuicMaxSizedMap<QuicBandwidth, QuicPacketSequenceNumber>
+      sorted_bitrate_estimates_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChannelEstimator);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_CHANNEL_ESTIMATOR_H_
diff --git a/net/quic/congestion_control/channel_estimator_test.cc b/net/quic/congestion_control/channel_estimator_test.cc
new file mode 100644
index 0000000..7ff1b6c2
--- /dev/null
+++ b/net/quic/congestion_control/channel_estimator_test.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "net/quic/congestion_control/channel_estimator.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class ChannelEstimatorTest : public ::testing::Test {
+ protected:
+  void SetUp() {
+    srand(1234);
+    packet_size_ = 1200;
+    sequence_number_ = 1;
+  }
+
+  QuicPacketSequenceNumber sequence_number_;
+  QuicByteCount packet_size_;
+  MockClock send_clock_;
+  MockClock receive_clock_;
+  ChannelEstimator channel_estimator_;
+};
+
+TEST_F(ChannelEstimatorTest, SimpleNonDetect) {
+  // In this test, the send times differ by the same delta as the receive times,
+  // so we haven't sent packets closely enough to detect "spreading," or
+  // effective bandwidth.
+  QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 1000; ++i) {
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(delta);
+    receive_clock_.AdvanceTime(delta);
+  }
+  QuicBandwidth estimate = QuicBandwidth::Zero();
+  EXPECT_EQ(kChannelEstimateUnknown,
+            channel_estimator_.GetChannelEstimate(&estimate));
+  EXPECT_TRUE(estimate.IsZero());
+}
+
+TEST_F(ChannelEstimatorTest, SimplePacketPairDetect) {
+  // In this test, we start by sending packet pairs back-to-back and
+  // add a receive side spreading that indicate an effective bandwidth.
+  // We do 2 testes with different effective bandwidth to make sure that we
+  // detect the new effective bandwidth.
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    QuicTime send_time = send_clock_.ApproximateNow();
+
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(send_delta);
+  }
+  QuicBandwidth estimate = QuicBandwidth::Zero();
+  EXPECT_EQ(kChannelEstimateGood,
+            channel_estimator_.GetChannelEstimate(&estimate));
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_, received_delta),
+            estimate);
+  received_delta = QuicTime::Delta::FromMilliseconds(1);
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    QuicTime send_time = send_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(send_delta);
+  }
+  EXPECT_EQ(kChannelEstimateGood,
+            channel_estimator_.GetChannelEstimate(&estimate));
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_, received_delta),
+            estimate);
+}
+
+TEST_F(ChannelEstimatorTest, SimpleFlatSlope) {
+  // In this test, we send packet pairs back-to-back and add a slowly increasing
+  // receive side spreading. We expect the estimate to be good and that our
+  // mean receive side spreading is returned as the estimate.
+  QuicTime::Delta initial_received_delta = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta received_delta = initial_received_delta;
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    QuicTime send_time = send_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(send_delta);
+    received_delta = received_delta.Add(QuicTime::Delta::FromMicroseconds(10));
+  }
+  QuicBandwidth estimate = QuicBandwidth::Zero();
+  EXPECT_EQ(kChannelEstimateGood,
+            channel_estimator_.GetChannelEstimate(&estimate));
+
+  // Calculate our mean receive delta.
+  QuicTime::Delta increased_received_delta =
+      received_delta.Subtract(initial_received_delta);
+  QuicTime::Delta mean_received_delta = initial_received_delta.Add(
+      QuicTime::Delta::FromMicroseconds(
+          increased_received_delta.ToMicroseconds() / 2));
+
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_,
+      mean_received_delta), estimate);
+}
+
+TEST_F(ChannelEstimatorTest, SimpleMediumSlope) {
+  // In this test, we send packet pairs back-to-back and add an increasing
+  // receive side spreading. We expect the estimate to be uncertaint and that
+  // our mean receive side spreading is returned as the estimate.
+  QuicTime::Delta initial_received_delta = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta received_delta = initial_received_delta;
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    QuicTime send_time = send_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(send_delta);
+    received_delta = received_delta.Add(QuicTime::Delta::FromMicroseconds(50));
+  }
+  QuicBandwidth estimate = QuicBandwidth::Zero();
+  EXPECT_EQ(kChannelEstimateUncertain,
+            channel_estimator_.GetChannelEstimate(&estimate));
+
+  // Calculate our mean receive delta.
+  QuicTime::Delta increased_received_delta =
+      received_delta.Subtract(initial_received_delta);
+  QuicTime::Delta mean_received_delta = initial_received_delta.Add(
+      QuicTime::Delta::FromMicroseconds(
+          increased_received_delta.ToMicroseconds() / 2));
+
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_,
+      mean_received_delta), estimate);
+}
+
+TEST_F(ChannelEstimatorTest, SimpleSteepSlope) {
+  // In this test, we send packet pairs back-to-back and add a rapidly
+  // increasing receive side spreading. We expect the estimate to be uncertain
+  // and that our mean receive side spreading is returned as the estimate.
+  QuicTime::Delta initial_received_delta = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta received_delta = initial_received_delta;
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 100; ++i) {
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    QuicTime send_time = send_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    channel_estimator_.OnAcknowledgedPacket(sequence_number_++,
+                                            packet_size_,
+                                            send_time,
+                                            receive_time);
+    send_clock_.AdvanceTime(send_delta);
+    received_delta = received_delta.Add(QuicTime::Delta::FromMicroseconds(100));
+  }
+  QuicBandwidth estimate = QuicBandwidth::Zero();
+  EXPECT_EQ(kChannelEstimateUncertain,
+            channel_estimator_.GetChannelEstimate(&estimate));
+
+  // Calculate our mean receive delta.
+  QuicTime::Delta increased_received_delta =
+      received_delta.Subtract(initial_received_delta);
+  QuicTime::Delta mean_received_delta = initial_received_delta.Add(
+      QuicTime::Delta::FromMicroseconds(
+          increased_received_delta.ToMicroseconds() / 2));
+
+  EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta(packet_size_,
+      mean_received_delta), estimate);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/cube_root.cc b/net/quic/congestion_control/cube_root.cc
new file mode 100644
index 0000000..c563ad9
--- /dev/null
+++ b/net/quic/congestion_control/cube_root.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/cube_root.h"
+
+#include "base/logging.h"
+
+namespace {
+
+// Find last bit in a 64-bit word.
+int FindMostSignificantBit(uint64 x) {
+  if (!x) {
+    return 0;
+  }
+  int r = 0;
+  if (x & 0xffffffff00000000ull) {
+    x >>= 32;
+    r += 32;
+  }
+  if (x & 0xffff0000u) {
+    x >>= 16;
+    r += 16;
+  }
+  if (x & 0xff00u) {
+    x >>= 8;
+    r += 8;
+  }
+  if (x & 0xf0u) {
+    x >>= 4;
+    r += 4;
+  }
+  if (x & 0xcu) {
+    x >>= 2;
+    r += 2;
+  }
+  if (x & 0x02u) {
+    x >>= 1;
+    r++;
+  }
+  if (x & 0x01u) {
+    r++;
+  }
+  return r;
+}
+
+// 6 bits table [0..63]
+const uint32 cube_root_table[] = {
+    0,  54,  54,  54, 118, 118, 118, 118, 123, 129, 134, 138, 143, 147, 151,
+  156, 157, 161, 164, 168, 170, 173, 176, 179, 181, 185, 187, 190, 192, 194,
+  197, 199, 200, 202, 204, 206, 209, 211, 213, 215, 217, 219, 221, 222, 224,
+  225, 227, 229, 231, 232, 234, 236, 237, 239, 240, 242, 244, 245, 246, 248,
+  250, 251, 252, 254
+};
+}  // namespace
+
+namespace net {
+
+// Calculate the cube root using a table lookup followed by one Newton-Raphson
+// iteration.
+uint32 CubeRoot::Root(uint64 a) {
+  uint32 msb = FindMostSignificantBit(a);
+  DCHECK_LE(msb, 64u);
+
+  if (msb < 7) {
+    // MSB in our table.
+    return ((cube_root_table[static_cast<uint32>(a)]) + 31) >> 6;
+  }
+  // MSB          7,  8,  9, 10, 11, 12, 13, 14, 15, 16, ...
+  // cubic_shift  1,  1,  1,  2,  2,  2,  3,  3,  3,  4, ...
+  uint32 cubic_shift = (msb - 4);
+  cubic_shift = ((cubic_shift * 342) >> 10);  // Div by 3, biased high.
+
+  // 4 to 6 bits accuracy depending on MSB.
+  uint32 down_shifted_to_6bit = (a >> (cubic_shift * 3));
+  uint64 root = ((cube_root_table[down_shifted_to_6bit] + 10) << cubic_shift)
+      >> 6;
+
+  // Make one Newton-Raphson iteration.
+  // Since x has an error (inaccuracy due to the use of fix point) we get a
+  // more accurate result by doing x * (x - 1) instead of x * x.
+  root = 2 * root + (a / (root * (root - 1)));
+  root = ((root * 341) >> 10);  // Div by 3, biased low.
+  return static_cast<uint32>(root);
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/cube_root.h b/net/quic/congestion_control/cube_root.h
new file mode 100644
index 0000000..3b3736c
--- /dev/null
+++ b/net/quic/congestion_control/cube_root.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_CUBE_ROOT_H_
+#define NET_QUIC_CONGESTION_CONTROL_CUBE_ROOT_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE CubeRoot {
+ public:
+  // Calculates the cube root using a table lookup followed by one Newton-
+  // Raphson iteration.
+  static uint32 Root(uint64 a);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_CUBE_ROOT_H_
diff --git a/net/quic/congestion_control/cube_root_test.cc b/net/quic/congestion_control/cube_root_test.cc
new file mode 100644
index 0000000..8f4729cb
--- /dev/null
+++ b/net/quic/congestion_control/cube_root_test.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "net/quic/congestion_control/cube_root.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class CubeRootTest : public ::testing::Test {
+ protected:
+  CubeRootTest() {
+  }
+};
+
+TEST_F(CubeRootTest, LowRoot) {
+  for (uint32 i = 1; i < 256; ++i) {
+    uint64 cube = i * i * i;
+    uint8 cube_root = CubeRoot::Root(cube);
+    EXPECT_EQ(i, cube_root);
+  }
+}
+
+TEST_F(CubeRootTest, HighRoot) {
+  // Test the range we will opperate in, 1300 to 130 000.
+  // We expect some loss in accuracy, accepting +-0.2%.
+  for (uint64 i = 1300; i < 20000; i += 100) {
+    uint64 cube = i * i * i;
+    uint32 cube_root = CubeRoot::Root(cube);
+    uint32 margin = cube_root >> 9;  // Calculate 0.2% roughly by
+                                     // dividing by 512.
+    EXPECT_LE(i - margin, cube_root);
+    EXPECT_GE(i + margin, cube_root);
+  }
+  for (uint64 i = 20000; i < 130000; i *= 2) {
+    uint64 cube = i * i * i;
+    uint32 cube_root = CubeRoot::Root(cube);
+    uint32 margin = cube_root >> 9;
+    EXPECT_LE(i - margin, cube_root);
+    EXPECT_GE(i + margin, cube_root);
+  }
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc
new file mode 100644
index 0000000..0a15a74d
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "net/quic/congestion_control/cube_root.h"
+#include "net/quic/quic_protocol.h"
+
+namespace {
+// The following constants are in 2^10 fractions of a second instead of ms to
+// allow a 10 shift right to divide.
+const int kCubeScale = 40;  // 1024*1024^3 (first 1024 is from 0.100^3)
+                            // where 0.100 is 100 ms which is the scaling
+                            // round trip time.
+// TODO(pwestin): Tuning parameter, currently close to TCP cubic at 100ms RTT.
+const int kPacedCubeScale = 6000;
+const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) / kPacedCubeScale;
+}  // namespace
+
+namespace net {
+
+InterArrivalBitrateRampUp::InterArrivalBitrateRampUp(const QuicClock* clock)
+    : clock_(clock),
+      current_rate_(QuicBandwidth::Zero()),
+      channel_estimate_(QuicBandwidth::Zero()),
+      available_channel_estimate_(QuicBandwidth::Zero()),
+      halfway_point_(QuicBandwidth::Zero()),
+      epoch_(QuicTime::Zero()),
+      last_update_time_(QuicTime::Zero()) {
+}
+
+void InterArrivalBitrateRampUp::Reset(QuicBandwidth new_rate,
+                                      QuicBandwidth available_channel_estimate,
+                                      QuicBandwidth channel_estimate) {
+  epoch_ = clock_->ApproximateNow();
+  last_update_time_ = epoch_;
+  available_channel_estimate_ = std::max(new_rate, available_channel_estimate);
+  channel_estimate_ = std::max(channel_estimate, available_channel_estimate_);
+
+  halfway_point_ = available_channel_estimate_.Add(
+      (channel_estimate_.Subtract(available_channel_estimate_)).Scale(0.5f));
+
+  if (new_rate < available_channel_estimate_) {
+    time_to_origin_point_ = CalcuateTimeToOriginPoint(
+        available_channel_estimate_.Subtract(new_rate));
+  } else if (new_rate >= channel_estimate_) {
+    time_to_origin_point_ = 0;
+  } else if (new_rate >= halfway_point_) {
+    time_to_origin_point_ =
+        CalcuateTimeToOriginPoint(channel_estimate_.Subtract(new_rate));
+  } else {
+    time_to_origin_point_ = CalcuateTimeToOriginPoint(
+        new_rate.Subtract(available_channel_estimate_));
+  }
+  current_rate_ = new_rate;
+  DLOG(INFO) << "Reset; time to origin point:" << time_to_origin_point_;
+}
+
+void InterArrivalBitrateRampUp::UpdateChannelEstimate(
+    QuicBandwidth channel_estimate) {
+  if (available_channel_estimate_ > channel_estimate ||
+      current_rate_ > channel_estimate ||
+      channel_estimate_ == channel_estimate) {
+    // Ignore, because one of the following reasons:
+    // 1) channel estimate is bellow our current available estimate which we
+    //    value higher that this estimate.
+    // 2) channel estimate is bellow our current send rate.
+    // 3) channel estimate has not changed.
+    return;
+  }
+  if (available_channel_estimate_ == halfway_point_ &&
+      channel_estimate_  == halfway_point_) {
+    // First time we get a usable channel estimate.
+    channel_estimate_ = channel_estimate;
+    halfway_point_ = available_channel_estimate_.Add(
+        (channel_estimate_.Subtract(available_channel_estimate_).Scale(0.5f)));
+    DLOG(INFO) << "UpdateChannelEstimate; first usable value:"
+               << channel_estimate.ToKBitsPerSecond() << " Kbits/s";
+    return;
+  }
+  if (current_rate_ < halfway_point_) {
+    // Update channel estimate without recalculating if we are bellow the
+    // halfway point.
+    channel_estimate_ = channel_estimate;
+    return;
+  }
+  // We are between halfway point and our channel_estimate.
+  epoch_ = clock_->ApproximateNow();
+  last_update_time_ = epoch_;
+  channel_estimate_ = channel_estimate;
+
+  time_to_origin_point_ =
+      CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate_));
+
+  DLOG(INFO) << "UpdateChannelEstimate; time to origin point:"
+             << time_to_origin_point_;
+}
+
+QuicBandwidth InterArrivalBitrateRampUp::GetNewBitrate(
+    QuicBandwidth sent_bitrate) {
+  DCHECK(epoch_.IsInitialized());
+  QuicTime current_time = clock_->ApproximateNow();
+  // Cubic is "independent" of RTT, the update is limited by the time elapsed.
+  if (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval()) {
+    return current_rate_;
+  }
+  QuicTime::Delta time_from_last_update =
+      current_time.Subtract(last_update_time_);
+
+  last_update_time_ = current_time;
+
+  if (!sent_bitrate.IsZero() &&
+      sent_bitrate.Add(sent_bitrate) < current_rate_) {
+    // Don't go up in bitrate when we are not sending.
+    // We need to update the epoch to reflect this state.
+    epoch_ = epoch_.Add(time_from_last_update);
+    DLOG(INFO) << "Don't increase; our sent bitrate is:"
+               << sent_bitrate.ToKBitsPerSecond() << " Kbits/s"
+               << " current target rate is:"
+               << current_rate_.ToKBitsPerSecond() << " Kbits/s";
+    return current_rate_;
+  }
+  QuicTime::Delta time_from_epoch = current_time.Subtract(epoch_);
+
+  // Change the time unit from microseconds to 2^10 fractions per second. This
+  // is done to allow us to use shift as a divide operator.
+  int64 elapsed_time = (time_from_epoch.ToMicroseconds() << 10) /
+      kNumMicrosPerSecond;
+
+  int64 offset = time_to_origin_point_ - elapsed_time;
+  // Note: using int64 since QuicBandwidth can't be negative
+  int64 delta_pace_kbps = (kPacedCubeScale * offset * offset * offset) >>
+        kCubeScale;
+
+  bool start_bellow_halfway_point = false;
+  if (current_rate_ < halfway_point_) {
+    start_bellow_halfway_point = true;
+
+    // available_channel_estimate_ is the orgin of the cubic function.
+    QuicBandwidth current_rate = QuicBandwidth::FromBytesPerSecond(
+        available_channel_estimate_.ToBytesPerSecond() -
+            (delta_pace_kbps << 10));
+
+    if (start_bellow_halfway_point && current_rate >= halfway_point_) {
+      // We passed the halfway point, recalculate with new orgin.
+      epoch_ = clock_->ApproximateNow();
+      // channel_estimate_ is the new orgin of the cubic function.
+      if (current_rate >= channel_estimate_) {
+        time_to_origin_point_ = 0;
+      } else {
+        time_to_origin_point_ =
+            CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate));
+      }
+      DLOG(INFO) << "Passed the halfway point; time to origin point:"
+                 << time_to_origin_point_;
+    }
+    current_rate_ = current_rate;
+  } else {
+    // channel_estimate_ is the orgin of the cubic function.
+    current_rate_ = QuicBandwidth::FromBytesPerSecond(
+        channel_estimate_.ToBytesPerSecond() - (delta_pace_kbps << 10));
+  }
+  return current_rate_;
+}
+
+uint32 InterArrivalBitrateRampUp::CalcuateTimeToOriginPoint(
+    QuicBandwidth rate_difference) const {
+  return CubeRoot::Root(kCubeFactor * rate_difference.ToKBytesPerSecond());
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h
new file mode 100644
index 0000000..93199239
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Ramp up bitrate from a start point normally our "current_rate" as long as we
+// have no packet loss or delay events.
+// The first half of the ramp up curve follows a cubic function with its orgin
+// at the estimated available bandwidth, onece the bitrate pass the halfway
+// point between the estimated available bandwidth and the estimated max
+// bandwidth it will follw a new cubic function with its orgin at the estimated
+// max bandwidth.
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_BITRATE_RAMP_UP_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_BITRATE_RAMP_UP_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+#include "net/quic/quic_bandwidth.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE InterArrivalBitrateRampUp {
+ public:
+  explicit InterArrivalBitrateRampUp(const QuicClock* clock);
+
+  // Call after a decision to lower the bitrate and after a probe.
+  void Reset(QuicBandwidth current_rate,
+             QuicBandwidth available_channel_estimate,
+             QuicBandwidth channel_estimate);
+
+  // Call everytime we get a new channel estimate.
+  void UpdateChannelEstimate(QuicBandwidth channel_estimate);
+
+  // Compute a new send pace to use.
+  QuicBandwidth GetNewBitrate(QuicBandwidth sent_bitrate);
+
+ private:
+  uint32 CalcuateTimeToOriginPoint(QuicBandwidth rate_difference) const;
+
+  static const QuicTime::Delta MaxCubicTimeInterval() {
+    return QuicTime::Delta::FromMilliseconds(30);
+  }
+
+  const QuicClock* clock_;
+
+  QuicBandwidth current_rate_;
+  QuicBandwidth channel_estimate_;
+  QuicBandwidth available_channel_estimate_;
+  QuicBandwidth halfway_point_;
+
+  // Time when this cycle started, after a Reset.
+  QuicTime epoch_;
+
+  // Time when we updated current_rate_.
+  QuicTime last_update_time_;
+
+  // Time to origin point of cubic function in 2^10 fractions of a second.
+  uint32 time_to_origin_point_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalBitrateRampUp);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_BITRATE_RAMP_UP_H_
diff --git a/net/quic/congestion_control/inter_arrival_bitrate_ramp_up_test.cc b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up_test.cc
new file mode 100644
index 0000000..b644301
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_bitrate_ramp_up_test.cc
@@ -0,0 +1,404 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class InterArrivalBitrateRampUpTest : public ::testing::Test {
+ protected:
+  InterArrivalBitrateRampUpTest()
+      : one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+        hundred_ms_(QuicTime::Delta::FromMilliseconds(100)),
+        bitrate_ramp_up_(&clock_) {
+  }
+  void SetUp() {
+    clock_.AdvanceTime(one_ms_);
+  }
+  const QuicTime::Delta one_ms_;
+  const QuicTime::Delta hundred_ms_;
+  MockClock clock_;
+  InterArrivalBitrateRampUp bitrate_ramp_up_;
+};
+
+TEST_F(InterArrivalBitrateRampUpTest, GoodEstimates) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(100);
+  QuicBandwidth available_channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(400);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // First concave growth, towards available_channel_estimate.
+  for (int i = 0; i < 25; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(available_channel_estimate, sent_bitrate);
+    EXPECT_LE(start_rate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(available_channel_estimate, sent_bitrate);
+
+  // First convex growth, from available_channel_estimate.
+  for (int j = 0; j < 25; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+
+  // Second concave growth, towards channel_estimate.
+  for (int i = 0; i < 24; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+    EXPECT_LE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(channel_estimate, sent_bitrate);
+
+  // Second convex growth, from channel_estimate.
+  for (int j = 0; j < 25; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 100000,
+              sent_bitrate.ToBytesPerSecond(), 10000);
+
+  // Verify that we increase cubic.
+  for (int j = 0; j < 23; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 750000,
+              sent_bitrate.ToBytesPerSecond(), 10000);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, GoodEstimatesLimitedSendRate) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(100);
+  QuicBandwidth available_channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth max_sent_rate =
+      QuicBandwidth::FromKBytesPerSecond(125);
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(400);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // First concave growth, towards available_channel_estimate.
+  // Should pass without being affected by the max_sent_rate.
+  for (int i = 0; i < 25; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    // Cap our previus sent rate.
+    sent_bitrate = std::min(sent_bitrate, max_sent_rate);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(available_channel_estimate, sent_bitrate);
+    EXPECT_LE(start_rate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  // Cap our previus sent rate.
+  sent_bitrate = std::min(sent_bitrate, max_sent_rate);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(available_channel_estimate, sent_bitrate);
+
+  // First convex growth, from available_channel_estimate.
+  for (int j = 0; j < 25; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    // Cap our previus sent rate.
+    sent_bitrate = std::min(sent_bitrate, max_sent_rate);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = std::min(sent_bitrate, max_sent_rate);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  // We expect 2 * sent_bitrate to cap the rate.
+  EXPECT_LE(max_sent_rate.Add(max_sent_rate), sent_bitrate);
+  // Remove our sent cap.
+  // Expect bitrate to continue to ramp from its previous rate.
+  for (int j = 0; j < 5; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_LE(max_sent_rate.Add(max_sent_rate), sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, GoodEstimatesCloseToChannelEstimate) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(100);
+  QuicBandwidth available_channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(250);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // First concave growth, towards available_channel_estimate.
+  for (int i = 0; i < 25; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(available_channel_estimate, sent_bitrate);
+    EXPECT_LE(start_rate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(available_channel_estimate, sent_bitrate);
+
+  // First convex growth, from available_channel_estimate.
+  for (int j = 0; j < 15; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+
+  // Second concave growth, towards channel_estimate.
+  for (int i = 0; i < 14; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+    EXPECT_LE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(channel_estimate, sent_bitrate);
+
+  // Second convex growth, from channel_estimate.
+  for (int j = 0; j < 25; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 100000,
+              sent_bitrate.ToBytesPerSecond(), 10000);
+
+  // Verify that we increase cubic.
+  for (int j = 0; j < 24; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 780000,
+              sent_bitrate.ToBytesPerSecond(), 20000);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, UncertainEstimates) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(100);
+  QuicBandwidth available_channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(400 * 0.7f);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // First concave growth, towards available_channel_estimate.
+  for (int i = 0; i < 20; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(available_channel_estimate, sent_bitrate);
+    EXPECT_LE(start_rate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(available_channel_estimate, sent_bitrate);
+
+  // First convex growth, from available_channel_estimate.
+  for (int j = 0; j < 23; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+
+  // Second concave growth, towards channel_estimate.
+  for (int i = 0; i < 12; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+    EXPECT_LE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(channel_estimate, sent_bitrate);
+
+  // Second convex growth, from channel_estimate.
+  for (int j = 0; j < 30; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 100000,
+              sent_bitrate.ToBytesPerSecond(), 10000);
+
+  // Verify that we increase cubic.
+  for (int j = 0; j < 23; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond() + 750000,
+              sent_bitrate.ToBytesPerSecond(), 20000);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, UnknownEstimates) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(100);
+  QuicBandwidth available_channel_estimate =
+      QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(400);
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         available_channel_estimate);
+
+  // First convex growth, from start_rate.
+  for (int j = 0; j < 20; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(start_rate, sent_bitrate);
+    EXPECT_GE(available_channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(available_channel_estimate.ToBytesPerSecond(),
+              sent_bitrate.ToBytesPerSecond(), 10000);
+
+  // Verify that we increase cubic.
+  for (int j = 0; j < 31; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_NEAR(channel_estimate.ToBytesPerSecond(),
+              sent_bitrate.ToBytesPerSecond(), 10000);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, UpdatingChannelEstimateHigher) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth available_channel_estimate = start_rate;
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(250);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // Convex growth, from available_channel_estimate.
+  for (int j = 0; j < 16; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+
+  // Increse channel estimate.
+  channel_estimate = QuicBandwidth::FromKBytesPerSecond(300);
+  bitrate_ramp_up_.UpdateChannelEstimate(channel_estimate);
+
+  // Concave growth, towards channel_estimate.
+  for (int i = 0; i < 22; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+    EXPECT_LE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(channel_estimate, sent_bitrate);
+}
+
+TEST_F(InterArrivalBitrateRampUpTest, UpdatingChannelEstimateLower) {
+  QuicBandwidth start_rate = QuicBandwidth::FromKBytesPerSecond(200);
+  QuicBandwidth available_channel_estimate = start_rate;
+  QuicBandwidth channel_estimate = QuicBandwidth::FromKBytesPerSecond(250);
+  QuicBandwidth halfway_point = available_channel_estimate.Add(
+      channel_estimate.Subtract(available_channel_estimate).Scale(0.5f));
+  QuicBandwidth sent_bitrate = QuicBandwidth::Zero();
+  bitrate_ramp_up_.Reset(start_rate,
+                         available_channel_estimate,
+                         channel_estimate);
+
+  // Convex growth, from available_channel_estimate.
+  for (int j = 0; j < 16; ++j) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_LE(available_channel_estimate, sent_bitrate);
+    EXPECT_GE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(halfway_point, sent_bitrate);
+
+  // Decrese channel estimate.
+  channel_estimate = QuicBandwidth::FromKBytesPerSecond(240);
+  bitrate_ramp_up_.UpdateChannelEstimate(channel_estimate);
+
+  // Concave growth, towards channel_estimate.
+  for (int i = 0; i < 11; ++i) {
+    clock_.AdvanceTime(hundred_ms_);
+    sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+    EXPECT_GE(channel_estimate, sent_bitrate);
+    EXPECT_LE(halfway_point, sent_bitrate);
+  }
+  clock_.AdvanceTime(hundred_ms_);
+  sent_bitrate = bitrate_ramp_up_.GetNewBitrate(sent_bitrate);
+  EXPECT_LE(channel_estimate, sent_bitrate);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector.cc b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
new file mode 100644
index 0000000..73e005d
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_overuse_detector.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_overuse_detector.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+// Initial noise variance, equal to a standard deviation of 1 millisecond.
+static const float kInitialVarianceNoise = 1000000.0;
+
+// Minimum variance of the time delta.
+static const int kMinVarianceDelta = 10000;
+
+// Threshold for accumulated delta.
+static const int kThresholdAccumulatedDeltasUs = 1000;
+
+// The higher the beta parameter, the lower is the effect of the input and the
+// more damping of the noise. And the longer time for a detection.
+static const float kBeta = 0.98f;
+
+// Same as above, described as numerator and denominator.
+static const int kBetaNumerator = 49;
+static const int kBetaDenominator = 50;
+
+// Trigger a signal when the accumulated time drift is larger than
+// 5 x standard deviation.
+// A lower value triggers earlier with more false detect as a side effect.
+static const int kDetectDriftStandardDeviation = 5;
+
+// Trigger an overuse when the time difference between send time and receive
+// is larger than 7 x standard deviation.
+// A lower value triggers earlier with more false detect as a side effect.
+static const float kDetectTimeDiffStandardDeviation = 7;
+
+// Trigger an overuse when the mean of the time difference diverges too far
+// from 0.
+// A higher value trigger earlier with more false detect as a side effect.
+static const int kDetectSlopeFactor = 14;
+
+// We need to get some initial statistics before the detection can start.
+static const int kMinSamplesBeforeDetect = 10;
+
+namespace net {
+
+InterArrivalOveruseDetector::InterArrivalOveruseDetector()
+    : last_sequence_number_(0),
+      num_of_deltas_(0),
+      accumulated_deltas_(QuicTime::Delta::Zero()),
+      delta_mean_(0.0),
+      delta_variance_(kInitialVarianceNoise),
+      delta_overuse_counter_(0),
+      delta_estimate_(kBandwidthSteady),
+      slope_overuse_counter_(0),
+      slope_estimate_(kBandwidthSteady),
+      send_receive_offset_(QuicTime::Delta::Infinite()),
+      estimated_congestion_delay_(QuicTime::Delta::Zero()) {
+}
+
+void InterArrivalOveruseDetector::OnAcknowledgedPacket(
+    QuicPacketSequenceNumber sequence_number,
+    QuicTime send_time,
+    bool last_of_send_time,
+    QuicTime receive_time) {
+  if (last_sequence_number_ >= sequence_number) {
+    // This is an old packet and should be ignored.  Note that we are called
+    // with a full 64 bit sequence number, even if the wire format may only
+    // convey some low-order bits of that number.
+    DLOG(INFO) << "Skip old packet";
+    return;
+  }
+
+  last_sequence_number_ = sequence_number;
+
+  if (current_packet_group_.send_time != send_time) {
+    // First value in this group. If the last packet of a group is lost we
+    // overwrite the old value and start over with a new measurement.
+    current_packet_group_.send_time = send_time;
+    // The receive_time value might not be first in a packet burst if that
+    // packet was lost, however we will still use it in this calculation.
+    UpdateSendReceiveTimeOffset(receive_time.Subtract(send_time));
+  }
+  if (!last_of_send_time) {
+    // We expect more packet with this send time.
+    return;
+  }
+  // First packet of a later group, the previous group sample is ready.
+  if (previous_packet_group_.send_time.IsInitialized()) {
+    QuicTime::Delta sent_delta = send_time.Subtract(
+        previous_packet_group_.send_time);
+    QuicTime::Delta receive_delta = receive_time.Subtract(
+        previous_packet_group_.last_receive_time);
+    // We assume that groups of packets are sent together as bursts (tagged
+    // with identical send times) because it is too computationally expensive
+    // to pace them out individually.  The received_delta is then the total
+    // delta between the receipt of the last packet of the previous group, and
+    // the last packet of the current group.  Assuming we are transmitting
+    // these bursts on average at the available bandwidth rate, there should be
+    // no change in overall spread (both deltas should be the same).
+    UpdateFilter(receive_delta, sent_delta);
+  }
+  // Save current as previous.
+  previous_packet_group_ = current_packet_group_;
+  previous_packet_group_.last_receive_time = receive_time;
+}
+
+void InterArrivalOveruseDetector::UpdateSendReceiveTimeOffset(
+    QuicTime::Delta offset) {
+  // Note the send and receive time can have a randomly large offset, however
+  // they are stable in relation to each other, hence no or extremely low clock
+  // drift relative to the duration of our stream.
+  if (offset.ToMicroseconds() < send_receive_offset_.ToMicroseconds()) {
+    send_receive_offset_ = offset;
+  }
+  estimated_congestion_delay_ = offset.Subtract(send_receive_offset_);
+}
+
+BandwidthUsage InterArrivalOveruseDetector::GetState(
+    QuicTime::Delta* estimated_congestion_delay) {
+  *estimated_congestion_delay = estimated_congestion_delay_;
+  int64 sigma_delta = sqrt(static_cast<double>(delta_variance_));
+  DetectSlope(sigma_delta);
+  DetectDrift(sigma_delta);
+  return std::max(slope_estimate_, delta_estimate_);
+}
+
+void InterArrivalOveruseDetector::UpdateFilter(QuicTime::Delta received_delta,
+                                               QuicTime::Delta sent_delta) {
+  ++num_of_deltas_;
+  QuicTime::Delta time_diff = received_delta.Subtract(sent_delta);
+  UpdateDeltaEstimate(time_diff);
+  accumulated_deltas_ = accumulated_deltas_.Add(time_diff);
+}
+
+void InterArrivalOveruseDetector::UpdateDeltaEstimate(
+    QuicTime::Delta residual) {
+  DCHECK_EQ(1, kBetaDenominator - kBetaNumerator);
+  int64 residual_us = residual.ToMicroseconds();
+  delta_mean_ =
+      (kBetaNumerator * delta_mean_ + residual_us) / kBetaDenominator;
+  delta_variance_ =
+      (kBetaNumerator * delta_variance_ +
+      (delta_mean_ - residual_us) * (delta_mean_ - residual_us)) /
+      kBetaDenominator;
+
+  if (delta_variance_ < kMinVarianceDelta) {
+    delta_variance_ = kMinVarianceDelta;
+  }
+}
+
+void InterArrivalOveruseDetector::DetectDrift(int64 sigma_delta) {
+  // We have 2 drift detectors. The accumulate of deltas and the absolute time
+  // differences.
+  if (num_of_deltas_ < kMinSamplesBeforeDetect) {
+    return;
+  }
+  if (delta_overuse_counter_ > 0 &&
+      accumulated_deltas_.ToMicroseconds() > kThresholdAccumulatedDeltasUs) {
+    if (delta_estimate_ != kBandwidthDraining) {
+      DLOG(INFO) << "Bandwidth estimate drift: Draining buffer(s) "
+                 << accumulated_deltas_.ToMilliseconds() << " ms";
+      delta_estimate_ = kBandwidthDraining;
+    }
+    return;
+  }
+  if ((sigma_delta * kDetectTimeDiffStandardDeviation >
+          estimated_congestion_delay_.ToMicroseconds()) &&
+      (sigma_delta * kDetectDriftStandardDeviation >
+          abs(accumulated_deltas_.ToMicroseconds()))) {
+    if (delta_estimate_ != kBandwidthSteady) {
+      DLOG(INFO) << "Bandwidth estimate drift: Steady"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta
+                 << " offset:" << send_receive_offset_.ToMicroseconds()
+                 << " delta:" << estimated_congestion_delay_.ToMicroseconds()
+                 << " drift:" << accumulated_deltas_.ToMicroseconds();
+      delta_estimate_ = kBandwidthSteady;
+      // Reset drift counter.
+      accumulated_deltas_ = QuicTime::Delta::Zero();
+      delta_overuse_counter_ = 0;
+    }
+    return;
+  }
+  if (accumulated_deltas_.ToMicroseconds() > 0) {
+    if (delta_estimate_ != kBandwidthOverUsing) {
+      ++delta_overuse_counter_;
+      DLOG(INFO) << "Bandwidth estimate drift: Over using"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta
+                 << " offset:" << send_receive_offset_.ToMicroseconds()
+                 << " delta:" << estimated_congestion_delay_.ToMicroseconds()
+                 << " drift:" << accumulated_deltas_.ToMicroseconds();
+      delta_estimate_ = kBandwidthOverUsing;
+    }
+  } else {
+    if (delta_estimate_ != kBandwidthUnderUsing) {
+      --delta_overuse_counter_;
+      DLOG(INFO) << "Bandwidth estimate drift: Under using"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta
+                 << " offset:" << send_receive_offset_.ToMicroseconds()
+                 << " delta:" << estimated_congestion_delay_.ToMicroseconds()
+                 << " drift:" << accumulated_deltas_.ToMicroseconds();
+      delta_estimate_ = kBandwidthUnderUsing;
+    }
+    // Adding decay of negative accumulated_deltas_ since it could be caused by
+    // a starting with full buffers. This way we will always converge to 0.
+    accumulated_deltas_ = accumulated_deltas_.Add(
+        QuicTime::Delta::FromMicroseconds(sigma_delta >> 3));
+  }
+}
+
+void InterArrivalOveruseDetector::DetectSlope(int64 sigma_delta) {
+  // We use the mean change since it has a constant expected mean 0
+  // regardless of number of packets and spread. It is also safe to use during
+  // packet loss, since a lost packet only results in a missed filter update
+  // not a drift.
+  if (num_of_deltas_ < kMinSamplesBeforeDetect) {
+    return;
+  }
+  if (slope_overuse_counter_ > 0 && delta_mean_ > 0) {
+    if (slope_estimate_ != kBandwidthDraining) {
+      DLOG(INFO) << "Bandwidth estimate slope: Draining buffer(s)";
+    }
+    slope_estimate_ = kBandwidthDraining;
+    return;
+  }
+  if (sigma_delta > abs(delta_mean_) * kDetectSlopeFactor) {
+    if (slope_estimate_ != kBandwidthSteady) {
+      DLOG(INFO) << "Bandwidth estimate slope: Steady"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta;
+      slope_overuse_counter_ = 0;
+      slope_estimate_ = kBandwidthSteady;
+    }
+    return;
+  }
+  if (delta_mean_ > 0) {
+    if (slope_estimate_ != kBandwidthOverUsing) {
+      ++slope_overuse_counter_;
+      DLOG(INFO) << "Bandwidth estimate slope: Over using"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta;
+      slope_estimate_ = kBandwidthOverUsing;
+    }
+  } else {
+    if (slope_estimate_ != kBandwidthUnderUsing) {
+      --slope_overuse_counter_;
+      DLOG(INFO) << "Bandwidth estimate slope: Under using"
+                 << " mean:" << delta_mean_
+                 << " sigma:" << sigma_delta;
+      slope_estimate_ = kBandwidthUnderUsing;
+    }
+  }
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector.h b/net/quic/congestion_control/inter_arrival_overuse_detector.h
new file mode 100644
index 0000000..1852362
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_overuse_detector.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class is a helper class to the inter arrival congestion control. It
+// provide a signal to the inter arrival congestion control of the estimated
+// state of our transport channel. The estimate is based on the inter arrival
+// time of the received packets relative to the time those packets were sent;
+// we can estimate the build up of buffers on the network before packets are
+// lost.
+//
+// Note: this class is not thread-safe.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_OVERUSE_DETECTOR_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_OVERUSE_DETECTOR_H_
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+enum NET_EXPORT_PRIVATE RateControlRegion {
+  kRateControlRegionUnknown = 0,
+  kRateControlRegionUnderMax = 1,
+  kRateControlRegionNearMax = 2
+};
+
+// Note: Order is important.
+enum NET_EXPORT_PRIVATE BandwidthUsage {
+  kBandwidthSteady = 0,
+  kBandwidthUnderUsing = 1,
+  kBandwidthDraining = 2,
+  kBandwidthOverUsing = 3,
+};
+
+//  Normal state transition diagram
+//
+//         kBandwidthUnderUsing
+//                  |
+//                  |
+//           kBandwidthSteady
+//             |          ^
+//             |          |
+//   kBandwidthOverUsing  |
+//             |          |
+//             |          |
+//          kBandwidthDraining
+//
+//  The above transitions is in normal operation, with extreme values we don't
+//  enforce the state transitions, hence you could in extreme scenarios go
+//  between any states.
+//
+//  kBandwidthSteady       When the packets arrive in the same pace as we sent
+//                         them. In this state we can increase our send pace.
+//
+//  kBandwidthOverUsing    When the packets arrive slower than the pace we sent
+//                         them. In this state we should decrease our send pace.
+//                         When we enter into this state we will also get an
+//                         estimate on how much delay we have built up. The
+//                         reduction in send pace should be chosen to drain the
+//                         built up delay within reasonable time.
+//
+//  kBandwidthUnderUsing   When the packets arrive faster than the pace we sent
+//                         them. In this state another stream disappeared from
+//                         a shared link leaving us more available bandwidth.
+//                         In this state we should hold our pace to make sure we
+//                         fully drain the buffers before we start increasing
+//                         our send rate. We do this to avoid operating with
+//                         semi-full buffers.
+//
+//  kBandwidthDraining     We can only be in this state after we have been in a
+//                         overuse state. In this state we should hold our pace
+//                         to make sure we fully drain the buffers before we
+//                         start increasing our send rate. We do this to avoid
+//                         operating with semi-full buffers.
+
+class NET_EXPORT_PRIVATE InterArrivalOveruseDetector {
+ public:
+  InterArrivalOveruseDetector();
+
+  // Update the statistics with the received delta times, call for every
+  // received delta time. This function assumes that there is no re-orderings.
+  // If multiple packets are sent at the same time (identical send_time)
+  // last_of_send_time should be set to false for all but the last calls to
+  // this function. If there is only one packet sent at a given time
+  // last_of_send_time must be true.
+  // received_delta is the time difference between receiving this packet and the
+  // previously received packet.
+  void OnAcknowledgedPacket(QuicPacketSequenceNumber sequence_number,
+                            QuicTime send_time,
+                            bool last_of_send_time,
+                            QuicTime receive_time);
+
+  // Get the current estimated state and update the estimated congestion delay.
+  // |estimated_congestion_delay| will be updated with the estimated built up
+  // buffer delay; it must not be NULL as it will be updated with the estimate.
+  // Note 1: estimated_buffer_delay will only be valid when kBandwidthOverUsing
+  //         is returned.
+  // Note 2: it's assumed that the pacer lower its send pace to drain the
+  //         built up buffer within reasonable time. The pacer should use the
+  //         estimated_buffer_delay as a guidance on how much to back off.
+  // Note 3: The absolute value of estimated_congestion_delay is less reliable
+  //         than the state itself. It is also biased to low since we can't know
+  //         how full the buffers are when the flow starts.
+  BandwidthUsage GetState(QuicTime::Delta* estimated_congestion_delay);
+
+ private:
+  struct PacketGroup {
+    PacketGroup()
+        : send_time(QuicTime::Zero()),
+          last_receive_time(QuicTime::Zero()) {
+    }
+    QuicTime send_time;
+    QuicTime last_receive_time;
+  };
+
+  // Update the statistics with the absolute receive time relative to the
+  // absolute send time.
+  void UpdateSendReceiveTimeOffset(QuicTime::Delta offset);
+
+  // Update the filter with this new data point.
+  void UpdateFilter(QuicTime::Delta received_delta,
+                    QuicTime::Delta sent_delta);
+
+  // Update the estimate with this residual.
+  void UpdateDeltaEstimate(QuicTime::Delta residual);
+
+  // Estimate the state based on the slope of the changes.
+  void DetectSlope(int64 sigma_delta);
+
+  // Estimate the state based on the accumulated drift of the changes.
+  void DetectDrift(int64 sigma_delta);
+
+  // Current grouping of packets that were sent at the same time.
+  PacketGroup current_packet_group_;
+  // Grouping of packets that were sent at the same time, just before the
+  // current_packet_group_ above.
+  PacketGroup previous_packet_group_;
+  // Sequence number of the last acknowledged packet.
+  QuicPacketSequenceNumber last_sequence_number_;
+  // Number of received delta times with unique send time.
+  int num_of_deltas_;
+  // Estimated accumulation of received delta times.
+  // Note: Can be negative and can drift over time which is why we bias it
+  // towards 0 and reset it given some triggers.
+  QuicTime::Delta accumulated_deltas_;
+  // Current running mean of our received delta times.
+  int delta_mean_;
+  // Current running variance of our received delta times.
+  int64 delta_variance_;
+  // Number of overuse signals currently triggered in this state.
+  // Note: negative represent underuse.
+  int delta_overuse_counter_;
+  // State estimated by the delta times.
+  BandwidthUsage delta_estimate_;
+  // Number of overuse signals currently triggered in this state.
+  // Note: negative represent underuse.
+  int slope_overuse_counter_;
+  // State estimated by the slope of the delta times.
+  BandwidthUsage slope_estimate_;
+  // Lowest offset between send and receive time ever received in this session.
+  QuicTime::Delta send_receive_offset_;
+  // Last received time difference between our normalized send and receive time.
+  QuicTime::Delta estimated_congestion_delay_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalOveruseDetector);
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_OVERUSE_DETECTOR_H_
diff --git a/net/quic/congestion_control/inter_arrival_overuse_detector_test.cc b/net/quic/congestion_control/inter_arrival_overuse_detector_test.cc
new file mode 100644
index 0000000..8d37749
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_overuse_detector_test.cc
@@ -0,0 +1,1114 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "net/quic/congestion_control/inter_arrival_overuse_detector.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+static const double kPi = 3.14159265;
+
+namespace net {
+namespace test {
+
+class InterArrivalOveruseDetectorTest : public ::testing::Test {
+ protected:
+  InterArrivalOveruseDetectorTest();
+
+  QuicTime::Delta GaussianRandom(QuicTime::Delta mean,
+                                 QuicTime::Delta standard_deviation);
+
+  int Run100000Samples(int packets_per_burst,
+                       QuicTime::Delta mean,
+                       QuicTime::Delta standard_deviation);
+
+  int RunUntilOveruse(int packets_per_burst,
+                      QuicTime::Delta mean,
+                      QuicTime::Delta standard_deviation,
+                      QuicTime::Delta drift_per_burst,
+                      QuicTime::Delta *estimated_buffer_delay);
+
+  int RunUntilSteady(int packets_per_burst,
+                     QuicTime::Delta mean,
+                     QuicTime::Delta standard_deviation,
+                     QuicTime::Delta drift_per_burst);
+
+  int RunUntilNotDraining(int packets_per_burst,
+                          QuicTime::Delta mean,
+                          QuicTime::Delta standard_deviation,
+                          QuicTime::Delta drift_per_burst);
+
+  int RunUntilUnderusing(int packets_per_burst,
+                         QuicTime::Delta mean,
+                         QuicTime::Delta standard_deviation,
+                         QuicTime::Delta drift_per_burst);
+
+  void RunXBursts(int bursts,
+                  int packets_per_burst,
+                  QuicTime::Delta mean,
+                  QuicTime::Delta standard_deviation,
+                  QuicTime::Delta drift_per_burst);
+
+  QuicPacketSequenceNumber sequence_number_;
+  MockClock send_clock_;
+  MockClock receive_clock_;
+  QuicTime::Delta drift_from_mean_;
+  InterArrivalOveruseDetector overuse_detector_;
+  unsigned int seed_;
+};
+
+InterArrivalOveruseDetectorTest::InterArrivalOveruseDetectorTest()
+    : sequence_number_(1),
+      drift_from_mean_(QuicTime::Delta::Zero()),
+      seed_(1234) {
+}
+
+QuicTime::Delta InterArrivalOveruseDetectorTest::GaussianRandom(
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation) {
+  // Creating a Normal distribution variable from two independent uniform
+  // variables based on the Box-Muller transform.
+  double uniform1 = base::RandDouble();
+  double uniform2 = base::RandDouble();
+
+  QuicTime::Delta random = QuicTime::Delta::FromMicroseconds(
+      static_cast<int>(standard_deviation.ToMicroseconds() *
+          sqrt(-2 * log(uniform1)) * cos(2 * kPi * uniform2))).
+              Add(mean).Subtract(drift_from_mean_);
+  if (random < QuicTime::Delta::Zero()) {
+    // Don't do negative deltas.
+    drift_from_mean_ = drift_from_mean_.Subtract(mean);
+    return QuicTime::Delta::Zero();
+  }
+  drift_from_mean_ = drift_from_mean_.Add(random).Subtract(mean);
+  return random;
+}
+
+int InterArrivalOveruseDetectorTest::Run100000Samples(
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation) {
+  int unique_overuse = 0;
+  int last_overuse = -1;
+  for (int i = 0; i < 100000; ++i) {
+    // Assume that we send out the packets with perfect pacing.
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean, standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+    // We expect to randomly hit a few false detects, count the unique
+    // overuse events, hence not multiple signals in a row.
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    if (kBandwidthOverUsing == overuse_detector_.GetState(
+        &estimated_buffer_delay)) {
+      if (last_overuse + 1 != i) {
+        unique_overuse++;
+      }
+      last_overuse = i;
+    }
+  }
+  return unique_overuse;
+}
+
+int InterArrivalOveruseDetectorTest::RunUntilOveruse(
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation,
+    QuicTime::Delta drift_per_burst,
+    QuicTime::Delta *estimated_buffer_delay) {
+  // Simulate a higher send pace, that is too high.
+  for (int i = 0; i < 1000; ++i) {
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean.Add(drift_per_burst),
+                                              standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+    if (kBandwidthOverUsing == overuse_detector_.GetState(
+        estimated_buffer_delay)) {
+      return i + 1;
+    }
+  }
+  return -1;
+}
+
+int InterArrivalOveruseDetectorTest::RunUntilSteady(
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation,
+    QuicTime::Delta drift_per_burst) {
+  // Simulate a lower send pace, that is lower than the capacity.
+  for (int i = 0; i < 1000; ++i) {
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean.Subtract(drift_per_burst),
+                                              standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    if (kBandwidthSteady ==
+        overuse_detector_.GetState(&estimated_buffer_delay)) {
+      return i + 1;
+    }
+  }
+  return -1;
+}
+
+int InterArrivalOveruseDetectorTest::RunUntilNotDraining(
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation,
+    QuicTime::Delta drift_per_burst) {
+  // Simulate a lower send pace, that is lower than the capacity.
+  for (int i = 0; i < 1000; ++i) {
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean.Subtract(drift_per_burst),
+                                              standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    if (kBandwidthDraining >
+        overuse_detector_.GetState(&estimated_buffer_delay)) {
+      return i + 1;
+    }
+  }
+  return -1;
+}
+
+int InterArrivalOveruseDetectorTest::RunUntilUnderusing(
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation,
+    QuicTime::Delta drift_per_burst) {
+  // Simulate a lower send pace, that is lower than the capacity.
+  for (int i = 0; i < 1000; ++i) {
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean.Subtract(drift_per_burst),
+                                              standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    if (kBandwidthUnderUsing == overuse_detector_.GetState(
+        &estimated_buffer_delay)) {
+      return i + 1;
+    }
+  }
+  return -1;
+}
+
+void InterArrivalOveruseDetectorTest::RunXBursts(
+    int bursts,
+    int packets_per_burst,
+    QuicTime::Delta mean,
+    QuicTime::Delta standard_deviation,
+    QuicTime::Delta drift_per_burst) {
+  for (int i = 0; i < bursts; ++i) {
+    send_clock_.AdvanceTime(mean);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    // Do only one random delta for all packets in a burst.
+    receive_clock_.AdvanceTime(GaussianRandom(mean.Add(drift_per_burst),
+                                              standard_deviation));
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    for (int j = 0; j <= packets_per_burst; ++j) {
+      overuse_detector_.OnAcknowledgedPacket(sequence_number_++,
+                                             send_time,
+                                             (j == packets_per_burst),
+                                             receive_time);
+    }
+  }
+}
+
+// TODO(pwestin): test packet loss impact on accuracy.
+// TODO(pwestin): test colored noise by dropping late frames.
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_TestNoise) {
+  int count[100];
+  memset(count, 0, sizeof(count));
+  for (int i = 0; i < 10000; ++i) {
+    QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(30);
+    QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(10);
+    count[GaussianRandom(mean, standard_deviation).ToMilliseconds()]++;
+  }
+  for (int j = 0; j < 100; ++j) {
+    DLOG(INFO) << j << ":" << count[j];
+  }
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_SimpleNonOveruse) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(10);
+
+  for (int i = 0; i < 1000; ++i) {
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           true,
+                                           receive_time);
+    send_clock_.AdvanceTime(delta);
+    receive_clock_.AdvanceTime(delta);
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    EXPECT_EQ(kBandwidthSteady,
+              overuse_detector_.GetState(&estimated_buffer_delay));
+  }
+}
+
+TEST_F(InterArrivalOveruseDetectorTest,
+       DISABLED_SimpleNonOveruseSendClockAhead) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(10);
+  send_clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1234));
+
+  for (int i = 0; i < 1000; ++i) {
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           true,
+                                           receive_time);
+    send_clock_.AdvanceTime(delta);
+    receive_clock_.AdvanceTime(delta);
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    EXPECT_EQ(kBandwidthSteady,
+              overuse_detector_.GetState(&estimated_buffer_delay));
+  }
+}
+
+TEST_F(InterArrivalOveruseDetectorTest,
+       DISABLED_SimpleNonOveruseSendClockBehind) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta delta = QuicTime::Delta::FromMilliseconds(10);
+  receive_clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1234));
+
+  for (int i = 0; i < 1000; ++i) {
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           true,
+                                           receive_time);
+    send_clock_.AdvanceTime(delta);
+    receive_clock_.AdvanceTime(delta);
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    EXPECT_EQ(kBandwidthSteady,
+              overuse_detector_.GetState(&estimated_buffer_delay));
+  }
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_SimpleNonOveruseWithVariance) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  for (int i = 0; i < 1000; ++i) {
+    if (i % 2) {
+      receive_clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+    } else {
+      receive_clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(15));
+    }
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           true,
+                                           receive_time);
+    send_clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+    QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+    EXPECT_EQ(kBandwidthSteady,
+              overuse_detector_.GetState(&estimated_buffer_delay));
+  }
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_SimpleOveruse) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta send_delta = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+
+  for (int i = 0; i < 100000; ++i) {
+    send_clock_.AdvanceTime(send_delta);
+    receive_clock_.AdvanceTime(received_delta);
+    QuicTime send_time = send_clock_.ApproximateNow();
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    // Sending 2 packets the same time as that is what we expect to do.
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           false,
+                                           receive_time);
+    receive_clock_.AdvanceTime(received_delta);
+    receive_time = receive_clock_.ApproximateNow();
+    overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                           send_time,
+                                           true,
+                                           receive_time);
+
+    EXPECT_EQ(kBandwidthSteady,
+              overuse_detector_.GetState(&estimated_buffer_delay));
+  }
+  // Simulate a higher send pace, that is too high by receiving 1 millisecond
+  // late per packet.
+  received_delta = QuicTime::Delta::FromMilliseconds(6);
+  send_clock_.AdvanceTime(send_delta);
+  receive_clock_.AdvanceTime(received_delta);
+  QuicTime send_time = send_clock_.ApproximateNow();
+  QuicTime receive_time = receive_clock_.ApproximateNow();
+  overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                         send_time,
+                                         false,
+                                         receive_time);
+  receive_clock_.AdvanceTime(received_delta);
+  receive_time = receive_clock_.ApproximateNow();
+  overuse_detector_.OnAcknowledgedPacket(sequence_number++,
+                                         send_time,
+                                         true,
+                                         receive_time);
+  EXPECT_EQ(kBandwidthOverUsing,
+            overuse_detector_.GetState(&estimated_buffer_delay));
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance10Kbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1000);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(5);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 6 updates with 5 milliseconds before
+  // detection.
+  // Resulting in a minimal buffer build up of 30 milliseconds.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(6, bursts_until_overuse);
+  EXPECT_NEAR(40, estimated_buffer_delay.ToMilliseconds(), 15);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(6, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(7, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance10Kbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1000);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(50);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(50);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 6 updates with 50 milliseconds before
+  // detection.
+  // Resulting in a minimal buffer build up of 300 milliseconds.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(6, bursts_until_overuse);
+  EXPECT_NEAR(400, estimated_buffer_delay.ToMilliseconds(), 150);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(6, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(7, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance100Kbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(100);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(5);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 6 updates with 5 milliseconds
+  // before detection.
+  // Resulting in a minimal buffer build up of 30 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(6, bursts_until_overuse);
+  EXPECT_NEAR(40, estimated_buffer_delay.ToMilliseconds(), 15);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(1,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(7, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(5, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance100Kbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(100);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(50);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(50);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 4 updates with 50 milliseconds
+  // before detection.
+  // Resulting in a minimal buffer build up of 200 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(4, bursts_until_overuse);
+  EXPECT_NEAR(300, estimated_buffer_delay.ToMilliseconds(), 150);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(1,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(5, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(5, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance1Mbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(5);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 4 updates with 5 millisecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 20 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(4, bursts_until_overuse);
+  EXPECT_NEAR(30, estimated_buffer_delay.ToMilliseconds(), 15);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(14, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(4, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance1Mbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(1);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 6 updates with 1 millisecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 6 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(6, bursts_until_overuse);
+  EXPECT_NEAR(8, estimated_buffer_delay.ToMilliseconds(), 3);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(16, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(4, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance20Mbit) {
+  int packets_per_burst = 2;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMicroseconds(500);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMicroseconds(500);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 4 updates with 500 microsecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 2 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(4, bursts_until_overuse);
+  EXPECT_NEAR(3, estimated_buffer_delay.ToMilliseconds(), 2);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(100,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_NEAR(100, bursts_until_not_draining, 10);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(1, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance100Mbit) {
+  int packets_per_burst = 10;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMicroseconds(500);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMicroseconds(500);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 4 updates with 500 microsecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 2 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(4, bursts_until_overuse);
+  EXPECT_NEAR(3, estimated_buffer_delay.ToMilliseconds(), 2);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(100,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_NEAR(100, bursts_until_not_draining, 10);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(1, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_VeryHighVariance100Mbit) {
+  int packets_per_burst = 10;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMicroseconds(500);
+
+  // We get false overuse in this scenario due to that the standard deviation is
+  // higher than our mean and the fact that a delta time can't be negative. This
+  // results in an under estimated standard deviation in the estimator causing
+  // false detects.
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(2000, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 25 updates with 500 microsecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 12.5 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(17, bursts_until_overuse);
+  EXPECT_NEAR(22, estimated_buffer_delay.ToMilliseconds(), 15);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(100,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(117, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(1, bursts_until_underusing);
+}
+
+//
+//  Tests simulating big drop in bitrate.
+//
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance1MbitTo100Kbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(100);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 1 update with 100 millisecond
+  // before detection.
+  // Resulting in a minimal buffer build up of 100 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(1, bursts_until_overuse);
+  EXPECT_NEAR(104, estimated_buffer_delay.ToMilliseconds(), 3);
+
+  // Back off 20% lower than estimate to drain.
+  mean = QuicTime::Delta::FromMilliseconds(100);
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(20);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(5, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(3, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_HighVariance20MbitTo1Mbit) {
+  int packets_per_burst = 2;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMicroseconds(500);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(10);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 1 update with 10 milliseconds
+  // before detection.
+  // Resulting in a minimal buffer build up of 10 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(1, bursts_until_overuse);
+  EXPECT_NEAR(12, estimated_buffer_delay.ToMilliseconds(), 2);
+
+  // Back off 20% lower than estimate to drain.
+  mean = QuicTime::Delta::FromMilliseconds(10);
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(2);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(5, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(3, bursts_until_underusing);
+}
+
+//
+//  Tests that we can detect slow drifts.
+//
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance1MbitSmallSteps) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMicroseconds(100);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 41 updates with 100 microseconds before
+  // detection.
+  // Resulting in a minimal buffer build up of 4.1 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(41, bursts_until_overuse);
+  EXPECT_NEAR(7, estimated_buffer_delay.ToMilliseconds(), 3);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(29, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(71, bursts_until_underusing);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest, DISABLED_LowVariance1MbitTinySteps) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMicroseconds(10);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a higher send pace, that is too high.
+  // With current tuning we require 345 updates with 10 microseconds before
+  // detection.
+  // Resulting in a minimal buffer build up of 3.45 ms.
+  QuicTime::Delta estimated_buffer_delay(QuicTime::Delta::Zero());
+  int bursts_until_overuse = RunUntilOveruse(packets_per_burst,
+                                             mean,
+                                             standard_deviation,
+                                             drift_per_burst,
+                                             &estimated_buffer_delay);
+  EXPECT_GE(345, bursts_until_overuse);
+  EXPECT_NEAR(7, estimated_buffer_delay.ToMilliseconds(), 3);
+
+  // Simulate an RTT of 100 ms. Hence overusing for additional 100 ms before
+  // detection.
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  int bursts_until_not_draining = RunUntilNotDraining(packets_per_burst,
+                                                      mean,
+                                                      standard_deviation,
+                                                      drift_per_burst);
+  EXPECT_GE(18, bursts_until_not_draining);
+
+  // After draining the buffer additionally we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(683, bursts_until_underusing);
+}
+
+//
+//  Tests simulating starting with full buffers.
+//
+
+TEST_F(InterArrivalOveruseDetectorTest,
+       DISABLED_StartedWithFullBuffersHighVariance1Mbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(5);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a lower send pace.
+  // Draining the buffer until we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(6, bursts_until_underusing);
+
+  // After draining the buffers we are back in a normal state.
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(0);
+  int bursts_until_steady = RunUntilSteady(packets_per_burst,
+                                           mean,
+                                           standard_deviation,
+                                           drift_per_burst);
+  EXPECT_GE(6, bursts_until_steady);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest,
+       DISABLED_StartedWithFullBuffersHighVariance1MbitSlowDrift) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(5);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(1);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a faster receive pace.
+  // Draining the buffer until we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(21, bursts_until_underusing);
+
+  // Simulate an RTT of 100 ms. Hence underusing for additional 100 ms before
+  // detection.
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(-1);
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(0);
+  int bursts_until_steady = RunUntilSteady(packets_per_burst,
+                                           mean,
+                                           standard_deviation,
+                                           drift_per_burst);
+  EXPECT_GE(4, bursts_until_steady);
+}
+
+TEST_F(InterArrivalOveruseDetectorTest,
+       DISABLED_StartedWithFullBuffersLowVariance1Mbit) {
+  int packets_per_burst = 1;
+  QuicTime::Delta mean = QuicTime::Delta::FromMilliseconds(10);
+  QuicTime::Delta standard_deviation = QuicTime::Delta::FromMilliseconds(1);
+  QuicTime::Delta drift_per_burst = QuicTime::Delta::FromMilliseconds(1);
+
+  int overuse_signals = Run100000Samples(packets_per_burst,
+                                         mean,
+                                         standard_deviation);
+  EXPECT_GE(1, overuse_signals);
+
+  // Simulate a lower send pace.
+  // Draining the buffer until we detect an underuse.
+  int bursts_until_underusing = RunUntilUnderusing(packets_per_burst,
+                                                   mean,
+                                                   standard_deviation,
+                                                   drift_per_burst);
+  EXPECT_GE(5, bursts_until_underusing);
+
+  // Simulate an RTT of 100 ms. Hence underusing for additional 100 ms before
+  // detection.
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(-1);
+  RunXBursts(10,
+             packets_per_burst,
+             mean,
+             standard_deviation,
+             drift_per_burst);
+
+  // After draining the buffers we are back in a normal state.
+  drift_per_burst = QuicTime::Delta::FromMilliseconds(0);
+  int bursts_until_steady = RunUntilSteady(packets_per_burst,
+                                           mean,
+                                           standard_deviation,
+                                           drift_per_burst);
+  EXPECT_GE(41, bursts_until_steady);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_probe.cc b/net/quic/congestion_control/inter_arrival_probe.cc
new file mode 100644
index 0000000..6d4c073
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_probe.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_probe.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+const int kProbeSizePackets = 10;
+const net::QuicByteCount kMinPacketSize = 500;
+const int64 kDefaultBytesPerSecond = 40000;
+const float kUncertainScaleFactor = 0.5;  // TODO(pwestin): revisit this factor.
+}
+
+namespace net {
+
+InterArrivalProbe::InterArrivalProbe()
+    : estimate_available_(false),
+      available_channel_estimate_(QuicBandwidth::Zero()),
+      unacked_data_(0) {
+}
+
+InterArrivalProbe::~InterArrivalProbe() {
+}
+
+bool InterArrivalProbe::GetEstimate(QuicBandwidth* available_channel_estimate) {
+  if (!estimate_available_) {
+    return false;
+  }
+  *available_channel_estimate = available_channel_estimate_;
+  return true;
+}
+
+void InterArrivalProbe::OnSentPacket(QuicByteCount bytes) {
+  if (!estimate_available_) {
+    unacked_data_ += bytes;
+  }
+}
+
+void InterArrivalProbe::OnAcknowledgedPacket(QuicByteCount bytes) {
+  if (!estimate_available_) {
+    DCHECK_LE(bytes, unacked_data_);
+    unacked_data_ -= bytes;
+  }
+}
+
+QuicByteCount InterArrivalProbe::GetAvailableCongestionWindow() {
+  if (estimate_available_) {
+    return 0;
+  }
+  return (kProbeSizePackets * kMaxPacketSize) - unacked_data_;
+}
+
+void InterArrivalProbe::OnIncomingFeedback(
+    QuicPacketSequenceNumber sequence_number,
+    QuicByteCount bytes_sent,
+    QuicTime time_sent,
+    QuicTime time_received) {
+  if (estimate_available_) {
+    return;
+  }
+
+  if (available_channel_estimator_.get() == NULL) {
+    if (bytes_sent < kMinPacketSize) {
+      // Packet too small to start the probe phase.
+      return;
+    }
+    first_sequence_number_ = sequence_number;
+    available_channel_estimator_.reset(new AvailableChannelEstimator(
+        sequence_number, time_sent, time_received));
+    return;
+  }
+
+  available_channel_estimator_->OnIncomingFeedback(sequence_number,
+                                                   bytes_sent,
+                                                   time_sent,
+                                                   time_received);
+  if (sequence_number < kProbeSizePackets - 1  + first_sequence_number_) {
+    // We need more feedback before we have a probe estimate.
+    return;
+  }
+  // Get the current estimated available channel capacity.
+  // available_channel_estimate is invalid if kAvailableChannelEstimateUnknown
+  // is returned.
+  QuicBandwidth available_channel_estimate = QuicBandwidth::Zero();
+  AvailableChannelEstimateState available_channel_estimate_state =
+      available_channel_estimator_->GetAvailableChannelEstimate(
+          &available_channel_estimate);
+  switch (available_channel_estimate_state) {
+    case kAvailableChannelEstimateUnknown:
+      // Backup when we miss our probe.
+      available_channel_estimate_ =
+          QuicBandwidth::FromBytesPerSecond(kDefaultBytesPerSecond);
+      break;
+    case kAvailableChannelEstimateUncertain:
+      available_channel_estimate_ =
+          available_channel_estimate.Scale(kUncertainScaleFactor);
+      break;
+    case kAvailableChannelEstimateGood:
+      available_channel_estimate_ = available_channel_estimate;
+      break;
+    case kAvailableChannelEstimateSenderLimited:
+      available_channel_estimate_ =
+          std::max(available_channel_estimate,
+                   QuicBandwidth::FromBytesPerSecond(kDefaultBytesPerSecond));
+      break;
+  }
+  estimate_available_ = true;
+  available_channel_estimator_.reset(NULL);
+  DLOG(INFO) << "Probe estimate:"
+             << available_channel_estimate_.ToKBitsPerSecond()
+             << " Kbits/s";
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_probe.h b/net/quic/congestion_control/inter_arrival_probe.h
new file mode 100644
index 0000000..5788a68
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_probe.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Class that handle the initial probing phase of inter arrival congestion
+// control.
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_PROBE_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_PROBE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_export.h"
+#include "net/quic/congestion_control/available_channel_estimator.h"
+#include "net/quic/quic_bandwidth.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE InterArrivalProbe {
+ public:
+  InterArrivalProbe();
+  ~InterArrivalProbe();
+
+  // Call every time a packet is sent to the network.
+  void OnSentPacket(QuicByteCount bytes);
+
+  // Call once for each sent packet that we receive an acknowledgement from
+  // the peer for.
+  void OnAcknowledgedPacket(QuicByteCount bytes);
+
+  // Call to get the number of bytes that can be sent as part of this probe.
+  QuicByteCount GetAvailableCongestionWindow();
+
+  // Call once for each sent packet we receive a congestion feedback from the
+  // peer for.
+  // If a peer sends both and ack and feedback for a sent packet, both
+  // OnAcknowledgedPacket and OnIncomingFeedback should be called.
+  void OnIncomingFeedback(QuicPacketSequenceNumber sequence_number,
+                          QuicByteCount bytes_sent,
+                          QuicTime time_sent,
+                          QuicTime time_received);
+
+  // Returns false as long as we are probing, available_channel_estimate is
+  // invalid during that time. When the probe is completed this function return
+  // true and available_channel_estimate contains the estimate.
+  bool GetEstimate(QuicBandwidth* available_channel_estimate);
+
+ private:
+  scoped_ptr<AvailableChannelEstimator> available_channel_estimator_;
+  QuicPacketSequenceNumber first_sequence_number_;
+  bool estimate_available_;
+  QuicBandwidth available_channel_estimate_;
+  QuicByteCount unacked_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalProbe);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_PROBE_H_
diff --git a/net/quic/congestion_control/inter_arrival_probe_test.cc b/net/quic/congestion_control/inter_arrival_probe_test.cc
new file mode 100644
index 0000000..18b97d3
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_probe_test.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/inter_arrival_probe.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class InterArrivalProbeTest : public ::testing::Test {
+ protected:
+  InterArrivalProbeTest() : start_(QuicTime::Zero()) {
+  }
+
+  InterArrivalProbe probe_;
+  QuicTime start_;
+};
+
+TEST_F(InterArrivalProbeTest, CongestionWindow) {
+  for (size_t i = 0; i < 10; i++) {
+    probe_.OnSentPacket(kMaxPacketSize);
+    EXPECT_EQ((9 - i) * kMaxPacketSize, probe_.GetAvailableCongestionWindow());
+  }
+  probe_.OnAcknowledgedPacket(kMaxPacketSize);
+  EXPECT_EQ(kMaxPacketSize, probe_.GetAvailableCongestionWindow());
+
+  probe_.OnSentPacket(kMaxPacketSize);
+  EXPECT_EQ(0u, probe_.GetAvailableCongestionWindow());
+}
+
+TEST_F(InterArrivalProbeTest, Estimate) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicByteCount bytes_sent = kMaxPacketSize;
+  QuicTime time_received = start_.Add(QuicTime::Delta::FromMilliseconds(10));
+  QuicTime time_sent = start_.Add(QuicTime::Delta::FromMilliseconds(1));
+  QuicBandwidth available_channel_estimate = QuicBandwidth::Zero();
+
+  for (size_t i = 0; i < 10; ++i) {
+    EXPECT_FALSE(probe_.GetEstimate(&available_channel_estimate));
+
+    probe_.OnIncomingFeedback(sequence_number++,
+                              bytes_sent,
+                              time_sent,
+                              time_received);
+    time_sent = time_sent.Add(QuicTime::Delta::FromMilliseconds(1));
+    time_received = time_received.Add(QuicTime::Delta::FromMilliseconds(10));
+  }
+  EXPECT_TRUE(probe_.GetEstimate(&available_channel_estimate));
+  EXPECT_EQ(kMaxPacketSize * 100,
+            static_cast<uint64>(available_channel_estimate.ToBytesPerSecond()));
+}
+
+TEST_F(InterArrivalProbeTest, EstimateWithLoss) {
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicByteCount bytes_sent = kMaxPacketSize;
+  QuicTime time_received = start_.Add(QuicTime::Delta::FromMilliseconds(10));
+  QuicTime time_sent = start_.Add(QuicTime::Delta::FromMilliseconds(1));
+  QuicBandwidth available_channel_estimate = QuicBandwidth::Zero();
+
+  for (size_t i = 0; i < 6; ++i) {
+    EXPECT_FALSE(probe_.GetEstimate(&available_channel_estimate));
+
+    probe_.OnIncomingFeedback(sequence_number,
+                              bytes_sent,
+                              time_sent,
+                              time_received);
+    sequence_number += 2;
+    time_sent = time_sent.Add(QuicTime::Delta::FromMilliseconds(1));
+    time_received = time_received.Add(QuicTime::Delta::FromMilliseconds(10));
+  }
+  EXPECT_TRUE(probe_.GetEstimate(&available_channel_estimate));
+  EXPECT_EQ(kMaxPacketSize * 50,
+            static_cast<uint64>(available_channel_estimate.ToBytesPerSecond()));
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_receiver.cc b/net/quic/congestion_control/inter_arrival_receiver.cc
new file mode 100644
index 0000000..770b287
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_receiver.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_receiver.h"
+
+#include "base/basictypes.h"
+
+namespace net {
+
+InterArrivalReceiver::InterArrivalReceiver()
+    : accumulated_number_of_recoverd_lost_packets_(0) {
+}
+
+InterArrivalReceiver::~InterArrivalReceiver() {
+}
+
+bool InterArrivalReceiver::GenerateCongestionFeedback(
+    QuicCongestionFeedbackFrame* feedback) {
+  if (received_packet_times_.size() <= 1) {
+    // Don't waste resources by sending a feedback frame for only one packet.
+    return false;
+  }
+  feedback->type = kInterArrival;
+  feedback->inter_arrival.accumulated_number_of_lost_packets =
+      accumulated_number_of_recoverd_lost_packets_;
+
+  // Copy our current receive set to our feedback message, we will not resend
+  // this data if it is lost.
+  feedback->inter_arrival.received_packet_times = received_packet_times_;
+
+  // Prepare for the next set of arriving packets by clearing our current set.
+  received_packet_times_.clear();
+  return true;
+}
+
+void InterArrivalReceiver::RecordIncomingPacket(
+    QuicByteCount /*bytes*/,
+    QuicPacketSequenceNumber sequence_number,
+    QuicTime timestamp,
+    bool revived) {
+  if (revived) {
+    ++accumulated_number_of_recoverd_lost_packets_;
+  }
+  received_packet_times_.insert(std::make_pair(sequence_number, timestamp));
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_receiver.h b/net/quic/congestion_control/inter_arrival_receiver.h
new file mode 100644
index 0000000..a9de62cb
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_receiver.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_RECEIVER_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_RECEIVER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+#include "net/quic/congestion_control/receive_algorithm_interface.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE InterArrivalReceiver
+    : public ReceiveAlgorithmInterface {
+ public:
+  InterArrivalReceiver();
+  virtual ~InterArrivalReceiver();
+
+  // Start implementation of ReceiveAlgorithmInterface.
+  virtual bool GenerateCongestionFeedback(
+      QuicCongestionFeedbackFrame* feedback) OVERRIDE;
+
+  virtual void RecordIncomingPacket(QuicByteCount bytes,
+                                    QuicPacketSequenceNumber sequence_number,
+                                    QuicTime timestamp,
+                                    bool revived) OVERRIDE;
+  // End implementation of ReceiveAlgorithmInterface.
+
+ private:
+  // We need to keep track of FEC recovered packets.
+  int accumulated_number_of_recoverd_lost_packets_;
+
+  // The set of received packets since the last feedback was sent, along with
+  // their arrival times.
+  TimeMap received_packet_times_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalReceiver);
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_RECEIVER_H_
diff --git a/net/quic/congestion_control/inter_arrival_receiver_test.cc b/net/quic/congestion_control/inter_arrival_receiver_test.cc
new file mode 100644
index 0000000..927fb6d9
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_receiver_test.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "net/quic/congestion_control/inter_arrival_receiver.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class InterArrivalReceiverTest : public ::testing::Test {
+ protected:
+  InterArrivalReceiver receiver_;
+  MockClock clock_;
+};
+
+TEST_F(InterArrivalReceiverTest, SimpleReceiver) {
+  QuicTime start = clock_.ApproximateNow();
+  QuicTime::Delta received_delta = QuicTime::Delta::FromMilliseconds(10);
+  clock_.AdvanceTime(received_delta);
+  QuicTime receive_timestamp = clock_.ApproximateNow();
+  receiver_.RecordIncomingPacket(1, 1, receive_timestamp, false);
+
+  QuicCongestionFeedbackFrame feedback;
+  ASSERT_FALSE(receiver_.GenerateCongestionFeedback(&feedback));
+
+  clock_.AdvanceTime(received_delta);
+  receive_timestamp = clock_.ApproximateNow();
+  // Packet not received; but rather revived by FEC.
+  receiver_.RecordIncomingPacket(1, 2, receive_timestamp, true);
+  clock_.AdvanceTime(received_delta);
+  receive_timestamp = clock_.ApproximateNow();
+  receiver_.RecordIncomingPacket(1, 3, receive_timestamp, false);
+
+  ASSERT_TRUE(receiver_.GenerateCongestionFeedback(&feedback));
+
+  EXPECT_EQ(kInterArrival, feedback.type);
+  EXPECT_EQ(1, feedback.inter_arrival.accumulated_number_of_lost_packets);
+  EXPECT_EQ(3u, feedback.inter_arrival.received_packet_times.size());
+  TimeMap::iterator it = feedback.inter_arrival.received_packet_times.begin();
+  EXPECT_EQ(1u, it->first);
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10), it->second.Subtract(start));
+  it = feedback.inter_arrival.received_packet_times.begin();
+  it++;
+  EXPECT_EQ(2u, it->first);
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(20), it->second.Subtract(start));
+  it++;
+  EXPECT_EQ(3u, it->first);
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(30), it->second.Subtract(start));
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_sender.cc b/net/quic/congestion_control/inter_arrival_sender.cc
new file mode 100644
index 0000000..77b9af0
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_sender.cc
@@ -0,0 +1,449 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_sender.h"
+
+namespace {
+const int64 kProbeBitrateKBytesPerSecond = 1200;  // 9.6 Mbit/s
+const float kPacketLossBitrateReduction = 0.7f;
+const float kUncertainSafetyMargin = 0.7f;
+const float kMaxBitrateReduction = 0.9f;
+const float kMinBitrateReduction = 0.05f;
+const uint64 kMinBitrateKbit = 10;
+const int kInitialRttMs = 60;  // At a typical RTT 60 ms.
+}
+
+namespace net {
+
+InterArrivalSender::InterArrivalSender(const QuicClock* clock)
+    : probing_(true),
+      current_bandwidth_(QuicBandwidth::Zero()),
+      smoothed_rtt_(QuicTime::Delta::Zero()),
+      channel_estimator_(new ChannelEstimator()),
+      bitrate_ramp_up_(new InterArrivalBitrateRampUp(clock)),
+      overuse_detector_(new InterArrivalOveruseDetector()),
+      probe_(new InterArrivalProbe()),
+      state_machine_(new InterArrivalStateMachine(clock)),
+      paced_sender_(new PacedSender(QuicBandwidth::FromKBytesPerSecond(
+          kProbeBitrateKBytesPerSecond))),
+      accumulated_number_of_lost_packets_(0),
+      bandwidth_usage_state_(kBandwidthSteady),
+      back_down_time_(QuicTime::Zero()),
+      back_down_bandwidth_(QuicBandwidth::Zero()),
+      back_down_congestion_delay_(QuicTime::Delta::Zero()) {
+}
+
+InterArrivalSender::~InterArrivalSender() {
+}
+
+void InterArrivalSender::OnIncomingQuicCongestionFeedbackFrame(
+    const QuicCongestionFeedbackFrame& feedback,
+    QuicTime feedback_receive_time,
+    QuicBandwidth sent_bandwidth,
+    const SentPacketsMap& sent_packets) {
+  DCHECK(feedback.type == kInterArrival);
+
+  if (feedback.type != kInterArrival) {
+    return;
+  }
+  TimeMap::const_iterator received_it;
+  for (received_it = feedback.inter_arrival.received_packet_times.begin();
+      received_it != feedback.inter_arrival.received_packet_times.end();
+      ++received_it) {
+    QuicPacketSequenceNumber sequence_number = received_it->first;
+
+    SentPacketsMap::const_iterator sent_it = sent_packets.find(sequence_number);
+    if (sent_it == sent_packets.end()) {
+      // Too old data; ignore and move forward.
+      DLOG(INFO) << "Too old feedback move forward, sequence_number:"
+                 << sequence_number;
+      continue;
+    }
+    QuicTime time_received = received_it->second;
+    QuicTime time_sent = sent_it->second->SendTimestamp();
+    QuicByteCount bytes_sent = sent_it->second->BytesSent();
+
+    channel_estimator_->OnAcknowledgedPacket(
+        sequence_number, bytes_sent, time_sent, time_received);
+    if (probing_) {
+      probe_->OnIncomingFeedback(
+          sequence_number, bytes_sent, time_sent, time_received);
+    } else {
+      bool last_of_send_time = false;
+      SentPacketsMap::const_iterator next_sent_it = ++sent_it;
+      if (next_sent_it == sent_packets.end()) {
+        // No more sent packets; hence this must be the last.
+        last_of_send_time = true;
+      } else {
+        if (time_sent != next_sent_it->second->SendTimestamp()) {
+          // Next sent packet have a different send time.
+          last_of_send_time = true;
+        }
+      }
+      overuse_detector_->OnAcknowledgedPacket(
+          sequence_number, time_sent, last_of_send_time, time_received);
+    }
+  }
+  if (probing_) {
+    probing_ = ProbingPhase(feedback_receive_time);
+    return;
+  }
+
+  bool packet_loss_event = false;
+  if (accumulated_number_of_lost_packets_ !=
+      feedback.inter_arrival.accumulated_number_of_lost_packets) {
+    accumulated_number_of_lost_packets_ =
+        feedback.inter_arrival.accumulated_number_of_lost_packets;
+    packet_loss_event = true;
+  }
+  InterArrivalState state = state_machine_->GetInterArrivalState();
+
+  if (state == kInterArrivalStatePacketLoss ||
+      state == kInterArrivalStateCompetingTcpFLow) {
+    if (packet_loss_event) {
+      if (!state_machine_->PacketLossEvent()) {
+        // Less than one RTT since last PacketLossEvent.
+        return;
+      }
+      EstimateBandwidthAfterLossEvent(feedback_receive_time);
+    } else {
+      EstimateNewBandwidth(feedback_receive_time, sent_bandwidth);
+    }
+    return;
+  }
+  EstimateDelayBandwidth(feedback_receive_time, sent_bandwidth);
+}
+
+bool InterArrivalSender::ProbingPhase(QuicTime feedback_receive_time) {
+  QuicBandwidth available_channel_estimate = QuicBandwidth::Zero();
+  if (!probe_->GetEstimate(&available_channel_estimate)) {
+    // Continue probing phase.
+    return true;
+  }
+  QuicBandwidth channel_estimate = QuicBandwidth::Zero();
+  ChannelEstimateState channel_estimator_state =
+      channel_estimator_->GetChannelEstimate(&channel_estimate);
+
+  QuicBandwidth new_rate =
+      available_channel_estimate.Scale(kUncertainSafetyMargin);
+
+  switch (channel_estimator_state) {
+    case kChannelEstimateUnknown:
+      channel_estimate = available_channel_estimate;
+      break;
+    case kChannelEstimateUncertain:
+      channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
+      break;
+    case kChannelEstimateGood:
+      // Do nothing.
+      break;
+  }
+  new_rate = std::max(new_rate,
+                       QuicBandwidth::FromKBitsPerSecond(kMinBitrateKbit));
+
+  bitrate_ramp_up_->Reset(new_rate, available_channel_estimate,
+                          channel_estimate);
+
+  current_bandwidth_ = new_rate;
+  paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_rate);
+  DLOG(INFO) << "Probe result; new rate:"
+             << new_rate.ToKBitsPerSecond() << " Kbits/s "
+             << " available estimate:"
+             << available_channel_estimate.ToKBitsPerSecond() << " Kbits/s "
+             << " channel estimate:"
+             << channel_estimate.ToKBitsPerSecond() << " Kbits/s ";
+  return false;
+}
+
+void InterArrivalSender::OnIncomingAck(
+    QuicPacketSequenceNumber /*acked_sequence_number*/,
+    QuicByteCount acked_bytes,
+    QuicTime::Delta rtt) {
+  DCHECK(!rtt.IsZero());
+  DCHECK(!rtt.IsInfinite());
+  if (smoothed_rtt_.IsZero()) {
+    smoothed_rtt_ = rtt;
+  } else {
+    smoothed_rtt_ = QuicTime::Delta::FromMicroseconds(
+        (smoothed_rtt_.ToMicroseconds() * 3 + rtt.ToMicroseconds()) / 4);
+  }
+  state_machine_->set_rtt(SmoothedRtt());
+  if (probing_) {
+    probe_->OnAcknowledgedPacket(acked_bytes);
+  }
+}
+
+void InterArrivalSender::OnIncomingLoss(QuicTime ack_receive_time) {
+  // Packet loss was reported.
+  if (!probing_) {
+    if (!state_machine_->PacketLossEvent()) {
+      // Less than one RTT since last PacketLossEvent.
+      return;
+    }
+    // Calculate new pace rate.
+    EstimateBandwidthAfterLossEvent(ack_receive_time);
+  }
+}
+
+void InterArrivalSender::SentPacket(QuicTime sent_time,
+                                    QuicPacketSequenceNumber sequence_number,
+                                    QuicByteCount bytes,
+                                    Retransmission /*retransmit*/) {
+  if (probing_) {
+    probe_->OnSentPacket(bytes);
+  }
+  paced_sender_->SentPacket(sent_time, bytes);
+}
+
+void InterArrivalSender::AbandoningPacket(
+    QuicPacketSequenceNumber /*sequence_number*/,
+    QuicByteCount abandoned_bytes) {
+  // TODO(pwestin): use for out outer_congestion_window_ logic.
+  if (probing_) {
+    probe_->OnAcknowledgedPacket(abandoned_bytes);
+  }
+}
+
+QuicTime::Delta InterArrivalSender::TimeUntilSend(
+    QuicTime now,
+    Retransmission /*retransmit*/,
+    HasRetransmittableData has_retransmittable_data) {
+  // TODO(pwestin): implement outer_congestion_window_ logic.
+  QuicTime::Delta outer_window = QuicTime::Delta::Zero();
+
+  if (probing_) {
+    if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA &&
+        probe_->GetAvailableCongestionWindow() == 0) {
+      outer_window = QuicTime::Delta::Infinite();
+    }
+  }
+  return paced_sender_->TimeUntilSend(now, outer_window);
+}
+
+void InterArrivalSender::EstimateDelayBandwidth(QuicTime feedback_receive_time,
+                                                QuicBandwidth sent_bandwidth) {
+  QuicTime::Delta estimated_congestion_delay = QuicTime::Delta::Zero();
+  BandwidthUsage new_bandwidth_usage_state =
+      overuse_detector_->GetState(&estimated_congestion_delay);
+
+  switch (new_bandwidth_usage_state) {
+    case kBandwidthDraining:
+    case kBandwidthUnderUsing:
+      // Hold our current bitrate.
+      break;
+    case kBandwidthOverUsing:
+      if (!state_machine_->IncreasingDelayEvent()) {
+        // Less than one RTT since last IncreasingDelayEvent.
+        return;
+      }
+      EstimateBandwidthAfterDelayEvent(feedback_receive_time,
+                                       estimated_congestion_delay);
+      break;
+    case kBandwidthSteady:
+      // Calculate new pace rate.
+      if (bandwidth_usage_state_ == kBandwidthDraining ||
+          bandwidth_usage_state_ == kBandwidthOverUsing) {
+        EstimateNewBandwidthAfterDraining(feedback_receive_time,
+                                          estimated_congestion_delay);
+      } else {
+        EstimateNewBandwidth(feedback_receive_time, sent_bandwidth);
+      }
+      break;
+  }
+  bandwidth_usage_state_ = new_bandwidth_usage_state;
+}
+
+QuicBandwidth InterArrivalSender::BandwidthEstimate() {
+  return current_bandwidth_;
+}
+
+QuicTime::Delta InterArrivalSender::SmoothedRtt() {
+  if (smoothed_rtt_.IsZero()) {
+    return QuicTime::Delta::FromMilliseconds(kInitialRttMs);
+  }
+  return smoothed_rtt_;
+}
+
+void InterArrivalSender::EstimateNewBandwidth(QuicTime feedback_receive_time,
+                                              QuicBandwidth sent_bandwidth) {
+  QuicBandwidth new_bandwidth = bitrate_ramp_up_->GetNewBitrate(sent_bandwidth);
+  if (current_bandwidth_ == new_bandwidth) {
+    return;
+  }
+  current_bandwidth_ = new_bandwidth;
+  state_machine_->IncreaseBitrateDecision();
+
+  QuicBandwidth channel_estimate = QuicBandwidth::Zero();
+  ChannelEstimateState channel_estimator_state =
+      channel_estimator_->GetChannelEstimate(&channel_estimate);
+
+  if (channel_estimator_state == kChannelEstimateGood) {
+    bitrate_ramp_up_->UpdateChannelEstimate(channel_estimate);
+  }
+  paced_sender_->UpdateBandwidthEstimate(feedback_receive_time,
+                                         current_bandwidth_);
+  DLOG(INFO) << "New bandwidth estimate in steady state:"
+             << current_bandwidth_.ToKBitsPerSecond()
+             << " Kbits/s";
+}
+
+// Did we drain the network buffers in our expected pace?
+void InterArrivalSender::EstimateNewBandwidthAfterDraining(
+    QuicTime feedback_receive_time,
+    QuicTime::Delta estimated_congestion_delay) {
+  if (current_bandwidth_ > back_down_bandwidth_) {
+    // Do nothing, our current bandwidth is higher than our bandwidth at the
+    // previous back down.
+    DLOG(INFO) << "Current bandwidth estimate is higher than before draining";
+    return;
+  }
+  if (estimated_congestion_delay >= back_down_congestion_delay_) {
+    // Do nothing, our estimated delay have increased.
+    DLOG(INFO) << "Current delay estimate is higher than before draining";
+    return;
+  }
+  DCHECK(back_down_time_.IsInitialized());
+  QuicTime::Delta buffer_reduction =
+      back_down_congestion_delay_.Subtract(estimated_congestion_delay);
+  QuicTime::Delta elapsed_time =
+      feedback_receive_time.Subtract(back_down_time_).Subtract(SmoothedRtt());
+
+  QuicBandwidth new_estimate = QuicBandwidth::Zero();
+  if (buffer_reduction >= elapsed_time) {
+    // We have drained more than the elapsed time... go back to our old rate.
+    new_estimate = back_down_bandwidth_;
+  } else {
+    float fraction_of_rate =
+        static_cast<float>(buffer_reduction.ToMicroseconds()) /
+            elapsed_time.ToMicroseconds();  // < 1.0
+
+    QuicBandwidth draining_rate = back_down_bandwidth_.Scale(fraction_of_rate);
+    QuicBandwidth max_estimated_draining_rate =
+        back_down_bandwidth_.Subtract(current_bandwidth_);
+    if (draining_rate > max_estimated_draining_rate) {
+      // We drained faster than our old send rate, go back to our old rate.
+      new_estimate = back_down_bandwidth_;
+    } else {
+      // Use our drain rate and our kMinBitrateReduction to go to our
+      // new estimate.
+      new_estimate = std::max(current_bandwidth_,
+                              current_bandwidth_.Add(draining_rate).Scale(
+                                  1.0f - kMinBitrateReduction));
+      DLOG(INFO) << "Draining calculation; current rate:"
+                 << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s "
+                 << "draining rate:"
+                 << draining_rate.ToKBitsPerSecond() << " Kbits/s "
+                 << "new estimate:"
+                 << new_estimate.ToKBitsPerSecond() << " Kbits/s "
+                 << " buffer reduction:"
+                 << buffer_reduction.ToMicroseconds() << " us "
+                 << " elapsed time:"
+                 << elapsed_time.ToMicroseconds()  << " us ";
+    }
+  }
+  if (new_estimate == current_bandwidth_) {
+    return;
+  }
+
+  QuicBandwidth channel_estimate = QuicBandwidth::Zero();
+  ChannelEstimateState channel_estimator_state =
+      channel_estimator_->GetChannelEstimate(&channel_estimate);
+
+  // TODO(pwestin): we need to analyze channel_estimate too.
+  switch (channel_estimator_state) {
+    case kChannelEstimateUnknown:
+      channel_estimate = current_bandwidth_;
+      break;
+    case kChannelEstimateUncertain:
+      channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
+      break;
+    case kChannelEstimateGood:
+      // Do nothing, estimate is accurate.
+      break;
+  }
+  bitrate_ramp_up_->Reset(new_estimate, back_down_bandwidth_, channel_estimate);
+  state_machine_->IncreaseBitrateDecision();
+  paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_estimate);
+  current_bandwidth_ = new_estimate;
+  DLOG(INFO) << "New bandwidth estimate after draining:"
+             << new_estimate.ToKBitsPerSecond() << " Kbits/s";
+}
+
+void InterArrivalSender::EstimateBandwidthAfterDelayEvent(
+    QuicTime feedback_receive_time,
+    QuicTime::Delta estimated_congestion_delay) {
+  QuicByteCount estimated_byte_buildup =
+      current_bandwidth_.ToBytesPerPeriod(estimated_congestion_delay);
+
+  // To drain all build up buffer within one RTT we need to reduce the
+  // bitrate with the following.
+  // TODO(pwestin): this is a crude first implementation.
+  int64 draining_rate_per_rtt = (estimated_byte_buildup *
+      kNumMicrosPerSecond) / SmoothedRtt().ToMicroseconds();
+
+  float decrease_factor =
+      draining_rate_per_rtt / current_bandwidth_.ToBytesPerSecond();
+
+  decrease_factor = std::max(decrease_factor, kMinBitrateReduction);
+  decrease_factor = std::min(decrease_factor, kMaxBitrateReduction);
+  back_down_congestion_delay_ = estimated_congestion_delay;
+  QuicBandwidth new_target_bitrate =
+      current_bandwidth_.Scale(1.0f - decrease_factor);
+
+  // While in delay sensing mode send at least one packet per RTT.
+  QuicBandwidth min_delay_bitrate =
+      QuicBandwidth::FromBytesAndTimeDelta(kMaxPacketSize, SmoothedRtt());
+  new_target_bitrate = std::max(new_target_bitrate, min_delay_bitrate);
+
+  ResetCurrentBandwidth(feedback_receive_time, new_target_bitrate);
+
+  DLOG(INFO) << "New bandwidth estimate after delay event:"
+      << current_bandwidth_.ToKBitsPerSecond()
+      << " Kbits/s min delay bitrate:"
+      << min_delay_bitrate.ToKBitsPerSecond()
+      << " Kbits/s RTT:"
+      << SmoothedRtt().ToMicroseconds()
+      << " us";
+}
+
+void InterArrivalSender::EstimateBandwidthAfterLossEvent(
+    QuicTime feedback_receive_time) {
+  ResetCurrentBandwidth(feedback_receive_time,
+                        current_bandwidth_.Scale(kPacketLossBitrateReduction));
+  DLOG(INFO) << "New bandwidth estimate after loss event:"
+             << current_bandwidth_.ToKBitsPerSecond()
+             << " Kbits/s";
+}
+
+void InterArrivalSender::ResetCurrentBandwidth(QuicTime feedback_receive_time,
+                                               QuicBandwidth new_rate) {
+  new_rate = std::max(new_rate,
+                      QuicBandwidth::FromKBitsPerSecond(kMinBitrateKbit));
+  QuicBandwidth channel_estimate = QuicBandwidth::Zero();
+  ChannelEstimateState channel_estimator_state =
+      channel_estimator_->GetChannelEstimate(&channel_estimate);
+
+  switch (channel_estimator_state) {
+    case kChannelEstimateUnknown:
+      channel_estimate = current_bandwidth_;
+      break;
+    case kChannelEstimateUncertain:
+      channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
+      break;
+    case kChannelEstimateGood:
+      // Do nothing.
+      break;
+  }
+  back_down_time_ = feedback_receive_time;
+  back_down_bandwidth_ = current_bandwidth_;
+  bitrate_ramp_up_->Reset(new_rate, current_bandwidth_, channel_estimate);
+  if (new_rate != current_bandwidth_) {
+    current_bandwidth_ = new_rate;
+    paced_sender_->UpdateBandwidthEstimate(feedback_receive_time,
+                                           current_bandwidth_);
+    state_machine_->DecreaseBitrateDecision();
+  }
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_sender.h b/net/quic/congestion_control/inter_arrival_sender.h
new file mode 100644
index 0000000..afcafe8
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_sender.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_SENDER_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_SENDER_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_export.h"
+#include "net/quic/congestion_control/channel_estimator.h"
+#include "net/quic/congestion_control/inter_arrival_bitrate_ramp_up.h"
+#include "net/quic/congestion_control/inter_arrival_overuse_detector.h"
+#include "net/quic/congestion_control/inter_arrival_probe.h"
+#include "net/quic/congestion_control/inter_arrival_state_machine.h"
+#include "net/quic/congestion_control/paced_sender.h"
+#include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/quic_bandwidth.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE InterArrivalSender : public SendAlgorithmInterface {
+ public:
+  explicit InterArrivalSender(const QuicClock* clock);
+  virtual ~InterArrivalSender();
+
+  // Start implementation of SendAlgorithmInterface.
+  virtual void OnIncomingQuicCongestionFeedbackFrame(
+      const QuicCongestionFeedbackFrame& feedback,
+      QuicTime feedback_receive_time,
+      QuicBandwidth sent_bandwidth,
+      const SentPacketsMap& sent_packets) OVERRIDE;
+
+  virtual void OnIncomingAck(QuicPacketSequenceNumber acked_sequence_number,
+                             QuicByteCount acked_bytes,
+                             QuicTime::Delta rtt) OVERRIDE;
+
+  virtual void OnIncomingLoss(QuicTime ack_receive_time) OVERRIDE;
+
+  virtual void SentPacket(QuicTime sent_time,
+                          QuicPacketSequenceNumber sequence_number,
+                          QuicByteCount bytes,
+                          Retransmission is_retransmit) OVERRIDE;
+
+  virtual void AbandoningPacket(QuicPacketSequenceNumber sequence_number,
+                                QuicByteCount abandoned_bytes) OVERRIDE;
+
+  virtual QuicTime::Delta TimeUntilSend(
+      QuicTime now,
+      Retransmission is_retransmission,
+      HasRetransmittableData has_retransmittable_data) OVERRIDE;
+
+  virtual QuicBandwidth BandwidthEstimate() OVERRIDE;
+  virtual QuicTime::Delta SmoothedRtt() OVERRIDE;
+  // End implementation of SendAlgorithmInterface.
+
+ private:
+  void EstimateDelayBandwidth(QuicTime feedback_receive_time,
+                              QuicBandwidth sent_bandwidth);
+  void EstimateNewBandwidth(QuicTime feedback_receive_time,
+                            QuicBandwidth sent_bandwidth);
+  void EstimateNewBandwidthAfterDraining(
+      QuicTime feedback_receive_time,
+      QuicTime::Delta estimated_congestion_delay);
+  void EstimateBandwidthAfterLossEvent(QuicTime feedback_receive_time);
+  void EstimateBandwidthAfterDelayEvent(
+      QuicTime feedback_receive_time,
+      QuicTime::Delta estimated_congestion_delay);
+  void ResetCurrentBandwidth(QuicTime feedback_receive_time,
+                             QuicBandwidth new_rate);
+  bool ProbingPhase(QuicTime feedback_receive_time);
+
+  bool probing_;  // Are we currently in the probing phase?
+  QuicBandwidth current_bandwidth_;
+  QuicTime::Delta smoothed_rtt_;
+  scoped_ptr<ChannelEstimator> channel_estimator_;
+  scoped_ptr<InterArrivalBitrateRampUp> bitrate_ramp_up_;
+  scoped_ptr<InterArrivalOveruseDetector> overuse_detector_;
+  scoped_ptr<InterArrivalProbe> probe_;
+  scoped_ptr<InterArrivalStateMachine> state_machine_;
+  scoped_ptr<PacedSender> paced_sender_;
+  int accumulated_number_of_lost_packets_;
+  BandwidthUsage bandwidth_usage_state_;
+  QuicTime back_down_time_;  // Time when we decided to back down.
+  QuicBandwidth back_down_bandwidth_;  // Bandwidth before backing down.
+  QuicTime::Delta back_down_congestion_delay_;  // Delay when backing down.
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalSender);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_SENDER_H_
diff --git a/net/quic/congestion_control/inter_arrival_sender_test.cc b/net/quic/congestion_control/inter_arrival_sender_test.cc
new file mode 100644
index 0000000..28ac9b2
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_sender_test.cc
@@ -0,0 +1,565 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "net/quic/congestion_control/inter_arrival_sender.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class InterArrivalSenderTest : public ::testing::Test {
+ protected:
+  InterArrivalSenderTest()
+     : rtt_(QuicTime::Delta::FromMilliseconds(60)),
+       one_ms_(QuicTime::Delta::FromMilliseconds(1)),
+       one_s_(QuicTime::Delta::FromMilliseconds(1000)),
+       nine_ms_(QuicTime::Delta::FromMilliseconds(9)),
+       send_start_time_(send_clock_.Now()),
+       sender_(&send_clock_),
+       sequence_number_(1),
+       acked_sequence_number_(1),
+       feedback_sequence_number_(1) {
+    send_clock_.AdvanceTime(one_ms_);
+    receive_clock_.AdvanceTime(one_ms_);
+  }
+
+  ~InterArrivalSenderTest() {
+    STLDeleteValues(&sent_packets_);
+  }
+
+  void SendAvailableCongestionWindow() {
+    while (sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                 HAS_RETRANSMITTABLE_DATA).IsZero()) {
+      QuicByteCount bytes_in_packet = kMaxPacketSize;
+      sent_packets_[sequence_number_] =
+          new class SendAlgorithmInterface::SentPacket(
+              bytes_in_packet, send_clock_.Now());
+
+      sender_.SentPacket(send_clock_.Now(), sequence_number_, bytes_in_packet,
+                         NOT_RETRANSMISSION);
+      sequence_number_++;
+    }
+    EXPECT_FALSE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                       HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+
+  void AckNPackets(int n) {
+    for (int i = 0; i < n; ++i) {
+      sender_.OnIncomingAck(acked_sequence_number_++, kMaxPacketSize, rtt_);
+    }
+  }
+
+  void SendDelaySpikeFeedbackMessage(QuicTime::Delta spike_time) {
+    QuicCongestionFeedbackFrame feedback;
+    feedback.type = kInterArrival;
+    feedback.inter_arrival.accumulated_number_of_lost_packets = 0;
+    receive_clock_.AdvanceTime(spike_time);
+    QuicTime receive_time = receive_clock_.ApproximateNow();
+    feedback.inter_arrival.received_packet_times.insert(
+        std::pair<QuicPacketSequenceNumber, QuicTime>(
+            feedback_sequence_number_, receive_time));
+    feedback_sequence_number_++;
+
+    // We need to send feedback for 2 packets since they where sent at the
+    // same time.
+    feedback.inter_arrival.received_packet_times.insert(
+        std::pair<QuicPacketSequenceNumber, QuicTime>(
+            feedback_sequence_number_, receive_time));
+    feedback_sequence_number_++;
+
+    sender_.OnIncomingQuicCongestionFeedbackFrame(
+        feedback, send_clock_.Now(), QuicBandwidth::Zero(), sent_packets_);
+  }
+
+  void SendFeedbackMessageNPackets(int n,
+                                   QuicTime::Delta delta_odd,
+                                   QuicTime::Delta delta_even) {
+    QuicCongestionFeedbackFrame feedback;
+    feedback.type = kInterArrival;
+    feedback.inter_arrival.accumulated_number_of_lost_packets = 0;
+    for (int i = 0; i < n; ++i) {
+      if (feedback_sequence_number_ % 2) {
+        receive_clock_.AdvanceTime(delta_even);
+      } else {
+        receive_clock_.AdvanceTime(delta_odd);
+      }
+      QuicTime receive_time = receive_clock_.ApproximateNow();
+      feedback.inter_arrival.received_packet_times.insert(
+          std::pair<QuicPacketSequenceNumber, QuicTime>(
+              feedback_sequence_number_, receive_time));
+      feedback_sequence_number_++;
+    }
+    sender_.OnIncomingQuicCongestionFeedbackFrame(feedback, send_clock_.Now(),
+        QuicBandwidth::Zero(), sent_packets_);
+  }
+
+  QuicTime::Delta SenderDeltaSinceStart() {
+    return send_clock_.ApproximateNow().Subtract(send_start_time_);
+  }
+
+  const QuicTime::Delta rtt_;
+  const QuicTime::Delta one_ms_;
+  const QuicTime::Delta one_s_;
+  const QuicTime::Delta nine_ms_;
+  MockClock send_clock_;
+  MockClock receive_clock_;
+  const QuicTime send_start_time_;
+  InterArrivalSender sender_;
+  QuicPacketSequenceNumber sequence_number_;
+  QuicPacketSequenceNumber acked_sequence_number_;
+  QuicPacketSequenceNumber feedback_sequence_number_;
+  SendAlgorithmInterface::SentPacketsMap sent_packets_;
+};
+
+TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) {
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // Send 5 bursts.
+  for (int i = 0; i < 4; ++i) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+  SendAvailableCongestionWindow();
+
+  // We have now sent our probe.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsInfinite());
+
+  AckNPackets(10);
+  SendFeedbackMessageNPackets(10, one_ms_, nine_ms_);
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // We should now have our probe rate.
+  QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41);
+  int64 probe_rate = kMaxPacketSize * 9 * kNumMicrosPerSecond /
+      acc_arrival_time.ToMicroseconds();
+  EXPECT_NEAR(0.7f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  DLOG(INFO) << "After probe";
+  // Send 50 bursts, make sure that we move fast in the beginning.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.875f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10);
+
+  // Send 50 bursts, make sure that we slow down towards the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.95f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 1100, 10);
+
+  // Send 50 bursts, make sure that we move very slow close to the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.99f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 1560, 10);
+  DLOG(INFO) << "Near available channel estimate";
+
+  // Send 50 bursts, make sure that we move very slow close to the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(1.00f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 2000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2000, 100);
+  DLOG(INFO) << "At available channel estimate";
+
+  // Send 50 bursts, make sure that we move very slow close to the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(1.01f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 2000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2500, 100);
+
+  // Send 50 bursts, make sure that we accelerate after the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(1.01f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 2000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2900, 100);
+
+  // Send 50 bursts, make sure that we accelerate after the probe rate.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(1.03f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 2000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 3400, 100);
+
+  int64 max_rate = kMaxPacketSize * kNumMicrosPerSecond /
+      one_ms_.ToMicroseconds();
+
+  int64 halfway_rate = probe_rate + (max_rate - probe_rate) / 2;
+
+  // Send until we reach halfway point.
+  for (int i = 0; i < 570; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(halfway_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 5000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 6600, 100);
+  DLOG(INFO) << "Near halfway point";
+
+  // Send until we reach max channel capacity.
+  for (int i = 0; i < 1500; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(max_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 5000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 10000, 200);
+}
+
+TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) {
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // Send 5 bursts.
+  for (int i = 0; i < 4; ++i) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+  SendAvailableCongestionWindow();
+
+  // We have now sent our probe.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsInfinite());
+
+  AckNPackets(10);
+  SendFeedbackMessageNPackets(10, one_ms_, nine_ms_);
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // We should now have our probe rate.
+  QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41);
+  int64 probe_rate = kMaxPacketSize * 9 * kNumMicrosPerSecond /
+      acc_arrival_time.ToMicroseconds();
+  EXPECT_NEAR(0.7f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+
+  // Send 50 bursts, make sure that we move fast in the beginning.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.875f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10);
+
+  SendAvailableCongestionWindow();
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+  AckNPackets(2);
+
+  int64 rate_at_introduced_delay_spike = 0.875f * probe_rate;
+  QuicTime::Delta spike_time = QuicTime::Delta::FromMilliseconds(100);
+  SendDelaySpikeFeedbackMessage(spike_time);
+
+  // Backing as much as we can, currently 90%.
+  EXPECT_NEAR(0.1f * rate_at_introduced_delay_spike,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 610, 10);
+
+  // Run until we are catched up after our introduced delay spike.
+  while (send_clock_.Now() < receive_clock_.Now()) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, one_ms_);
+  }
+  // Expect that we go back to 67% of the rate before the spike.
+  EXPECT_NEAR(0.67f * rate_at_introduced_delay_spike,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 820, 10);
+
+  // Send 100 bursts, make sure that we slow down towards the rate we had
+  // before the spike.
+  for (int i = 0; i < 100; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.97f * rate_at_introduced_delay_spike,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2100, 10);
+}
+
+TEST_F(InterArrivalSenderTest, DelaySpikeFollowedByImmediateDrain) {
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // Send 5 bursts.
+  for (int i = 0; i < 4; ++i) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+  SendAvailableCongestionWindow();
+
+  // We have now sent our probe.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsInfinite());
+
+  AckNPackets(10);
+  SendFeedbackMessageNPackets(10, one_ms_, nine_ms_);
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // We should now have our probe rate.
+  QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41);
+  int64 probe_rate = kMaxPacketSize * 9 * kNumMicrosPerSecond /
+      acc_arrival_time.ToMicroseconds();
+  EXPECT_NEAR(0.7f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+
+  // Send 50 bursts, make sure that we move fast in the beginning.
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    AckNPackets(2);
+    SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_));
+  }
+  EXPECT_NEAR(0.875f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10);
+
+  SendAvailableCongestionWindow();
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+  AckNPackets(2);
+
+  int64 rate_at_introduced_delay_spike = 0.875f * probe_rate;
+  QuicTime::Delta spike_time = QuicTime::Delta::FromMilliseconds(100);
+  SendDelaySpikeFeedbackMessage(spike_time);
+
+  // Backing as much as we can, currently 90%.
+  EXPECT_NEAR(0.1f * rate_at_introduced_delay_spike,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 610, 10);
+
+  // Move send time forward.
+  send_clock_.AdvanceTime(spike_time);
+  // Make sure our clocks are aligned again.
+  receive_clock_.AdvanceTime(send_clock_.Now().Subtract(receive_clock_.Now()));
+
+  SendAvailableCongestionWindow();
+  AckNPackets(2);
+  SendFeedbackMessageNPackets(2, one_ms_, one_ms_);
+  // We should now be back where we introduced the delay spike.
+  EXPECT_NEAR(rate_at_introduced_delay_spike,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+  EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 710, 10);
+}
+
+TEST_F(InterArrivalSenderTest, MinBitrateDueToDelay) {
+  QuicBandwidth expected_min_bitrate = QuicBandwidth::FromKBitsPerSecond(10);
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // Send 5 bursts.
+  for (int i = 0; i < 4; ++i) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+  SendAvailableCongestionWindow();
+
+  AckNPackets(10);
+
+  // One second spread per packet is expected to result in an estimate at
+  // our minimum bitrate.
+  SendFeedbackMessageNPackets(10, one_s_, one_s_);
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+  EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate());
+}
+
+TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) {
+  QuicBandwidth expected_min_bitrate = QuicBandwidth::FromKBitsPerSecond(10);
+  QuicCongestionFeedbackFrame feedback;
+  // At startup make sure we can send.
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  // Send 5 bursts.
+  for (int i = 0; i < 4; ++i) {
+    SendAvailableCongestionWindow();
+    send_clock_.AdvanceTime(sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+  }
+  SendAvailableCongestionWindow();
+
+  AckNPackets(10);
+  SendFeedbackMessageNPackets(10, nine_ms_, nine_ms_);
+  send_clock_.AdvanceTime(sender_.TimeUntilSend(
+      send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                    HAS_RETRANSMITTABLE_DATA).IsZero());
+
+  QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(81);
+  int64 probe_rate = kMaxPacketSize * 9 * kNumMicrosPerSecond /
+      acc_arrival_time.ToMicroseconds();
+  EXPECT_NEAR(0.7f * probe_rate,
+              sender_.BandwidthEstimate().ToBytesPerSecond(), 1000);
+
+  for (int i = 0; i < 15; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    sender_.OnIncomingLoss(send_clock_.Now());
+    sender_.OnIncomingAck(acked_sequence_number_, kMaxPacketSize, rtt_);
+    acked_sequence_number_ += 2;  // Create a loss by not acking both packets.
+    SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_);
+  }
+  // Test that our exponentail back off stop at expected_min_bitrate.
+  EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate());
+
+  for (int i = 0; i < 50; ++i) {
+    SendAvailableCongestionWindow();
+    QuicTime::Delta time_until_send = sender_.TimeUntilSend(
+        send_clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    send_clock_.AdvanceTime(time_until_send);
+    EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION,
+                                      HAS_RETRANSMITTABLE_DATA).IsZero());
+    sender_.OnIncomingLoss(send_clock_.Now());
+    sender_.OnIncomingAck(acked_sequence_number_, kMaxPacketSize, rtt_);
+    acked_sequence_number_ += 2;  // Create a loss by not acking both packets.
+    SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_);
+
+    // Make sure our bitrate is fixed at the expected_min_bitrate.
+    EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate());
+  }
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_state_machine.cc b/net/quic/congestion_control/inter_arrival_state_machine.cc
new file mode 100644
index 0000000..7095e603
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_state_machine.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_state_machine.h"
+
+#include "base/logging.h"
+
+namespace  {
+const int kIncreaseEventsBeforeDowngradingState = 5;
+const int kDecreaseEventsBeforeUpgradingState = 2;
+// Note: Can not be higher than kDecreaseEventsBeforeUpgradingState;
+const int kLossEventsBeforeUpgradingState = 2;
+// Timeout old loss and delay events after this time.
+const int kEventTimeoutMs = 10000;
+// A reasonable arbitrary chosen value for initial round trip time.
+const int kInitialRttMs = 80;
+}
+
+namespace net {
+
+InterArrivalStateMachine::InterArrivalStateMachine(const QuicClock* clock)
+    : clock_(clock),
+      current_state_(kInterArrivalStateStable),
+      smoothed_rtt_(QuicTime::Delta::FromMilliseconds(kInitialRttMs)),
+      decrease_event_count_(0),
+      last_decrease_event_(QuicTime::Zero()),
+      increase_event_count_(0),
+      last_increase_event_(QuicTime::Zero()),
+      loss_event_count_(0),
+      last_loss_event_(QuicTime::Zero()),
+      delay_event_count_(0),
+      last_delay_event_(QuicTime::Zero()) {
+}
+
+InterArrivalState InterArrivalStateMachine::GetInterArrivalState() {
+  return current_state_;
+}
+
+void InterArrivalStateMachine::IncreaseBitrateDecision() {
+  // Multiple increase event without packet loss or delay events will drive
+  // state back to stable.
+  QuicTime current_time = clock_->ApproximateNow();
+  if (current_time.Subtract(last_increase_event_) < smoothed_rtt_) {
+    // Less than one RTT have passed; ignore this event.
+    return;
+  }
+  last_increase_event_ = current_time;
+  increase_event_count_++;
+  decrease_event_count_ = 0;  // Reset previous decrease events.
+
+  if (increase_event_count_ < kIncreaseEventsBeforeDowngradingState) {
+    // Not enough increase events to change state.
+    return;
+  }
+  increase_event_count_ = 0;  // Reset increase events.
+
+  switch (current_state_) {
+    case kInterArrivalStateStable:
+      // Keep this state.
+      break;
+    case kInterArrivalStatePacketLoss:
+      current_state_ = kInterArrivalStateStable;
+      break;
+    case kInterArrivalStateDelay:
+      current_state_ = kInterArrivalStateStable;
+      break;
+    case kInterArrivalStateCompetingFlow:
+      current_state_ = kInterArrivalStateDelay;
+      break;
+    case kInterArrivalStateCompetingTcpFLow:
+      current_state_ = kInterArrivalStateDelay;
+      break;
+  }
+}
+
+void InterArrivalStateMachine::DecreaseBitrateDecision() {
+  DCHECK(kDecreaseEventsBeforeUpgradingState >=
+         kLossEventsBeforeUpgradingState);
+
+  QuicTime current_time = clock_->ApproximateNow();
+  if (current_time.Subtract(last_decrease_event_) < smoothed_rtt_) {
+    // Less than one RTT have passed; ignore this event.
+    return;
+  }
+  last_decrease_event_ = current_time;
+  decrease_event_count_++;
+  increase_event_count_ = 0;  // Reset previous increase events.
+  if (decrease_event_count_ < kDecreaseEventsBeforeUpgradingState) {
+    // Not enough decrease events to change state.
+    return;
+  }
+  decrease_event_count_ = 0;  // Reset decrease events.
+
+  switch (current_state_) {
+    case kInterArrivalStateStable:
+      if (delay_event_count_ == 0 && loss_event_count_ > 0) {
+        // No recent delay events; only packet loss events.
+        current_state_ = kInterArrivalStatePacketLoss;
+      } else {
+        current_state_ = kInterArrivalStateDelay;
+      }
+      break;
+    case kInterArrivalStatePacketLoss:
+      // Keep this state.
+      break;
+    case kInterArrivalStateDelay:
+      if (loss_event_count_ >= kLossEventsBeforeUpgradingState) {
+        // We have packet loss events. Assume fighting with TCP.
+        current_state_ = kInterArrivalStateCompetingTcpFLow;
+      } else {
+        current_state_ = kInterArrivalStateCompetingFlow;
+      }
+      break;
+    case kInterArrivalStateCompetingFlow:
+      if (loss_event_count_ >= kLossEventsBeforeUpgradingState) {
+        // We have packet loss events. Assume fighting with TCP.
+        current_state_ = kInterArrivalStateCompetingTcpFLow;
+      }
+      break;
+    case kInterArrivalStateCompetingTcpFLow:
+      // Keep this state.
+      break;
+  }
+}
+
+void InterArrivalStateMachine::set_rtt(QuicTime::Delta rtt) {
+  smoothed_rtt_ = rtt;
+}
+
+bool InterArrivalStateMachine::PacketLossEvent() {
+  QuicTime current_time = clock_->ApproximateNow();
+  if (current_time.Subtract(last_loss_event_) < smoothed_rtt_) {
+    // Less than one RTT have passed; ignore this event.
+    return false;
+  }
+  last_loss_event_ = current_time;
+  loss_event_count_++;
+  if (current_time.Subtract(last_delay_event_) >
+      QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) {
+    // Delay event have timed out.
+    delay_event_count_ = 0;
+  }
+  return true;
+}
+
+bool InterArrivalStateMachine::IncreasingDelayEvent() {
+  QuicTime current_time = clock_->ApproximateNow();
+  if (current_time.Subtract(last_delay_event_) < smoothed_rtt_) {
+    // Less than one RTT have passed; ignore this event.
+    return false;
+  }
+  last_delay_event_ = current_time;
+  delay_event_count_++;
+  if (current_time.Subtract(last_loss_event_) >
+      QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) {
+    // Loss event have timed out.
+    loss_event_count_ = 0;
+  }
+  return true;
+}
+
+}  // namespace net
diff --git a/net/quic/congestion_control/inter_arrival_state_machine.h b/net/quic/congestion_control/inter_arrival_state_machine.h
new file mode 100644
index 0000000..829aa29
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_state_machine.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// State machine for congestion control. The state is updated by calls from
+// other modules as they detect events, or decide on taking specific actions.
+// Events include things like packet loss, or growing delay, while decisions
+// include decisions to increase or decrease bitrates.
+// This class should be called for every event and decision made by the
+// congestion control, this class will coalesce all calls relative to the
+// smoothed RTT.
+
+#ifndef NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_STATE_MACHINE_H_
+#define NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_STATE_MACHINE_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/quic_clock.h"
+#include "net/quic/quic_time.h"
+
+namespace net {
+
+//  State transition diagram.
+//
+//                     kInterArrivalStatePacketLoss
+//                                   |
+//                       kInterArrivalStateStable
+//                                   |
+//                       kInterArrivalStateDelay
+//                           |              |
+//  kInterArrivalStateCompetingFlow -> kInterArrivalStateCompetingTcpFLow
+
+enum NET_EXPORT_PRIVATE InterArrivalState {
+  // We are on a network with a delay that is too small to be reliably detected,
+  // such as a local ethernet.
+  kInterArrivalStatePacketLoss = 1,
+  // We are on an underutilized network operating with low delay and low loss.
+  kInterArrivalStateStable = 2,
+  // We are on a network where we can detect delay changes and suffer only
+  // low loss. Nothing indicates that we are competing with another flow.
+  kInterArrivalStateDelay = 3,
+  // We are on a network where we can detect delay changes and suffer only
+  // low loss. We have indications that we are compete with another flow.
+  kInterArrivalStateCompetingFlow = 4,
+  // We are on a network where we can detect delay changes, however we suffer
+  // packet loss due to sharing the bottleneck link with another flow, which is
+  // most likely a TCP flow.
+  kInterArrivalStateCompetingTcpFLow = 5,
+};
+
+class NET_EXPORT_PRIVATE InterArrivalStateMachine {
+ public:
+  explicit InterArrivalStateMachine(const QuicClock* clock);
+
+  InterArrivalState GetInterArrivalState();
+
+  // Inter arrival congestion control decided to increase bitrate.
+  void IncreaseBitrateDecision();
+
+  // Inter arrival congestion control decided to decrease bitrate.
+  void DecreaseBitrateDecision();
+
+  // Estimated smoothed round trip time.
+  // This should be called whenever the smoothed RTT estimate is updated.
+  void set_rtt(QuicTime::Delta rtt);
+
+  // This method is called when a packet loss was reported.
+  bool PacketLossEvent();
+
+  // This method is called when we believe that packet transit delay is
+  // increasing, presumably due to a growing queue along the path.
+  bool IncreasingDelayEvent();
+
+ private:
+  const QuicClock* clock_;
+  InterArrivalState current_state_;
+  QuicTime::Delta smoothed_rtt_;
+
+  int decrease_event_count_;
+  QuicTime last_decrease_event_;
+
+  int increase_event_count_;
+  QuicTime last_increase_event_;
+
+  int loss_event_count_;
+  QuicTime last_loss_event_;
+
+  int delay_event_count_;
+  QuicTime last_delay_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterArrivalStateMachine);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_INTER_ARRIVAL_STATE_MACHINE_H_
diff --git a/net/quic/congestion_control/inter_arrival_state_machine_test.cc b/net/quic/congestion_control/inter_arrival_state_machine_test.cc
new file mode 100644
index 0000000..10759c22d
--- /dev/null
+++ b/net/quic/congestion_control/inter_arrival_state_machine_test.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/inter_arrival_state_machine.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class InterArrivalStateMachineTest : public ::testing::Test {
+ protected:
+  InterArrivalStateMachineTest() {
+  }
+
+  void SetUp() {
+    state_machine_.reset(new InterArrivalStateMachine(&clock_));
+  }
+
+  MockClock clock_;
+  scoped_ptr<InterArrivalStateMachine> state_machine_;
+};
+
+TEST_F(InterArrivalStateMachineTest, SimplePacketLoss) {
+  QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+  state_machine_->set_rtt(rtt);
+  state_machine_->IncreaseBitrateDecision();
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateStable,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we switch to state packet loss.
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStatePacketLoss,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we stay in state packet loss.
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStatePacketLoss,
+            state_machine_->GetInterArrivalState());
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStatePacketLoss,
+            state_machine_->GetInterArrivalState());
+}
+
+TEST_F(InterArrivalStateMachineTest, SimpleDelay) {
+  QuicTime::Delta rtt = QuicTime::Delta::FromMilliseconds(100);
+  state_machine_->set_rtt(rtt);
+  state_machine_->IncreaseBitrateDecision();
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->IncreasingDelayEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateStable,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we switch to state delay.
+  clock_.AdvanceTime(rtt);
+  state_machine_->IncreasingDelayEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateDelay,
+            state_machine_->GetInterArrivalState());
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->IncreasingDelayEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateDelay,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we switch to state competing flow(s).
+  clock_.AdvanceTime(rtt);
+  state_machine_->IncreasingDelayEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingFlow,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we stay in state competing flow(s).
+  clock_.AdvanceTime(rtt);
+  state_machine_->IncreasingDelayEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingFlow,
+            state_machine_->GetInterArrivalState());
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingFlow,
+            state_machine_->GetInterArrivalState());
+
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingFlow,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we switch to state competing TCP flow(s).
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingTcpFLow,
+            state_machine_->GetInterArrivalState());
+
+  // Make sure we stay in state competing TCP flow(s).
+  clock_.AdvanceTime(rtt);
+  state_machine_->PacketLossEvent();
+  state_machine_->DecreaseBitrateDecision();
+  EXPECT_EQ(kInterArrivalStateCompetingTcpFLow,
+            state_machine_->GetInterArrivalState());
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/quic_congestion_control_test.cc b/net/quic/congestion_control/quic_congestion_control_test.cc
new file mode 100644
index 0000000..0a581d0
--- /dev/null
+++ b/net/quic/congestion_control/quic_congestion_control_test.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Test of the full congestion control chain.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/quic_congestion_manager.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::max;
+
+namespace net {
+namespace test {
+
+class QuicCongestionManagerPeer : public QuicCongestionManager {
+ public:
+  explicit QuicCongestionManagerPeer(const QuicClock* clock,
+                                     CongestionFeedbackType congestion_type)
+      : QuicCongestionManager(clock, congestion_type) {
+  }
+  using QuicCongestionManager::SentBandwidth;
+  using QuicCongestionManager::BandwidthEstimate;
+};
+
+class QuicCongestionControlTest : public ::testing::Test {
+ protected:
+  QuicCongestionControlTest()
+      : start_(clock_.ApproximateNow()) {
+  }
+
+  void SetUpCongestionType(CongestionFeedbackType congestion_type) {
+    manager_.reset(new QuicCongestionManagerPeer(&clock_, congestion_type));
+  }
+
+  MockClock clock_;
+  QuicTime start_;
+  scoped_ptr<QuicCongestionManagerPeer> manager_;
+};
+
+TEST_F(QuicCongestionControlTest, FixedRateSenderAPI) {
+  SetUpCongestionType(kFixRate);
+  QuicCongestionFeedbackFrame congestion_feedback;
+  congestion_feedback.type = kFixRate;
+  congestion_feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(30);
+  manager_->OnIncomingQuicCongestionFeedbackFrame(congestion_feedback,
+                                                  clock_.Now());
+  EXPECT_TRUE(manager_->SentBandwidth(clock_.Now()).IsZero());
+  EXPECT_TRUE(manager_->TimeUntilSend(
+    clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+  manager_->SentPacket(1, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(40),
+            manager_->TimeUntilSend(
+                clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(35));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_->TimeUntilSend(
+                clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
+  EXPECT_EQ(QuicTime::Delta::Infinite(),
+            manager_->TimeUntilSend(
+                clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA));
+}
+
+TEST_F(QuicCongestionControlTest, FixedRatePacing) {
+  SetUpCongestionType(kFixRate);
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = 0;
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+
+  QuicCongestionFeedbackFrame feedback;
+  feedback.type = kFixRate;
+  feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(100);
+  manager_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
+
+  QuicTime acc_advance_time(QuicTime::Zero());
+  for (QuicPacketSequenceNumber i = 1; i <= 100; ++i) {
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(i, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+    QuicTime::Delta advance_time = manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    clock_.AdvanceTime(advance_time);
+    acc_advance_time = acc_advance_time.Add(advance_time);
+    // Ack the packet we sent.
+    ack.received_info.largest_observed = max(
+        i, ack.received_info.largest_observed);
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+  }
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(1200),
+            acc_advance_time.Subtract(start_));
+}
+
+TEST_F(QuicCongestionControlTest, Pacing) {
+  SetUpCongestionType(kFixRate);
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = 0;
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+
+  QuicCongestionFeedbackFrame feedback;
+  feedback.type = kFixRate;
+  // Test a high bitrate (8Mbit/s) to trigger pacing.
+  feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(1000);
+  manager_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
+
+  QuicTime acc_advance_time(QuicTime::Zero());
+  for (QuicPacketSequenceNumber i = 1; i <= 100;) {
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(i++, clock_.Now(), kMaxPacketSize, NOT_RETRANSMISSION);
+    QuicTime::Delta advance_time = manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    clock_.AdvanceTime(advance_time);
+    acc_advance_time = acc_advance_time.Add(advance_time);
+    // Ack the packets we sent.
+    ack.received_info.largest_observed = max(
+        i - 2, ack.received_info.largest_observed);
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+    ack.received_info.largest_observed = max(
+        i - 1, ack.received_info.largest_observed);
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+  }
+  EXPECT_EQ(QuicTime::Delta::FromMilliseconds(120),
+            acc_advance_time.Subtract(start_));
+}
+
+// TODO(pwestin): add TCP tests.
+
+// TODO(pwestin): add InterArrival tests.
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/quic_congestion_manager.h b/net/quic/congestion_control/quic_congestion_manager.h
index 5840444..1ffe12a5 100644
--- a/net/quic/congestion_control/quic_congestion_manager.h
+++ b/net/quic/congestion_control/quic_congestion_manager.h
@@ -1,3 +1,7 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -26,7 +30,7 @@
 class QuicClock;
 class ReceiveAlgorithmInterface;
 
-class QuicCongestionManager {
+class NET_EXPORT_PRIVATE QuicCongestionManager {
  public:
   QuicCongestionManager(const QuicClock* clock,
                         CongestionFeedbackType congestion_type);
diff --git a/net/quic/congestion_control/quic_congestion_manager_test.cc b/net/quic/congestion_control/quic_congestion_manager_test.cc
new file mode 100644
index 0000000..fb6d2e8
--- /dev/null
+++ b/net/quic/congestion_control/quic_congestion_manager_test.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/congestion_control/quic_congestion_manager.h"
+#include "net/quic/quic_protocol.h"
+#include "net/quic/test_tools/mock_clock.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::StrictMock;
+
+namespace net {
+namespace test {
+
+class QuicCongestionManagerPeer : public QuicCongestionManager {
+ public:
+  explicit QuicCongestionManagerPeer(const QuicClock* clock,
+                                     CongestionFeedbackType congestion_type)
+      : QuicCongestionManager(clock, congestion_type) {
+  }
+  void SetSendAlgorithm(SendAlgorithmInterface* send_algorithm) {
+    this->send_algorithm_.reset(send_algorithm);
+  }
+
+  using QuicCongestionManager::rtt;
+  using QuicCongestionManager::SentBandwidth;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(QuicCongestionManagerPeer);
+};
+
+class QuicCongestionManagerTest : public ::testing::Test {
+ protected:
+  void SetUpCongestionType(CongestionFeedbackType congestion_type) {
+    manager_.reset(new QuicCongestionManagerPeer(&clock_, congestion_type));
+  }
+  MockClock clock_;
+  scoped_ptr<QuicCongestionManagerPeer> manager_;
+};
+
+TEST_F(QuicCongestionManagerTest, Bandwidth) {
+  SetUpCongestionType(kFixRate);
+  QuicAckFrame ack;
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+
+  QuicCongestionFeedbackFrame feedback;
+  feedback.type = kFixRate;
+  feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(100);
+  manager_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
+
+  for (int i = 1; i <= 100; ++i) {
+    QuicTime::Delta advance_time = manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+    clock_.AdvanceTime(advance_time);
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(i, clock_.Now(), 1000, NOT_RETRANSMISSION);
+    // Ack the packet we sent.
+    ack.received_info.largest_observed = i;
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+  }
+  EXPECT_EQ(100, manager_->BandwidthEstimate().ToKBytesPerSecond());
+  EXPECT_NEAR(100,
+              manager_->SentBandwidth(clock_.Now()).ToKBytesPerSecond(), 4);
+}
+
+TEST_F(QuicCongestionManagerTest, BandwidthWith1SecondGap) {
+  SetUpCongestionType(kFixRate);
+  QuicAckFrame ack;
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+
+  QuicCongestionFeedbackFrame feedback;
+  feedback.type = kFixRate;
+  feedback.fix_rate.bitrate = QuicBandwidth::FromKBytesPerSecond(100);
+  manager_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now());
+
+  for (QuicPacketSequenceNumber sequence_number = 1; sequence_number <= 100;
+      ++sequence_number) {
+    clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(
+        sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+    // Ack the packet we sent.
+    ack.received_info.largest_observed = sequence_number;
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+  }
+  EXPECT_EQ(100000, manager_->BandwidthEstimate().ToBytesPerSecond());
+  EXPECT_NEAR(100000,
+              manager_->SentBandwidth(clock_.Now()).ToBytesPerSecond(), 2000);
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(500));
+  EXPECT_NEAR(50000,
+              manager_->SentBandwidth(clock_.Now()).ToBytesPerSecond(), 1000);
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(501));
+  EXPECT_NEAR(100000, manager_->BandwidthEstimate().ToBytesPerSecond(), 2000);
+  EXPECT_TRUE(manager_->SentBandwidth(clock_.Now()).IsZero());
+  for (int i = 1; i <= 150; ++i) {
+    EXPECT_TRUE(manager_->TimeUntilSend(
+        clock_.Now(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA).IsZero());
+    manager_->SentPacket(i + 100, clock_.Now(), 1000, NOT_RETRANSMISSION);
+    clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+    // Ack the packet we sent.
+    ack.received_info.largest_observed = i + 100;
+    manager_->OnIncomingAckFrame(ack, clock_.Now());
+  }
+  EXPECT_EQ(100, manager_->BandwidthEstimate().ToKBytesPerSecond());
+  EXPECT_NEAR(100,
+              manager_->SentBandwidth(clock_.Now()).ToKBytesPerSecond(), 2);
+}
+
+TEST_F(QuicCongestionManagerTest, Rtt) {
+  SetUpCongestionType(kFixRate);
+
+  MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+  manager_->SetSendAlgorithm(send_algorithm);
+
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(15);
+
+  EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm,
+              OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
+
+  manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
+
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = sequence_number;
+  ack.received_info.delta_time_largest_observed =
+      QuicTime::Delta::FromMilliseconds(5);
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+  EXPECT_EQ(manager_->rtt(), expected_rtt);
+}
+
+TEST_F(QuicCongestionManagerTest, RttWithInvalidDelta) {
+  // Expect that the RTT is infinite since the delta_time_largest_observed is
+  // larger than the local time elapsed aka invalid.
+  SetUpCongestionType(kFixRate);
+
+  MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+  manager_->SetSendAlgorithm(send_algorithm);
+
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite();
+
+  EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm,
+              OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
+
+  manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = sequence_number;
+  ack.received_info.delta_time_largest_observed =
+      QuicTime::Delta::FromMilliseconds(11);
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+  EXPECT_EQ(manager_->rtt(), expected_rtt);
+}
+
+TEST_F(QuicCongestionManagerTest, RttInfiniteDelta) {
+  // Expect that the RTT is infinite since the delta_time_largest_observed is
+  // infinite aka invalid.
+  SetUpCongestionType(kFixRate);
+
+  MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+  manager_->SetSendAlgorithm(send_algorithm);
+
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta expected_rtt = QuicTime::Delta::Infinite();
+
+  EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm,
+              OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
+
+  manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+  clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
+
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = sequence_number;
+  ack.received_info.delta_time_largest_observed = QuicTime::Delta::Infinite();
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+  EXPECT_EQ(manager_->rtt(), expected_rtt);
+}
+
+TEST_F(QuicCongestionManagerTest, RttZeroDelta) {
+  // Expect that the RTT is the time between send and receive since the
+  // delta_time_largest_observed is zero.
+  SetUpCongestionType(kFixRate);
+
+  MockSendAlgorithm* send_algorithm = new StrictMock<MockSendAlgorithm>;
+  manager_->SetSendAlgorithm(send_algorithm);
+
+  QuicPacketSequenceNumber sequence_number = 1;
+  QuicTime::Delta expected_rtt = QuicTime::Delta::FromMilliseconds(10);
+
+  EXPECT_CALL(*send_algorithm, SentPacket(_, _, _, _)).Times(1);
+  EXPECT_CALL(*send_algorithm,
+              OnIncomingAck(sequence_number, _, expected_rtt)).Times(1);
+
+  manager_->SentPacket(sequence_number, clock_.Now(), 1000, NOT_RETRANSMISSION);
+  clock_.AdvanceTime(expected_rtt);
+
+  QuicAckFrame ack;
+  ack.received_info.largest_observed = sequence_number;
+  ack.received_info.delta_time_largest_observed = QuicTime::Delta::Zero();
+  manager_->OnIncomingAckFrame(ack, clock_.Now());
+  EXPECT_EQ(manager_->rtt(), expected_rtt);
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/congestion_control/quic_max_sized_map.h b/net/quic/congestion_control/quic_max_sized_map.h
new file mode 100644
index 0000000..a4ed776
--- /dev/null
+++ b/net/quic/congestion_control/quic_max_sized_map.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Simple max sized map. Automatically deletes the oldest element when the
+// max limit is reached.
+// Note: the ConstIterator will NOT be valid after an Insert or RemoveAll.
+#ifndef NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
+#define NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
+
+#include <stdlib.h>
+
+#include <list>
+#include <map>
+
+#include "base/basictypes.h"
+
+namespace net {
+
+template <class Key, class Value>
+class QuicMaxSizedMap {
+ public:
+  typedef typename std::multimap<Key, Value>::const_iterator ConstIterator;
+
+  explicit QuicMaxSizedMap(size_t max_numer_of_items)
+      : max_numer_of_items_(max_numer_of_items) {
+  }
+
+  size_t MaxSize() const {
+    return max_numer_of_items_;
+  }
+
+  size_t Size() const {
+    return table_.size();
+  }
+
+  void Insert(const Key& k, const Value& value) {
+    if (Size() == MaxSize()) {
+      ListIterator list_it = insert_order_.begin();
+      table_.erase(*list_it);
+      insert_order_.pop_front();
+    }
+    TableIterator it = table_.insert(std::pair<Key, Value>(k, value));
+    insert_order_.push_back(it);
+  }
+
+  void RemoveAll() {
+    table_.clear();
+    insert_order_.clear();
+  }
+
+  // STL style const_iterator support.
+  ConstIterator Find(const Key& k) const {
+    return table_.find(k);
+  }
+
+  ConstIterator Begin() const {
+    return ConstIterator(table_.begin());
+  }
+
+  ConstIterator End() const {
+    return ConstIterator(table_.end());
+  }
+
+ private:
+  typedef typename std::multimap<Key, Value>::iterator TableIterator;
+  typedef typename std::list<TableIterator>::iterator ListIterator;
+
+  const size_t max_numer_of_items_;
+  std::multimap<Key, Value> table_;
+  std::list<TableIterator> insert_order_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuicMaxSizedMap);
+};
+
+}  // namespace net
+#endif  // NET_QUIC_CONGESTION_CONTROL_QUIC_MAX_SIZED_MAP_H_
diff --git a/net/quic/congestion_control/quic_max_sized_map_test.cc b/net/quic/congestion_control/quic_max_sized_map_test.cc
new file mode 100644
index 0000000..89c05cc
--- /dev/null
+++ b/net/quic/congestion_control/quic_max_sized_map_test.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "net/quic/congestion_control/quic_max_sized_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+class QuicMaxSizedMapTest : public ::testing::Test {
+};
+
+TEST_F(QuicMaxSizedMapTest, Basic) {
+  QuicMaxSizedMap<int, int> test_map(100);
+  EXPECT_EQ(100u, test_map.MaxSize());
+  EXPECT_EQ(0u, test_map.Size());
+  test_map.Insert(1, 2);
+  test_map.Insert(1, 3);
+  EXPECT_EQ(100u, test_map.MaxSize());
+  EXPECT_EQ(2u, test_map.Size());
+  test_map.RemoveAll();
+  EXPECT_EQ(100u, test_map.MaxSize());
+  EXPECT_EQ(0u, test_map.Size());
+}
+
+TEST_F(QuicMaxSizedMapTest, Find) {
+  QuicMaxSizedMap<int, int> test_map(100);
+  test_map.Insert(1, 2);
+  test_map.Insert(1, 3);
+  test_map.Insert(2, 4);
+  test_map.Insert(3, 5);
+  QuicMaxSizedMap<int, int>::ConstIterator it = test_map.Find(2);
+  EXPECT_TRUE(it != test_map.End());
+  EXPECT_EQ(4, it->second);
+  it = test_map.Find(1);
+  EXPECT_TRUE(it != test_map.End());
+  EXPECT_EQ(2, it->second);
+  ++it;
+  EXPECT_TRUE(it != test_map.End());
+  EXPECT_EQ(3, it->second);
+}
+
+TEST_F(QuicMaxSizedMapTest, Sort) {
+  QuicMaxSizedMap<int, int> test_map(100);
+  test_map.Insert(9, 9);
+  test_map.Insert(8, 8);
+  test_map.Insert(7, 7);
+  test_map.Insert(6, 6);
+  test_map.Insert(2, 2);
+  test_map.Insert(4, 4);
+  test_map.Insert(5, 5);
+  test_map.Insert(3, 3);
+  test_map.Insert(0, 0);
+  test_map.Insert(1, 1);
+  QuicMaxSizedMap<int, int>::ConstIterator it = test_map.Begin();
+  for (int i = 0; i < 10; ++i, ++it) {
+    EXPECT_TRUE(it != test_map.End());
+    EXPECT_EQ(i, it->first);
+    EXPECT_EQ(i, it->second);
+  }
+}
+
+}  // namespace test
+}  // namespace net