diff --git a/modules/congestion_controller/bbr/BUILD.gn b/modules/congestion_controller/bbr/BUILD.gn index 68d74fe311..4ddf2c98d9 100644 --- a/modules/congestion_controller/bbr/BUILD.gn +++ b/modules/congestion_controller/bbr/BUILD.gn @@ -28,6 +28,7 @@ rtc_source_set("bbr_controller") { ] deps = [ ":bandwidth_sampler", + ":loss_rate_filter", ":rtt_stats", ":windowed_filter", "../../../api:optional", @@ -82,6 +83,16 @@ rtc_source_set("packet_number_indexed_queue") { ] } +rtc_source_set("loss_rate_filter") { + visibility = [ ":*" ] + sources = [ + "loss_rate_filter.cc", + "loss_rate_filter.h", + ] + deps = [ + "../../../api:optional", + ] +} rtc_source_set("rtt_stats") { visibility = [ ":*" ] sources = [ @@ -107,6 +118,7 @@ if (rtc_include_tests) { "bandwidth_sampler_unittest.cc", "bbr_network_controller_unittest.cc", "data_transfer_tracker_unittest.cc", + "loss_rate_filter_unittest.cc", "packet_number_indexed_queue_unittest.cc", "rtt_stats_unittest.cc", "windowed_filter_unittest.cc", @@ -116,12 +128,14 @@ if (rtc_include_tests) { ":bbr", ":bbr_controller", ":data_transfer_tracker", + ":loss_rate_filter", ":packet_number_indexed_queue", ":rtt_stats", ":windowed_filter", "../../../api/transport:network_control_test", "../../../api/units:data_rate", "../../../api/units:time_delta", + "../../../api/units:timestamp", "../../../test:test_support", ] if (!build_with_chromium && is_clang) { diff --git a/modules/congestion_controller/bbr/bbr_network_controller.cc b/modules/congestion_controller/bbr/bbr_network_controller.cc index 76de566244..03491e7e6a 100644 --- a/modules/congestion_controller/bbr/bbr_network_controller.cc +++ b/modules/congestion_controller/bbr/bbr_network_controller.cc @@ -163,6 +163,7 @@ BbrNetworkController::DebugState::DebugState(const DebugState& state) = default; BbrNetworkController::BbrNetworkController(NetworkControllerConfig config) : rtt_stats_(), random_(10), + loss_rate_(), mode_(STARTUP), sampler_(new BandwidthSampler()), round_trip_count_(0), @@ -398,6 +399,13 @@ NetworkControlUpdate BbrNetworkController::OnTransportPacketsFeedback( DiscardLostPackets(lost_packets); std::vector acked_packets = msg.ReceivedWithSendInfo(); + + int packets_sent = + static_cast(lost_packets.size() + acked_packets.size()); + int packets_lost = static_cast(lost_packets.size()); + loss_rate_.UpdateWithLossStatus(msg.feedback_time.ms(), packets_sent, + packets_lost); + // Input the new data into the BBR model of the connection. if (!acked_packets.empty()) { int64_t last_acked_packet = diff --git a/modules/congestion_controller/bbr/bbr_network_controller.h b/modules/congestion_controller/bbr/bbr_network_controller.h index 0f5a1ed0b2..20cda56dbc 100644 --- a/modules/congestion_controller/bbr/bbr_network_controller.h +++ b/modules/congestion_controller/bbr/bbr_network_controller.h @@ -22,6 +22,7 @@ #include "api/transport/network_control.h" #include "api/transport/network_types.h" #include "modules/congestion_controller/bbr/bandwidth_sampler.h" +#include "modules/congestion_controller/bbr/loss_rate_filter.h" #include "modules/congestion_controller/bbr/rtt_stats.h" #include "modules/congestion_controller/bbr/windowed_filter.h" @@ -215,6 +216,7 @@ class BbrNetworkController : public NetworkControllerInterface { RttStats rtt_stats_; webrtc::Random random_; + LossRateFilter loss_rate_; rtc::Optional constraints_; diff --git a/modules/congestion_controller/bbr/loss_rate_filter.cc b/modules/congestion_controller/bbr/loss_rate_filter.cc new file mode 100644 index 0000000000..302e64a429 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2018 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/bbr/loss_rate_filter.h" + +namespace webrtc { +namespace bbr { +namespace { +// From SendSideBandwidthEstimation. +const int kLimitNumPackets = 20; +// From RTCPSender video report interval. +const int64_t kUpdateIntervalMs = 1000; +} // namespace + +LossRateFilter::LossRateFilter() + : lost_packets_since_last_loss_update_(0), + expected_packets_since_last_loss_update_(0), + loss_rate_estimate_(0.0), + next_loss_update_ms_(0) {} + +void LossRateFilter::UpdateWithLossStatus(int64_t feedback_time, + int packets_sent, + int packets_lost) { + lost_packets_since_last_loss_update_ += packets_lost; + expected_packets_since_last_loss_update_ += packets_sent; + + if (feedback_time >= next_loss_update_ms_ && + expected_packets_since_last_loss_update_ >= kLimitNumPackets) { + int64_t lost = lost_packets_since_last_loss_update_; + int64_t expected = expected_packets_since_last_loss_update_; + loss_rate_estimate_ = static_cast(lost) / expected; + next_loss_update_ms_ = feedback_time + kUpdateIntervalMs; + lost_packets_since_last_loss_update_ = 0; + expected_packets_since_last_loss_update_ = 0; + } +} + +double LossRateFilter::GetLossRate() const { + return loss_rate_estimate_; +} +} // namespace bbr +} // namespace webrtc diff --git a/modules/congestion_controller/bbr/loss_rate_filter.h b/modules/congestion_controller/bbr/loss_rate_filter.h new file mode 100644 index 0000000000..4cc0cbe8b1 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 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_BBR_LOSS_RATE_FILTER_H_ +#define MODULES_CONGESTION_CONTROLLER_BBR_LOSS_RATE_FILTER_H_ + +#include "api/optional.h" + +namespace webrtc { +namespace bbr { + +// Loss rate filter based on the implementation in SendSideBandwidthEstimation +// and the RTCPSender receiver report interval for video. +class LossRateFilter { + public: + LossRateFilter(); + void UpdateWithLossStatus(int64_t feedback_time_ms, + int packets_sent, + int packets_lost); + double GetLossRate() const; + + private: + int lost_packets_since_last_loss_update_; + int expected_packets_since_last_loss_update_; + double loss_rate_estimate_; + int64_t next_loss_update_ms_; +}; + +} // namespace bbr +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_BBR_LOSS_RATE_FILTER_H_ diff --git a/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc b/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc new file mode 100644 index 0000000000..c007da8b52 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc @@ -0,0 +1,71 @@ +/* + * Copyright 2018 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/bbr/loss_rate_filter.h" +#include "api/units/timestamp.h" +#include "test/gtest.h" + +namespace webrtc { +namespace bbr { + +namespace { +const Timestamp kTestStartTime = Timestamp::seconds(100000); +} // namespace + +TEST(LossRateFilterTest, AccumulatesToOne) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int i = 0; i < 10; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 10); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 1.0, 0.01); +} + +TEST(LossRateFilterTest, StaysAtZero) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int i = 0; i < 10; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 0); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 0.0, 0.01); +} + +TEST(LossRateFilterTest, VariesWithInput) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 5; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 10); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 1.0, 0.1); + for (int i = 0; i < 5; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 0); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 0.0, 0.1); + } +} + +TEST(LossRateFilterTest, DetectsChangingRate) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int per_decile = 0; per_decile < 10; per_decile += 1) { + // Update every 200 ms for 2 seconds + for (int i = 0; i < 10; i++) { + current_time += TimeDelta::ms(200); + filter.UpdateWithLossStatus(current_time.ms(), 10, per_decile); + } + EXPECT_NEAR(filter.GetLossRate(), per_decile / 10.0, 0.05); + } +} +} // namespace bbr +} // namespace webrtc