Reland Addd class InterArrivalDelta to goog_cc

This time the class is added but only used if the field trial "WebRTC-Bwe-NewInterArrivalDelta/Enabled/" is enabled.
Original cl description:

This cl copies modules/remote_bitrate_estimator/inter_arrival.x to inter_arrival.h and interrival_delta.cc in goog_cc
but modified to use webrtc::Timestamp and webrtc::Timedelta in order to avoid having to use 24 bit time repressentation.

patchset 1 is a pure revert of the revert https://webrtc-review.googlesource.com/c/src/+/196343
patchset 2 contains a modification to allow running it behind an experiment.


Bug: webrtc:12269
Change-Id: Ide80e9f5243362799a2cc1f0fcf7e613e707d851
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/196502
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32784}
diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn
index d169d37..e3be246 100644
--- a/modules/congestion_controller/goog_cc/BUILD.gn
+++ b/modules/congestion_controller/goog_cc/BUILD.gn
@@ -180,6 +180,8 @@
   sources = [
     "delay_based_bwe.cc",
     "delay_based_bwe.h",
+    "inter_arrival_delta.cc",
+    "inter_arrival_delta.h",
   ]
 
   deps = [
@@ -187,8 +189,9 @@
     "../../../api:network_state_predictor_api",
     "../../../api/rtc_event_log",
     "../../../api/transport:network_control",
-    "../../../api/transport:network_control",
     "../../../api/transport:webrtc_key_value_config",
+    "../../../api/units:time_delta",
+    "../../../api/units:timestamp",
     "../../../logging:rtc_event_bwe",
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.cc b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
index dec36b7..185b09d 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe.cc
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe.cc
@@ -20,6 +20,7 @@
 #include "absl/strings/match.h"
 #include "api/rtc_event_log/rtc_event.h"
 #include "api/rtc_event_log/rtc_event_log.h"
+#include "api/units/time_delta.h"
 #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
 #include "modules/congestion_controller/goog_cc/trendline_estimator.h"
 #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
@@ -31,6 +32,11 @@
 namespace webrtc {
 namespace {
 constexpr TimeDelta kStreamTimeOut = TimeDelta::Seconds(2);
+
+// Used with field trial "WebRTC-Bwe-NewInterArrivalDelta/Enabled/
+constexpr TimeDelta kSendTimeGroupLength = TimeDelta::Millis(5);
+
+// Used unless field trial "WebRTC-Bwe-NewInterArrivalDelta/Enabled/"
 constexpr int kTimestampGroupLengthMs = 5;
 constexpr int kAbsSendTimeFraction = 18;
 constexpr int kAbsSendTimeInterArrivalUpshift = 8;
@@ -69,7 +75,6 @@
       recovered_from_overuse(false),
       backoff_in_alr(false) {}
 
-
 DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
                              RtcEventLog* event_log,
                              NetworkStatePredictor* network_state_predictor)
@@ -79,10 +84,8 @@
       audio_packets_since_last_video_(0),
       last_video_packet_recv_time_(Timestamp::MinusInfinity()),
       network_state_predictor_(network_state_predictor),
-      video_inter_arrival_(),
       video_delay_detector_(
           new TrendlineEstimator(key_value_config_, network_state_predictor_)),
-      audio_inter_arrival_(),
       audio_delay_detector_(
           new TrendlineEstimator(key_value_config_, network_state_predictor_)),
       active_delay_detector_(video_delay_detector_.get()),
@@ -92,6 +95,9 @@
       prev_bitrate_(DataRate::Zero()),
       has_once_detected_overuse_(false),
       prev_state_(BandwidthUsage::kBwNormal),
+      use_new_inter_arrival_delta_(absl::StartsWith(
+          key_value_config->Lookup("WebRTC-Bwe-NewInterArrivalDelta"),
+          "Enabled")),
       alr_limited_backoff_enabled_(absl::StartsWith(
           key_value_config->Lookup("WebRTC-Bwe-AlrLimitedBackoff"),
           "Enabled")) {
@@ -156,12 +162,19 @@
   // Reset if the stream has timed out.
   if (last_seen_packet_.IsInfinite() ||
       at_time - last_seen_packet_ > kStreamTimeOut) {
-    video_inter_arrival_.reset(
-        new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
+    if (use_new_inter_arrival_delta_) {
+      video_inter_arrival_delta_ =
+          std::make_unique<InterArrivalDelta>(kSendTimeGroupLength);
+      audio_inter_arrival_delta_ =
+          std::make_unique<InterArrivalDelta>(kSendTimeGroupLength);
+    } else {
+      video_inter_arrival_ = std::make_unique<InterArrival>(
+          kTimestampGroupTicks, kTimestampToMs, true);
+      audio_inter_arrival_ = std::make_unique<InterArrival>(
+          kTimestampGroupTicks, kTimestampToMs, true);
+    }
     video_delay_detector_.reset(
         new TrendlineEstimator(key_value_config_, network_state_predictor_));
-    audio_inter_arrival_.reset(
-        new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
     audio_delay_detector_.reset(
         new TrendlineEstimator(key_value_config_, network_state_predictor_));
     active_delay_detector_ = video_delay_detector_.get();
@@ -170,12 +183,10 @@
 
   // As an alternative to ignoring small packets, we can separate audio and
   // video packets for overuse detection.
-  InterArrival* inter_arrival_for_packet = video_inter_arrival_.get();
   DelayIncreaseDetectorInterface* delay_detector_for_packet =
       video_delay_detector_.get();
   if (separate_audio_.enabled) {
     if (packet_feedback.sent_packet.audio) {
-      inter_arrival_for_packet = audio_inter_arrival_.get();
       delay_detector_for_packet = audio_delay_detector_.get();
       audio_packets_since_last_video_++;
       if (audio_packets_since_last_video_ > separate_audio_.packet_threshold &&
@@ -190,30 +201,59 @@
       active_delay_detector_ = video_delay_detector_.get();
     }
   }
-
-  uint32_t send_time_24bits =
-      static_cast<uint32_t>(
-          ((static_cast<uint64_t>(packet_feedback.sent_packet.send_time.ms())
-            << kAbsSendTimeFraction) +
-           500) /
-          1000) &
-      0x00FFFFFF;
-  // Shift up send time to use the full 32 bits that inter_arrival works with,
-  // so wrapping works properly.
-  uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
-
-  uint32_t timestamp_delta = 0;
-  int64_t recv_delta_ms = 0;
-  int size_delta = 0;
   DataSize packet_size = packet_feedback.sent_packet.size;
-  bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas(
-      timestamp, packet_feedback.receive_time.ms(), at_time.ms(),
-      packet_size.bytes(), &timestamp_delta, &recv_delta_ms, &size_delta);
-  double send_delta_ms = (1000.0 * timestamp_delta) / (1 << kInterArrivalShift);
-  delay_detector_for_packet->Update(recv_delta_ms, send_delta_ms,
-                                    packet_feedback.sent_packet.send_time.ms(),
-                                    packet_feedback.receive_time.ms(),
-                                    packet_size.bytes(), calculated_deltas);
+
+  if (use_new_inter_arrival_delta_) {
+    TimeDelta send_delta = TimeDelta::Zero();
+    TimeDelta recv_delta = TimeDelta::Zero();
+    int size_delta = 0;
+
+    InterArrivalDelta* inter_arrival_for_packet =
+        (separate_audio_.enabled && packet_feedback.sent_packet.audio)
+            ? video_inter_arrival_delta_.get()
+            : audio_inter_arrival_delta_.get();
+    bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas(
+        packet_feedback.sent_packet.send_time, packet_feedback.receive_time,
+        at_time, packet_size.bytes(), &send_delta, &recv_delta, &size_delta);
+
+    delay_detector_for_packet->Update(
+        recv_delta.ms(), send_delta.ms(),
+        packet_feedback.sent_packet.send_time.ms(),
+        packet_feedback.receive_time.ms(), packet_size.bytes(),
+        calculated_deltas);
+  } else {
+    InterArrival* inter_arrival_for_packet =
+        (separate_audio_.enabled && packet_feedback.sent_packet.audio)
+            ? video_inter_arrival_.get()
+            : audio_inter_arrival_.get();
+
+    uint32_t send_time_24bits =
+        static_cast<uint32_t>(
+            ((static_cast<uint64_t>(packet_feedback.sent_packet.send_time.ms())
+              << kAbsSendTimeFraction) +
+             500) /
+            1000) &
+        0x00FFFFFF;
+    // Shift up send time to use the full 32 bits that inter_arrival works with,
+    // so wrapping works properly.
+    uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
+
+    uint32_t timestamp_delta = 0;
+    int64_t recv_delta_ms = 0;
+    int size_delta = 0;
+
+    bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas(
+        timestamp, packet_feedback.receive_time.ms(), at_time.ms(),
+        packet_size.bytes(), &timestamp_delta, &recv_delta_ms, &size_delta);
+    double send_delta_ms =
+        (1000.0 * timestamp_delta) / (1 << kInterArrivalShift);
+
+    delay_detector_for_packet->Update(
+        recv_delta_ms, send_delta_ms,
+        packet_feedback.sent_packet.send_time.ms(),
+        packet_feedback.receive_time.ms(), packet_size.bytes(),
+        calculated_deltas);
+  }
 }
 
 DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe.h b/modules/congestion_controller/goog_cc/delay_based_bwe.h
index a87ad4a..85ce6ea 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe.h
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe.h
@@ -22,6 +22,7 @@
 #include "api/transport/network_types.h"
 #include "api/transport/webrtc_key_value_config.h"
 #include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h"
+#include "modules/congestion_controller/goog_cc/inter_arrival_delta.h"
 #include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h"
 #include "modules/remote_bitrate_estimator/aimd_rate_control.h"
 #include "modules/remote_bitrate_estimator/inter_arrival.h"
@@ -113,8 +114,10 @@
 
   NetworkStatePredictor* network_state_predictor_;
   std::unique_ptr<InterArrival> video_inter_arrival_;
+  std::unique_ptr<InterArrivalDelta> video_inter_arrival_delta_;
   std::unique_ptr<DelayIncreaseDetectorInterface> video_delay_detector_;
   std::unique_ptr<InterArrival> audio_inter_arrival_;
+  std::unique_ptr<InterArrivalDelta> audio_inter_arrival_delta_;
   std::unique_ptr<DelayIncreaseDetectorInterface> audio_delay_detector_;
   DelayIncreaseDetectorInterface* active_delay_detector_;
 
@@ -124,6 +127,7 @@
   DataRate prev_bitrate_;
   bool has_once_detected_overuse_;
   BandwidthUsage prev_state_;
+  const bool use_new_inter_arrival_delta_;
   bool alr_limited_backoff_enabled_;
 };
 
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc
index 7860c3d..06345c4 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest.cc
@@ -10,6 +10,8 @@
 
 #include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
 
+#include <string>
+
 #include "api/transport/network_types.h"
 #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
 #include "modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h"
@@ -26,7 +28,15 @@
 constexpr float kTargetUtilizationFraction = 0.95f;
 }  // namespace
 
-TEST_F(DelayBasedBweTest, ProbeDetection) {
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    DelayBasedBweTest,
+    ::testing::Values("", "WebRTC-Bwe-NewInterArrivalDelta/Enabled/"),
+    [](::testing::TestParamInfo<std::string> info) {
+      return info.param == "" ? "Default" : "NewInterArrival";
+    });
+
+TEST_P(DelayBasedBweTest, ProbeDetection) {
   int64_t now_ms = clock_.TimeInMilliseconds();
 
   // First burst sent at 8 * 1000 / 10 = 800 kbps.
@@ -48,7 +58,7 @@
   EXPECT_GT(bitrate_observer_.latest_bitrate(), 1500000u);
 }
 
-TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) {
+TEST_P(DelayBasedBweTest, ProbeDetectionNonPacedPackets) {
   int64_t now_ms = clock_.TimeInMilliseconds();
   // First burst sent at 8 * 1000 / 10 = 800 kbps, but with every other packet
   // not being paced which could mess things up.
@@ -65,7 +75,7 @@
   EXPECT_GT(bitrate_observer_.latest_bitrate(), 800000u);
 }
 
-TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) {
+TEST_P(DelayBasedBweTest, ProbeDetectionFasterArrival) {
   int64_t now_ms = clock_.TimeInMilliseconds();
   // First burst sent at 8 * 1000 / 10 = 800 kbps.
   // Arriving at 8 * 1000 / 5 = 1600 kbps.
@@ -80,7 +90,7 @@
   EXPECT_FALSE(bitrate_observer_.updated());
 }
 
-TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) {
+TEST_P(DelayBasedBweTest, ProbeDetectionSlowerArrival) {
   int64_t now_ms = clock_.TimeInMilliseconds();
   // First burst sent at 8 * 1000 / 5 = 1600 kbps.
   // Arriving at 8 * 1000 / 7 = 1142 kbps.
@@ -99,7 +109,7 @@
               kTargetUtilizationFraction * 1140000u, 10000u);
 }
 
-TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) {
+TEST_P(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) {
   int64_t now_ms = clock_.TimeInMilliseconds();
   // Burst sent at 8 * 1000 / 1 = 8000 kbps.
   // Arriving at 8 * 1000 / 2 = 4000 kbps.
@@ -118,7 +128,7 @@
               kTargetUtilizationFraction * 4000000u, 10000u);
 }
 
-TEST_F(DelayBasedBweTest, GetExpectedBwePeriodMs) {
+TEST_P(DelayBasedBweTest, GetExpectedBwePeriodMs) {
   auto default_interval = bitrate_estimator_->GetExpectedBwePeriod();
   EXPECT_GT(default_interval.ms(), 0);
   CapacityDropTestHelper(1, true, 333, 0);
@@ -127,45 +137,45 @@
   EXPECT_NE(interval.ms(), default_interval.ms());
 }
 
-TEST_F(DelayBasedBweTest, InitialBehavior) {
+TEST_P(DelayBasedBweTest, InitialBehavior) {
   InitialBehaviorTestHelper(730000);
 }
 
-TEST_F(DelayBasedBweTest, RateIncreaseReordering) {
+TEST_P(DelayBasedBweTest, RateIncreaseReordering) {
   RateIncreaseReorderingTestHelper(730000);
 }
-TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) {
+TEST_P(DelayBasedBweTest, RateIncreaseRtpTimestamps) {
   RateIncreaseRtpTimestampsTestHelper(622);
 }
 
-TEST_F(DelayBasedBweTest, CapacityDropOneStream) {
+TEST_P(DelayBasedBweTest, CapacityDropOneStream) {
   CapacityDropTestHelper(1, false, 300, 0);
 }
 
-TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) {
+TEST_P(DelayBasedBweTest, CapacityDropPosOffsetChange) {
   CapacityDropTestHelper(1, false, 867, 30000);
 }
 
-TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) {
+TEST_P(DelayBasedBweTest, CapacityDropNegOffsetChange) {
   CapacityDropTestHelper(1, false, 933, -30000);
 }
 
-TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) {
+TEST_P(DelayBasedBweTest, CapacityDropOneStreamWrap) {
   CapacityDropTestHelper(1, true, 333, 0);
 }
 
-TEST_F(DelayBasedBweTest, TestTimestampGrouping) {
+TEST_P(DelayBasedBweTest, TestTimestampGrouping) {
   TestTimestampGroupingTestHelper();
 }
 
-TEST_F(DelayBasedBweTest, TestShortTimeoutAndWrap) {
+TEST_P(DelayBasedBweTest, TestShortTimeoutAndWrap) {
   // Simulate a client leaving and rejoining the call after 35 seconds. This
   // will make abs send time wrap, so if streams aren't timed out properly
   // the next 30 seconds of packets will be out of order.
   TestWrappingHelper(35);
 }
 
-TEST_F(DelayBasedBweTest, TestLongTimeoutAndWrap) {
+TEST_P(DelayBasedBweTest, TestLongTimeoutAndWrap) {
   // Simulate a client leaving and rejoining the call after some multiple of
   // 64 seconds later. This will cause a zero difference in abs send times due
   // to the wrap, but a big difference in arrival time, if streams aren't
@@ -173,7 +183,7 @@
   TestWrappingHelper(10 * 64);
 }
 
-TEST_F(DelayBasedBweTest, TestInitialOveruse) {
+TEST_P(DelayBasedBweTest, TestInitialOveruse) {
   const DataRate kStartBitrate = DataRate::KilobitsPerSec(300);
   const DataRate kInitialCapacity = DataRate::KilobitsPerSec(200);
   const uint32_t kDummySsrc = 0;
@@ -213,15 +223,16 @@
 }
 
 class DelayBasedBweTestWithBackoffTimeoutExperiment : public DelayBasedBweTest {
- public:
-  DelayBasedBweTestWithBackoffTimeoutExperiment()
-      : DelayBasedBweTest(
-            "WebRTC-BweAimdRateControlConfig/initial_backoff_interval:200ms/") {
-  }
 };
 
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    DelayBasedBweTestWithBackoffTimeoutExperiment,
+    ::testing::Values(
+        "WebRTC-BweAimdRateControlConfig/initial_backoff_interval:200ms/"));
+
 // This test subsumes and improves DelayBasedBweTest.TestInitialOveruse above.
-TEST_F(DelayBasedBweTestWithBackoffTimeoutExperiment, TestInitialOveruse) {
+TEST_P(DelayBasedBweTestWithBackoffTimeoutExperiment, TestInitialOveruse) {
   const DataRate kStartBitrate = DataRate::KilobitsPerSec(300);
   const DataRate kInitialCapacity = DataRate::KilobitsPerSec(200);
   const uint32_t kDummySsrc = 0;
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc
index 14bac1e..946805a 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.cc
@@ -146,21 +146,7 @@
 }  // namespace test
 
 DelayBasedBweTest::DelayBasedBweTest()
-    : field_trial(),
-      clock_(100000000),
-      acknowledged_bitrate_estimator_(
-          AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_)),
-      probe_bitrate_estimator_(new ProbeBitrateEstimator(nullptr)),
-      bitrate_estimator_(
-          new DelayBasedBwe(&field_trial_config_, nullptr, nullptr)),
-      stream_generator_(new test::StreamGenerator(1e6,  // Capacity.
-                                                  clock_.TimeInMicroseconds())),
-      arrival_time_offset_ms_(0),
-      first_update_(true) {}
-
-DelayBasedBweTest::DelayBasedBweTest(const std::string& field_trial_string)
-    : field_trial(
-          std::make_unique<test::ScopedFieldTrials>(field_trial_string)),
+    : field_trial(std::make_unique<test::ScopedFieldTrials>(GetParam())),
       clock_(100000000),
       acknowledged_bitrate_estimator_(
           AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_)),
diff --git a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h
index 608cd6b..24e558c 100644
--- a/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h
+++ b/modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h
@@ -113,10 +113,9 @@
 };
 }  // namespace test
 
-class DelayBasedBweTest : public ::testing::Test {
+class DelayBasedBweTest : public ::testing::TestWithParam<std::string> {
  public:
   DelayBasedBweTest();
-  explicit DelayBasedBweTest(const std::string& field_trial_string);
   ~DelayBasedBweTest() override;
 
  protected:
@@ -176,9 +175,8 @@
   std::unique_ptr<test::StreamGenerator> stream_generator_;
   int64_t arrival_time_offset_ms_;
   bool first_update_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest);
 };
+
 }  // namespace webrtc
 
 #endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_UNITTEST_HELPER_H_
diff --git a/modules/congestion_controller/goog_cc/inter_arrival_delta.cc b/modules/congestion_controller/goog_cc/inter_arrival_delta.cc
new file mode 100644
index 0000000..791867d
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/inter_arrival_delta.cc
@@ -0,0 +1,140 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/congestion_controller/goog_cc/inter_arrival_delta.h"
+
+#include <algorithm>
+
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+static constexpr TimeDelta kBurstDeltaThreshold = TimeDelta::Millis(5);
+static constexpr TimeDelta kMaxBurstDuration = TimeDelta::Millis(100);
+constexpr TimeDelta InterArrivalDelta::kArrivalTimeOffsetThreshold;
+
+InterArrivalDelta::InterArrivalDelta(TimeDelta send_time_group_length)
+    : send_time_group_length_(send_time_group_length),
+      current_timestamp_group_(),
+      prev_timestamp_group_(),
+      num_consecutive_reordered_packets_(0) {}
+
+bool InterArrivalDelta::ComputeDeltas(Timestamp send_time,
+                                      Timestamp arrival_time,
+                                      Timestamp system_time,
+                                      size_t packet_size,
+                                      TimeDelta* send_time_delta,
+                                      TimeDelta* arrival_time_delta,
+                                      int* packet_size_delta) {
+  bool calculated_deltas = false;
+  if (current_timestamp_group_.IsFirstPacket()) {
+    // We don't have enough data to update the filter, so we store it until we
+    // have two frames of data to process.
+    current_timestamp_group_.send_time = send_time;
+    current_timestamp_group_.first_send_time = send_time;
+    current_timestamp_group_.first_arrival = arrival_time;
+  } else if (current_timestamp_group_.first_send_time > send_time) {
+    // Reordered packet.
+    return false;
+  } else if (NewTimestampGroup(arrival_time, send_time)) {
+    // First packet of a later send burst, the previous packets sample is ready.
+    if (prev_timestamp_group_.complete_time.IsFinite()) {
+      *send_time_delta =
+          current_timestamp_group_.send_time - prev_timestamp_group_.send_time;
+      *arrival_time_delta = current_timestamp_group_.complete_time -
+                            prev_timestamp_group_.complete_time;
+
+      TimeDelta system_time_delta = current_timestamp_group_.last_system_time -
+                                    prev_timestamp_group_.last_system_time;
+
+      if (*arrival_time_delta - system_time_delta >=
+          kArrivalTimeOffsetThreshold) {
+        RTC_LOG(LS_WARNING)
+            << "The arrival time clock offset has changed (diff = "
+            << arrival_time_delta->ms() - system_time_delta.ms()
+            << " ms), resetting.";
+        Reset();
+        return false;
+      }
+      if (*arrival_time_delta < TimeDelta::Zero()) {
+        // The group of packets has been reordered since receiving its local
+        // arrival timestamp.
+        ++num_consecutive_reordered_packets_;
+        if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) {
+          RTC_LOG(LS_WARNING)
+              << "Packets between send burst arrived out of order, resetting."
+              << " arrival_time_delta" << arrival_time_delta->ms()
+              << " send time delta " << send_time_delta->ms();
+          Reset();
+        }
+        return false;
+      } else {
+        num_consecutive_reordered_packets_ = 0;
+      }
+      *packet_size_delta = static_cast<int>(current_timestamp_group_.size) -
+                           static_cast<int>(prev_timestamp_group_.size);
+      calculated_deltas = true;
+    }
+    prev_timestamp_group_ = current_timestamp_group_;
+    // The new timestamp is now the current frame.
+    current_timestamp_group_.first_send_time = send_time;
+    current_timestamp_group_.send_time = send_time;
+    current_timestamp_group_.first_arrival = arrival_time;
+    current_timestamp_group_.size = 0;
+  } else {
+    current_timestamp_group_.send_time =
+        std::max(current_timestamp_group_.send_time, send_time);
+  }
+  // Accumulate the frame size.
+  current_timestamp_group_.size += packet_size;
+  current_timestamp_group_.complete_time = arrival_time;
+  current_timestamp_group_.last_system_time = system_time;
+
+  return calculated_deltas;
+}
+
+// Assumes that |timestamp| is not reordered compared to
+// |current_timestamp_group_|.
+bool InterArrivalDelta::NewTimestampGroup(Timestamp arrival_time,
+                                          Timestamp send_time) const {
+  if (current_timestamp_group_.IsFirstPacket()) {
+    return false;
+  } else if (BelongsToBurst(arrival_time, send_time)) {
+    return false;
+  } else {
+    return send_time - current_timestamp_group_.first_send_time >
+           send_time_group_length_;
+  }
+}
+
+bool InterArrivalDelta::BelongsToBurst(Timestamp arrival_time,
+                                       Timestamp send_time) const {
+  RTC_DCHECK(current_timestamp_group_.complete_time.IsFinite());
+  TimeDelta arrival_time_delta =
+      arrival_time - current_timestamp_group_.complete_time;
+  TimeDelta send_time_delta = send_time - current_timestamp_group_.send_time;
+  if (send_time_delta.IsZero())
+    return true;
+  TimeDelta propagation_delta = arrival_time_delta - send_time_delta;
+  if (propagation_delta < TimeDelta::Zero() &&
+      arrival_time_delta <= kBurstDeltaThreshold &&
+      arrival_time - current_timestamp_group_.first_arrival < kMaxBurstDuration)
+    return true;
+  return false;
+}
+
+void InterArrivalDelta::Reset() {
+  num_consecutive_reordered_packets_ = 0;
+  current_timestamp_group_ = SendTimeGroup();
+  prev_timestamp_group_ = SendTimeGroup();
+}
+}  // namespace webrtc
diff --git a/modules/congestion_controller/goog_cc/inter_arrival_delta.h b/modules/congestion_controller/goog_cc/inter_arrival_delta.h
new file mode 100644
index 0000000..28dc806
--- /dev/null
+++ b/modules/congestion_controller/goog_cc/inter_arrival_delta.h
@@ -0,0 +1,90 @@
+/*
+ *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_
+#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_
+
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+
+// Helper class to compute the inter-arrival time delta and the size delta
+// between two send bursts. This code is branched from
+// modules/remote_bitrate_estimator/inter_arrival.
+class InterArrivalDelta {
+ public:
+  // After this many packet groups received out of order InterArrival will
+  // reset, assuming that clocks have made a jump.
+  static constexpr int kReorderedResetThreshold = 3;
+  static constexpr TimeDelta kArrivalTimeOffsetThreshold =
+      TimeDelta::Seconds(3);
+
+  // A send time group is defined as all packets with a send time which are at
+  // most send_time_group_length older than the first timestamp in that
+  // group.
+  explicit InterArrivalDelta(TimeDelta send_time_group_length);
+
+  InterArrivalDelta() = delete;
+  InterArrivalDelta(const InterArrivalDelta&) = delete;
+  InterArrivalDelta& operator=(const InterArrivalDelta&) = delete;
+
+  // This function returns true if a delta was computed, or false if the current
+  // group is still incomplete or if only one group has been completed.
+  // |send_time| is the send time.
+  // |arrival_time| is the time at which the packet arrived.
+  // |packet_size| is the size of the packet.
+  // |timestamp_delta| (output) is the computed send time delta.
+  // |arrival_time_delta_ms| (output) is the computed arrival-time delta.
+  // |packet_size_delta| (output) is the computed size delta.
+  bool ComputeDeltas(Timestamp send_time,
+                     Timestamp arrival_time,
+                     Timestamp system_time,
+                     size_t packet_size,
+                     TimeDelta* send_time_delta,
+                     TimeDelta* arrival_time_delta,
+                     int* packet_size_delta);
+
+ private:
+  struct SendTimeGroup {
+    SendTimeGroup()
+        : size(0),
+          first_send_time(Timestamp::MinusInfinity()),
+          send_time(Timestamp::MinusInfinity()),
+          first_arrival(Timestamp::MinusInfinity()),
+          complete_time(Timestamp::MinusInfinity()),
+          last_system_time(Timestamp::MinusInfinity()) {}
+
+    bool IsFirstPacket() const { return complete_time.IsInfinite(); }
+
+    size_t size;
+    Timestamp first_send_time;
+    Timestamp send_time;
+    Timestamp first_arrival;
+    Timestamp complete_time;
+    Timestamp last_system_time;
+  };
+
+  // Returns true if the last packet was the end of the current batch and the
+  // packet with |send_time| is the first of a new batch.
+  bool NewTimestampGroup(Timestamp arrival_time, Timestamp send_time) const;
+
+  bool BelongsToBurst(Timestamp arrival_time, Timestamp send_time) const;
+
+  void Reset();
+
+  const TimeDelta send_time_group_length_;
+  SendTimeGroup current_timestamp_group_;
+  SendTimeGroup prev_timestamp_group_;
+  int num_consecutive_reordered_packets_;
+};
+}  // namespace webrtc
+
+#endif  // MODULES_CONGESTION_CONTROLLER_GOOG_CC_INTER_ARRIVAL_DELTA_H_