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(), ×tamp_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(), ×tamp_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_