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 51f3cd723b..9503ada774 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 @@ -555,6 +555,58 @@ TEST_F(GoogCcNetworkControllerTest, EXPECT_GT(client->target_rate().kbps(), 100); } +DataRate AverageBitrateAfterCrossInducedLoss(std::string name) { + Scenario s(name, false); + NetworkSimulationConfig net_conf; + net_conf.bandwidth = DataRate::kbps(1000); + net_conf.delay = TimeDelta::ms(100); + // Short queue length means that we'll induce loss when sudden TCP traffic + // spikes are induced. This corresponds to ca 200 ms for a packet size of 1000 + // bytes. Such limited buffers are common on for instance wifi routers. + net_conf.packet_queue_length_limit = 25; + + auto send_net = {s.CreateSimulationNode(net_conf)}; + auto ret_net = {s.CreateSimulationNode(net_conf)}; + + auto* client = s.CreateClient("send", CallClientConfig()); + auto* route = s.CreateRoutes( + client, send_net, s.CreateClient("return", CallClientConfig()), ret_net); + auto* video = s.CreateVideoStream(route->forward(), VideoStreamConfig()); + s.RunFor(TimeDelta::seconds(10)); + for (int i = 0; i < 4; ++i) { + // Sends TCP cross traffic inducing loss. + auto* tcp_traffic = + s.net()->StartFakeTcpCrossTraffic(send_net, ret_net, FakeTcpConfig()); + s.RunFor(TimeDelta::seconds(2)); + // Allow the ccongestion controller to recover. + s.net()->StopCrossTraffic(tcp_traffic); + s.RunFor(TimeDelta::seconds(20)); + } + return DataSize::bytes(video->receive() + ->GetStats() + .rtp_stats.packet_counter.TotalBytes()) / + s.TimeSinceStart(); +} + +TEST_F(GoogCcNetworkControllerTest, + NoLossBasedRecoversSlowerAfterCrossInducedLoss) { + // This test acts as a reference for the test below, showing that wihtout the + // trial, we have worse behavior. + DataRate average_bitrate = + AverageBitrateAfterCrossInducedLoss("googcc_unit/no_cross_loss_based"); + RTC_DCHECK_LE(average_bitrate, DataRate::kbps(650)); +} + +TEST_F(GoogCcNetworkControllerTest, + LossBasedRecoversFasterAfterCrossInducedLoss) { + // We recover bitrate better when subject to loss spikes from cross traffic + // when loss based controller is used. + ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); + DataRate average_bitrate = + AverageBitrateAfterCrossInducedLoss("googcc_unit/cross_loss_based"); + RTC_DCHECK_GE(average_bitrate, DataRate::kbps(750)); +} + TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) { ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); Scenario s("googcc_unit/moderate_loss_channel", false); diff --git a/test/scenario/network_node.cc b/test/scenario/network_node.cc index b936fcb60d..d381152934 100644 --- a/test/scenario/network_node.cc +++ b/test/scenario/network_node.cc @@ -29,6 +29,8 @@ SimulatedNetwork::Config CreateSimulationConfig( sim_config.packet_overhead = config.packet_overhead.bytes(); sim_config.codel_active_queue_management = config.codel_active_queue_management; + sim_config.queue_length_packets = + config.packet_queue_length_limit.value_or(0); return sim_config; } } // namespace diff --git a/test/scenario/scenario_config.h b/test/scenario/scenario_config.h index 13d85c3de4..e769e80513 100644 --- a/test/scenario/scenario_config.h +++ b/test/scenario/scenario_config.h @@ -223,6 +223,7 @@ struct NetworkSimulationConfig { TimeDelta delay_std_dev = TimeDelta::Zero(); double loss_rate = 0; bool codel_active_queue_management = false; + absl::optional packet_queue_length_limit; DataSize packet_overhead = DataSize::Zero(); }; } // namespace test