diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc index 41aa3e50dd..aee5bd12bb 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc @@ -799,6 +799,44 @@ TEST(GoogCcScenario, MaintainsLowRateInSafeResetTrial) { EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 50); } +TEST(GoogCcScenario, DoNotResetBweUnlessNetworkAdapterChangeOnRoutChange) { + ScopedFieldTrials trial("WebRTC-Bwe-ResetOnAdapterIdChange/Enabled/"); + Scenario s("googcc_unit/do_not_reset_bwe_unless_adapter_change"); + + const DataRate kLinkCapacity = DataRate::KilobitsPerSec(1000); + const DataRate kStartRate = DataRate::KilobitsPerSec(300); + + auto send_net = s.CreateSimulationNode([&](NetworkSimulationConfig* c) { + c->bandwidth = kLinkCapacity; + c->delay = TimeDelta::Millis(50); + }); + auto* client = s.CreateClient("send", [&](CallClientConfig* c) { + c->transport.rates.start_rate = kStartRate; + }); + client->UpdateNetworkAdapterId(0); + auto* route = s.CreateRoutes( + client, {send_net}, s.CreateClient("return", CallClientConfig()), + {s.CreateSimulationNode(NetworkSimulationConfig())}); + s.CreateVideoStream(route->forward(), VideoStreamConfig()); + // Allow the controller to stabilize. + s.RunFor(TimeDelta::Millis(500)); + EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 300); + s.ChangeRoute(route->forward(), {send_net}); + // Allow new settings to propagate. + s.RunFor(TimeDelta::Millis(50)); + // Under the trial, the target should not drop. + EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 300); + + s.RunFor(TimeDelta::Millis(500)); + // But if adapter id change, BWE should reset and start from the beginning if + // the network route changes. + client->UpdateNetworkAdapterId(1); + s.ChangeRoute(route->forward(), {send_net}); + // Allow new settings to propagate. + s.RunFor(TimeDelta::Millis(50)); + EXPECT_NEAR(client->send_bandwidth().kbps(), kStartRate.kbps(), 30); +} + TEST(GoogCcScenario, CutsHighRateInSafeResetTrial) { const DataRate kLinkCapacity = DataRate::KilobitsPerSec(1000); const DataRate kStartRate = DataRate::KilobitsPerSec(300); @@ -819,6 +857,7 @@ TEST(GoogCcScenario, CutsHighRateInSafeResetTrial) { // Allow the controller to stabilize. s.RunFor(TimeDelta::Millis(500)); EXPECT_NEAR(client->send_bandwidth().kbps(), kLinkCapacity.kbps(), 300); + client->UpdateNetworkAdapterId(1); s.ChangeRoute(route->forward(), {send_net}); // Allow new settings to propagate. s.RunFor(TimeDelta::Millis(50)); @@ -851,6 +890,7 @@ TEST(GoogCcScenario, DetectsHighRateInSafeResetTrial) { // Allow the controller to stabilize. s.RunFor(TimeDelta::Millis(2000)); EXPECT_NEAR(client->send_bandwidth().kbps(), kInitialLinkCapacity.kbps(), 50); + client->UpdateNetworkAdapterId(1); s.ChangeRoute(route->forward(), {new_net}); // Allow new settings to propagate, but not probes to be received. s.RunFor(TimeDelta::Millis(50)); diff --git a/test/scenario/call_client.cc b/test/scenario/call_client.cc index 8845ad6b0f..2ec9fec45a 100644 --- a/test/scenario/call_client.cc +++ b/test/scenario/call_client.cc @@ -364,6 +364,10 @@ void CallClient::SendTask(std::function task) { task_queue_.SendTask(std::move(task)); } +void CallClient::UpdateNetworkAdapterId(int adapter_id) { + transport_->UpdateAdapterId(adapter_id); +} + int16_t CallClient::Bind(EmulatedEndpoint* endpoint) { uint16_t port = endpoint->BindReceiver(0, this).value(); endpoints_.push_back({endpoint, port}); diff --git a/test/scenario/call_client.h b/test/scenario/call_client.h index c5f558138a..37757c603b 100644 --- a/test/scenario/call_client.h +++ b/test/scenario/call_client.h @@ -130,6 +130,9 @@ class CallClient : public EmulatedNetworkReceiverInterface { void SetVideoReceiveRtpHeaderExtensions( rtc::ArrayView extensions); + // Sets the network adapter id used next time the network route changes. + void UpdateNetworkAdapterId(int adapter_id); + void OnPacketReceived(EmulatedIpPacket packet) override; std::unique_ptr GetLogWriter(std::string name); diff --git a/test/scenario/network_node.cc b/test/scenario/network_node.cc index edc573d95f..9c44e08d0f 100644 --- a/test/scenario/network_node.cc +++ b/test/scenario/network_node.cc @@ -14,6 +14,7 @@ #include #include "absl/cleanup/cleanup.h" +#include "api/sequence_checker.h" #include "rtc_base/net_helper.h" #include "rtc_base/numerics/safe_minmax.h" @@ -33,6 +34,12 @@ SimulatedNetwork::Config CreateSimulationConfig( config.packet_queue_length_limit.value_or(0); return sim_config; } + +rtc::RouteEndpoint CreateRouteEndpoint(uint16_t network_id, + uint16_t adapter_id) { + return rtc::RouteEndpoint(rtc::ADAPTER_TYPE_UNKNOWN, adapter_id, network_id, + /* uses_turn = */ false); +} } // namespace SimulationNode::SimulationNode(NetworkSimulationConfig config, @@ -68,7 +75,9 @@ ColumnPrinter SimulationNode::ConfigPrinter() const { NetworkNodeTransport::NetworkNodeTransport(Clock* sender_clock, Call* sender_call) - : sender_clock_(sender_clock), sender_call_(sender_call) {} + : sender_clock_(sender_clock), sender_call_(sender_call) { + sequence_checker_.Detach(); +} NetworkNodeTransport::~NetworkNodeTransport() = default; @@ -103,16 +112,26 @@ bool NetworkNodeTransport::SendRtcp(rtc::ArrayView packet) { return true; } +void NetworkNodeTransport::UpdateAdapterId(int adapter_id) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + adapter_id_ = adapter_id; +} + void NetworkNodeTransport::Connect(EmulatedEndpoint* endpoint, const rtc::SocketAddress& receiver_address, DataSize packet_overhead) { + RTC_DCHECK_RUN_ON(&sequence_checker_); rtc::NetworkRoute route; route.connected = true; // We assume that the address will be unique in the lower bytes. - route.local = rtc::RouteEndpoint::CreateWithNetworkId(static_cast( - receiver_address.ipaddr().v4AddressAsHostOrderInteger())); - route.remote = rtc::RouteEndpoint::CreateWithNetworkId(static_cast( - receiver_address.ipaddr().v4AddressAsHostOrderInteger())); + route.local = CreateRouteEndpoint( + static_cast( + receiver_address.ipaddr().v4AddressAsHostOrderInteger()), + adapter_id_); + route.remote = CreateRouteEndpoint( + static_cast( + receiver_address.ipaddr().v4AddressAsHostOrderInteger()), + adapter_id_); route.packet_overhead = packet_overhead.bytes() + receiver_address.ipaddr().overhead() + cricket::kUdpHeaderSize; diff --git a/test/scenario/network_node.h b/test/scenario/network_node.h index 790a7dc240..57d683c038 100644 --- a/test/scenario/network_node.h +++ b/test/scenario/network_node.h @@ -17,6 +17,7 @@ #include #include "api/call/transport.h" +#include "api/sequence_checker.h" #include "api/units/timestamp.h" #include "call/call.h" #include "rtc_base/copy_on_write_buffer.h" @@ -53,6 +54,8 @@ class NetworkNodeTransport : public Transport { NetworkNodeTransport(Clock* sender_clock, Call* sender_call); ~NetworkNodeTransport() override; + void UpdateAdapterId(int adapter_id); + bool SendRtp(rtc::ArrayView packet, const PacketOptions& options) override; bool SendRtcp(rtc::ArrayView packet) override; @@ -68,6 +71,9 @@ class NetworkNodeTransport : public Transport { } private: + SequenceChecker sequence_checker_; + int adapter_id_ RTC_GUARDED_BY(sequence_checker_) = 0; + Mutex mutex_; Clock* const sender_clock_; Call* const sender_call_;