From ea969d287bfe6634c8925f34f9e7997d168dfca1 Mon Sep 17 00:00:00 2001 From: Per Kjellander Date: Fri, 4 Dec 2020 17:31:37 +0100 Subject: [PATCH] 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 Reviewed-by: Christoffer Rodbro Cr-Commit-Position: refs/heads/master@{#32784} --- .../congestion_controller/goog_cc/BUILD.gn | 5 +- .../goog_cc/delay_based_bwe.cc | 104 +++++++++---- .../goog_cc/delay_based_bwe.h | 4 + .../goog_cc/delay_based_bwe_unittest.cc | 57 ++++--- .../delay_based_bwe_unittest_helper.cc | 16 +- .../goog_cc/delay_based_bwe_unittest_helper.h | 6 +- .../goog_cc/inter_arrival_delta.cc | 140 ++++++++++++++++++ .../goog_cc/inter_arrival_delta.h | 90 +++++++++++ 8 files changed, 347 insertions(+), 75 deletions(-) create mode 100644 modules/congestion_controller/goog_cc/inter_arrival_delta.cc create mode 100644 modules/congestion_controller/goog_cc/inter_arrival_delta.h diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index d169d37acf..e3be246347 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -180,6 +180,8 @@ rtc_library("delay_based_bwe") { sources = [ "delay_based_bwe.cc", "delay_based_bwe.h", + "inter_arrival_delta.cc", + "inter_arrival_delta.h", ] deps = [ @@ -187,8 +189,9 @@ rtc_library("delay_based_bwe") { "../../../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 dec36b790f..185b09d8ab 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 @@ DelayBasedBwe::Result::Result() 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 @@ DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, 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 @@ DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config, 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 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback, // 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(kSendTimeGroupLength); + audio_inter_arrival_delta_ = + std::make_unique(kSendTimeGroupLength); + } else { + video_inter_arrival_ = std::make_unique( + kTimestampGroupTicks, kTimestampToMs, true); + audio_inter_arrival_ = std::make_unique( + 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 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback, // 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 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback, active_delay_detector_ = video_delay_detector_.get(); } } - - uint32_t send_time_24bits = - static_cast( - ((static_cast(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( + ((static_cast(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 a87ad4af51..85ce6eaa82 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 @@ class DelayBasedBwe { NetworkStatePredictor* network_state_predictor_; std::unique_ptr video_inter_arrival_; + std::unique_ptr video_inter_arrival_delta_; std::unique_ptr video_delay_detector_; std::unique_ptr audio_inter_arrival_; + std::unique_ptr audio_inter_arrival_delta_; std::unique_ptr audio_delay_detector_; DelayIncreaseDetectorInterface* active_delay_detector_; @@ -124,6 +127,7 @@ class DelayBasedBwe { 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 7860c3d84d..06345c4d9b 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 + #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 @@ const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000); constexpr float kTargetUtilizationFraction = 0.95f; } // namespace -TEST_F(DelayBasedBweTest, ProbeDetection) { +INSTANTIATE_TEST_SUITE_P( + , + DelayBasedBweTest, + ::testing::Values("", "WebRTC-Bwe-NewInterArrivalDelta/Enabled/"), + [](::testing::TestParamInfo 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 @@ TEST_F(DelayBasedBweTest, ProbeDetection) { 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 @@ TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) { 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 @@ TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) { 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 @@ TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) { 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 @@ TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) { 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 @@ TEST_F(DelayBasedBweTest, GetExpectedBwePeriodMs) { 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 @@ TEST_F(DelayBasedBweTest, TestLongTimeoutAndWrap) { 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 @@ TEST_F(DelayBasedBweTest, TestInitialOveruse) { } 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 14bac1e455..946805ab8a 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 @@ int64_t StreamGenerator::GenerateFrame(std::vector* packets, } // 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(field_trial_string)), + : field_trial(std::make_unique(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 608cd6bc70..24e558c2d7 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 @@ class StreamGenerator { }; } // namespace test -class DelayBasedBweTest : public ::testing::Test { +class DelayBasedBweTest : public ::testing::TestWithParam { public: DelayBasedBweTest(); - explicit DelayBasedBweTest(const std::string& field_trial_string); ~DelayBasedBweTest() override; protected: @@ -176,9 +175,8 @@ class DelayBasedBweTest : public ::testing::Test { std::unique_ptr 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 0000000000..791867db67 --- /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 + +#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(current_timestamp_group_.size) - + static_cast(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 0000000000..28dc806249 --- /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_