/*
 *  Copyright (c) 2025 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 <map>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <utility>
#include <vector>

#include "absl/flags/flag.h"
#include "api/audio_options.h"
#include "api/rtp_parameters.h"
#include "api/scoped_refptr.h"
#include "api/stats/rtc_stats_report.h"
#include "api/test/network_emulation/dual_pi2_network_queue.h"
#include "api/test/network_emulation/network_config_schedule.pb.h"
#include "api/test/network_emulation/network_emulation_interfaces.h"
#include "api/test/network_emulation/network_queue.h"
#include "api/test/network_emulation/schedulable_network_node_builder.h"
#include "api/test/network_emulation/token_bucket_network_behavior_builder.h"
#include "api/test/network_emulation_manager.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/logging.h"
#include "test/create_frame_generator_capturer.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/network/network_emulation.h"
#include "test/peer_scenario/bwe_integration_tests/stats_utilities.h"
#include "test/peer_scenario/peer_scenario.h"
#include "test/peer_scenario/peer_scenario_client.h"

// Tests for SCReAM.
// Per default, the tests currently does not set expectations on BWE. The
// reason is due to that the tests are not deterministic enough on all
// platforms.
// TODO: bugs.webrtc.org/447037083 - Attempt to make tests stable enough for
// the none deterministic behaviour to not matter.
// To enable BWE expectations, set the flag --enable-scream-bwe-expectations.
// To write RTC eventlogs to file, set the flag --peer_logs=true and
// --peer_logs_root=<path>.

ABSL_FLAG(bool,
          enable_scream_bwe_expectations,
          false,
          "Enable BWE expectations in Scream tests.");

namespace webrtc {
namespace {

using test::GetAvailableSendBitrate;
using test::GetCurrentRoundTripTime;
using test::GetFirstReportAtOrAfter;
using test::GetPacketsLost;
using test::GetPacketsReceived;
using test::GetPacketsReceivedWithCe;
using test::GetPacketsReceivedWithEct1;
using test::GetPacketsSent;
using test::GetPacketsSentWithEct1;
using test::GetStatsAndProcess;
using test::PeerScenario;
using test::PeerScenarioClient;
using ::testing::AllOf;
using ::testing::Each;
using ::testing::Gt;
using ::testing::HasSubstr;
using ::testing::Lt;
using ::testing::TestWithParam;

#if defined(ADDRESS_SANITIZER)
// These tests are too slow to run with ASAN.
#define MaybeTest(t) DISABLED_##t
#else
#define MaybeTest(t) t
#endif

MATCHER_P2(AvailableSendBitrateIsBetween, low, high, "") {
  DataRate available_bwe = GetAvailableSendBitrate(arg);
  if (available_bwe > low && available_bwe < high) {
    return true;
  }
  *result_listener << "the available send bitrate is " << available_bwe.kbps()
                   << "kbps, which is not between " << low.kbps() << "kbps and "
                   << high.kbps() << " kbps";
  if (absl::GetFlag(FLAGS_enable_scream_bwe_expectations)) {
    // TODO: bugs.webrtc.org/447037083 - Attempt to make tests stable enough for
    // the none deterministic behaviour to not matter.
    return false;
  }
  RTC_LOG(LS_ERROR) << "!!! the available send bitrate is "
                    << available_bwe.kbps() << "kbps, which is not between "
                    << low.kbps() << "kbps and " << high.kbps() << " kbps";
  return true;
}

MATCHER_P2(CurrentRoundTripTimeIsBetween, low, high, "") {
  TimeDelta rtt = GetCurrentRoundTripTime(arg);
  if (rtt > low && rtt < high) {
    return true;
  }
  *result_listener << "the current round trip time is " << rtt.ms()
                   << "ms, which is not between " << low.ms() << "ms and "
                   << high.ms() << " ms";

  return false;
}

std::vector<EmulatedNetworkNode*> CreateNetworkPath(
    NetworkEmulationManager::SimulatedNetworkNode::Builder& network_builder,
    bool use_dual_pi) {
  std::unique_ptr<NetworkQueueFactory> queue_factory;
  if (use_dual_pi) {
    queue_factory = std::make_unique<DualPi2NetworkQueueFactory>(
        DualPi2NetworkQueue::Config({.target_delay = TimeDelta::Millis(10)}));
    network_builder.queue_factory(*queue_factory);
  }
  return {network_builder.Build().node};
}

std::vector<EmulatedNetworkNode*> CreateNetworkPath(PeerScenario& s,
                                                    bool use_dual_pi,
                                                    DataRate link_capacity,
                                                    TimeDelta one_way_delay) {
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()
          ->NodeBuilder()
          .capacity(link_capacity)
          .delay_ms(one_way_delay.ms());
  return CreateNetworkPath(network_builder, use_dual_pi);
}

std::vector<EmulatedNetworkNode*> CreateNetworkPathWithPauseBetween3sAnd6s(
    PeerScenario& s) {
  network_behaviour::NetworkConfigSchedule schedule;
  auto initial_config = schedule.add_item();
  initial_config->set_link_capacity_kbps(1000);
  auto updated_capacity = schedule.add_item();
  updated_capacity->set_time_since_first_sent_packet_ms(3000);
  updated_capacity->set_link_capacity_kbps(0);
  updated_capacity = schedule.add_item();
  updated_capacity->set_time_since_first_sent_packet_ms(6000);
  updated_capacity->set_link_capacity_kbps(1000);
  SchedulableNetworkNodeBuilder schedulable_builder(*s.net(),
                                                    std::move(schedule));
  return {schedulable_builder.Build()};
}

std::vector<EmulatedNetworkNode*> CreateNetworkPathWithRepeatedPause(
    PeerScenario& s,
    DataRate link_capacity,
    TimeDelta pause_duration,
    TimeDelta repeat_pause_interval) {
  network_behaviour::NetworkConfigSchedule schedule;
  auto initial_config = schedule.add_item();
  initial_config->set_link_capacity_kbps(link_capacity.kbps());
  initial_config->set_queue_delay_ms(10);
  auto updated_capacity = schedule.add_item();
  updated_capacity->set_time_since_first_sent_packet_ms(
      repeat_pause_interval.ms());
  updated_capacity->set_link_capacity_kbps(0);
  schedule.set_repeat_schedule_after_last_ms(pause_duration.ms());
  SchedulableNetworkNodeBuilder schedulable_builder(*s.net(),
                                                    std::move(schedule));
  return {schedulable_builder.Build()};
}

std::vector<EmulatedNetworkNode*> CreateNetworkPath1MbitDelayIncreaseAfter3S(
    PeerScenario& s) {
  network_behaviour::NetworkConfigSchedule schedule;
  auto initial_config = schedule.add_item();
  initial_config->set_link_capacity_kbps(1000);
  initial_config->set_queue_delay_ms(10);
  auto updated_latency = schedule.add_item();
  updated_latency->set_time_since_first_sent_packet_ms(3000);
  updated_latency->set_queue_delay_ms(80);

  SchedulableNetworkNodeBuilder schedulable_builder(*s.net(),
                                                    std::move(schedule));
  return {schedulable_builder.Build()};
}

std::vector<EmulatedNetworkNode*> CreateNetworkPathWithChangedCapacityAfter5s(
    PeerScenario& s,
    DataRate link_capacity_1,
    DataRate link_capacity_2) {
  network_behaviour::NetworkConfigSchedule schedule;
  auto initial_config = schedule.add_item();
  initial_config->set_link_capacity_kbps(link_capacity_1.kbps());
  initial_config->set_queue_delay_ms(15);
  auto updated_capacity = schedule.add_item();
  updated_capacity->set_time_since_first_sent_packet_ms(5000);
  updated_capacity->set_link_capacity_kbps(link_capacity_2.kbps());

  SchedulableNetworkNodeBuilder schedulable_builder(*s.net(),
                                                    std::move(schedule));
  return {schedulable_builder.Build()};
}

struct SendMediaTestResult {
  // Stats gathered every second during the call.
  std::vector<scoped_refptr<const RTCStatsReport>> caller_stats;
  std::vector<scoped_refptr<const RTCStatsReport>> callee_stats;

  std::span<const scoped_refptr<const RTCStatsReport>> caller() const {
    return std::span<const scoped_refptr<const RTCStatsReport>>(caller_stats);
  }

  std::span<const scoped_refptr<const RTCStatsReport>> callee() const {
    return std::span<const scoped_refptr<const RTCStatsReport>>(callee_stats);
  }
};

struct SendMediaTestParams {
  std::vector<EmulatedNetworkNode*> caller_to_callee_path;
  std::vector<EmulatedNetworkNode*> callee_to_caller_path;
  std::map</*trial*/ std::string, /*group*/ std::string> field_trials = {
      {"WebRTC-RFC8888CongestionControlFeedback", "Enabled,offer:true"},
      {"WebRTC-Bwe-ScreamV2", "Enabled"}};

  // Audio is negotiated and sent.
  bool send_audio = true;
  // Video capturer is producing frames.
  bool video_capture_enabled = true;

  // Configure and set the max video encoding bitrate. If not set, the max
  // default per codec and resolution is used.
  std::optional<DataRate> max_video_bitrate;

  PeerScenarioClient::VideoSendTrackConfig caller_video_conf = {
      .generator = {.squares_video =
                        test::FrameGeneratorCapturerConfig::SquaresVideo{
                            .framerate = 30,
                            .width = 1280,
                            .height = 720,
                        }}};

  TimeDelta test_duration = TimeDelta::Seconds(10);
  TimeDelta stats_interval = TimeDelta::Seconds(1);
};

// Sends audio and video from a caller to a callee with symmetric
// uplink/downlink network.
SendMediaTestResult SendMediaInOneDirection(SendMediaTestParams params,
                                            PeerScenario& s) {
  PeerScenarioClient::Config config;
  for (auto [trial, group] : params.field_trials) {
    config.field_trials.Set(trial, group);
  }
  PeerScenarioClient* caller = s.CreateClient(config);
  PeerScenarioClient* callee = s.CreateClient(config);

  if (params.send_audio) {
    caller->CreateAudio("AUDIO_1", {});
  }
  test::PeerScenarioClient::VideoSendTrack video_track =
      caller->CreateVideo("VIDEO_1", params.caller_video_conf);
  if (!params.video_capture_enabled) {
    // Stop the capturer.
    video_track.source->Stop();
  }
  if (params.max_video_bitrate.has_value()) {
    RtpParameters rtp_parameters = video_track.sender->GetParameters();
    rtp_parameters.encodings[0].max_bitrate_bps =
        params.max_video_bitrate->bps();
    video_track.sender->SetParameters(rtp_parameters);
  }

  s.SimpleConnection(caller, callee, std::move(params.caller_to_callee_path),
                     std::move(params.callee_to_caller_path));
  SendMediaTestResult result;

  Timestamp end_time = s.net()->Now() + params.test_duration;
  while (s.net()->Now() < end_time) {
    s.ProcessMessages(params.stats_interval);
    result.caller_stats.push_back(GetStatsAndProcess(s, caller));
    result.callee_stats.push_back(GetStatsAndProcess(s, callee));
  }
  return result;
}

// This test is not using Scream - it is only here as a reference.
TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt100msNoEcnWithGoogCC)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{
      .field_trials = {
          {"WebRTC-RFC8888CongestionControlFeedback", "Enabled,offer:true"}}};
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(450),
                                            DataRate::KilobitsPerSec(700)));
}

TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt100msNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(250),
                                              DataRate::KilobitsPerSec(700))));
}

TEST(ScreamTest,
     MaybeTest(LinkCapacityIncreaseFrom500KbitTo5MbpsAfter5sNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.caller_to_callee_path = CreateNetworkPathWithChangedCapacityAfter5s(
      s, DataRate::KilobitsPerSec(500), DataRate::KilobitsPerSec(5000));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(3000), TimeDelta::Millis(25));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // Stats 2-5s
  EXPECT_THAT(
      result.caller().subspan(1, 3),
      Each(AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(200),
                                         DataRate::KilobitsPerSec(600))));
  // Stats after 9s
  EXPECT_THAT(result.caller().subspan(9), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1200),
                                              DataRate::KilobitsPerSec(5000))));
}

TEST(
    ScreamTest,
    MaybeTest(
        LinkCapacityIncreaseFrom80KbitTo5MbpsAfter5sVideoCaptureStoppedNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.video_capture_enabled = false;
  params.max_video_bitrate = DataRate::KilobitsPerSec(3000);
  params.caller_to_callee_path = CreateNetworkPathWithChangedCapacityAfter5s(
      s, DataRate::KilobitsPerSec(80), DataRate::KilobitsPerSec(5000));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(3000), TimeDelta::Millis(25));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // Stats 2-5s
  EXPECT_THAT(
      result.caller().subspan(1, 3),
      Each(AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(10),
                                         DataRate::KilobitsPerSec(140))));
  EXPECT_THAT(result.caller()[3],
              CurrentRoundTripTimeIsBetween(TimeDelta::Millis(40),
                                            TimeDelta::Millis(200)));
  // Stats after 9s
  // TODO: bugs.webrtc.org/447037083 - Figure out why setting max_video_bitrate
  // does not force available send bitrate to increase despite that the camera
  // is disabled.
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(100),
                                            DataRate::KilobitsPerSec(6500)));
}

TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt20msNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(10));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(10));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(200),
                                              DataRate::KilobitsPerSec(900))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt100msEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // Allow rampup to take 3s.
  EXPECT_THAT(result.caller().subspan(3), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(350),
                                              DataRate::KilobitsPerSec(660))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt100msEcnAfterCe)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.field_trials = {
      {"WebRTC-RFC8888CongestionControlFeedback", "Enabled,offer:true"},
      {"WebRTC-Bwe-ScreamV2", "mode:only_after_ce"}};

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // All packets are sent as ECT1.
  EXPECT_EQ(GetPacketsSent(result.caller_stats.back()),
            GetPacketsSentWithEct1(result.caller_stats.back()));
  // Not all packets has been received yet.
  EXPECT_GE(GetPacketsSentWithEct1(result.caller_stats.back()),
            0.9 * (GetPacketsReceived(result.callee_stats.back())));
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(350),
                                            DataRate::KilobitsPerSec(660)));
}

// Test that we can switch from Goog CC sending ECT1 to send ECT 0 and adapt.
TEST(ScreamTest, MaybeTest(LinkCapacity600KbpsRtt100msEcnWithGoogCcAfterCe)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));
  params.field_trials = {
      {"WebRTC-RFC8888CongestionControlFeedback", "Enabled,offer:true"},
      {"WebRTC-Bwe-ScreamV2", "mode:goog_cc_with_ect1"}};

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(350),
                                            DataRate::KilobitsPerSec(660)));

  // Not all packets are sent as ECT1 since packets are supposed to be sent as
  // not ECT if CE is detected.
  EXPECT_GT(GetPacketsSent(result.caller_stats.back()),
            GetPacketsSentWithEct1(result.caller_stats.back()));
  EXPECT_GE(GetPacketsReceivedWithCe(result.callee_stats.back()), 1);
}

TEST(ScreamTest, MaybeTest(LinkCapacity1000KbpsRtt100msEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(1000), TimeDelta::Millis(50));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(1000), TimeDelta::Millis(50));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // Ignore result first 2s since ramp up is rather slow at higher RTT.
  ASSERT_GT(result.caller().subspan(2).size(), 0u);
  EXPECT_THAT(result.caller().subspan(2), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(600),
                                              DataRate::KilobitsPerSec(1000))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity1500KbpsRtt30msNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(1500), TimeDelta::Millis(15));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(1500), TimeDelta::Millis(15));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(800),
                                              DataRate::KilobitsPerSec(2200))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity2MbpsRtt50msNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1300),
                                              DataRate::KilobitsPerSec(2300))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity2MbpsRtt50msEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ true,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1300),
                                              DataRate::KilobitsPerSec(2300))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity2MbpsRtt50msNoEcnWithGoogCC)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.field_trials = {
      {"WebRTC-RFC8888CongestionControlFeedback", "Enabled,offer:true"},
  };

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(1000),
                                            DataRate::KilobitsPerSec(2600)));
}

TEST(ScreamTest, MaybeTest(LinkCapacity4MbpsRtt50ms10MsDelayStdDev)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder(
      s.net());
  network_builder.delay_ms(25);
  network_builder.delay_standard_deviation_ms(10);
  network_builder.capacity_Mbps(4);
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(700),
                                              DataRate::KilobitsPerSec(4100))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity2MbpsRtt50msNoEcnWithTwcc)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.field_trials = {
      {"WebRTC-RFC8888CongestionControlFeedback", "Disabled"},
      {"WebRTC-Bwe-ScreamV2", "mode:always"},
  };

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // BWE rampup is quite slow since feedback is only sent every 90ms
  // approximately.
  EXPECT_THAT(result.caller().subspan(5), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(700),
                                              DataRate::KilobitsPerSec(2600))));
}

TEST(ScreamTest, MaybeTest(CallerPauseSendingVideoIfFeedbackNotReceived)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.callee_to_caller_path = CreateNetworkPathWithPauseBetween3sAnd6s(s);
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(600), TimeDelta::Millis(50));

  Timestamp start_time = s.net()->Now();
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  std::optional<scoped_refptr<const RTCStatsReport>> report_after_4s =
      GetFirstReportAtOrAfter(start_time + TimeDelta::Seconds(4),
                              result.caller_stats);
  std::optional<scoped_refptr<const RTCStatsReport>> report_after_5s =
      GetFirstReportAtOrAfter(start_time + TimeDelta::Seconds(5),
                              result.caller_stats);
  ASSERT_TRUE(report_after_4s.has_value());
  ASSERT_TRUE(report_after_5s.has_value());
  ASSERT_GT(GetPacketsSent(report_after_4s.value(), "video"), 0);
  // Audio not paused.
  EXPECT_LT(GetPacketsSent(report_after_4s.value()),
            GetPacketsSent(report_after_5s.value()));
  // video paused.
  EXPECT_EQ(GetPacketsSent(report_after_4s.value(), "video"),
            GetPacketsSent(report_after_5s.value(), "video"));
  // video resumed.
  EXPECT_LT(GetPacketsSent(report_after_4s.value(), "video"),
            GetPacketsSent(result.caller_stats.back(), "video"));

  // Target rate is within reason at the end of the call.
  // TODO: bugs.webrtc.org/447037083 - There is no pushback between pacer queue
  // encoder. If pacer queue is paused for too long, the pacer will send
  // packets too fast.
  // EXPECT_GT(GetAvailableSendBitrate(result.caller_stats.back()),
  //          DataRate::KilobitsPerSec(400));
  EXPECT_LT(GetAvailableSendBitrate(result.caller_stats.back()),
            DataRate::KilobitsPerSec(800));
}

TEST(ScreamTest,
     MaybeTest(CallerResetQueueDelayEstimateAfterIncreasedFixedDelay)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(35)};
  params.caller_to_callee_path = CreateNetworkPath1MbitDelayIncreaseAfter3S(s);
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(10));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // After the increased delay, BWE should drop
  EXPECT_LT(GetAvailableSendBitrate(result.caller_stats[5]),
            DataRate::KilobitsPerSec(400));

  // But have recovered by the end of the test.
  EXPECT_THAT(result.caller_stats.back(),
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(600),
                                            DataRate::KilobitsPerSec(1200)));
}

TEST(ScreamTest, MaybeTest(ScreencastSlideChange2Mbit50msRttNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_to_callee_path = params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_video_conf = {
      .generator = {.image_slides =
                        test::FrameGeneratorCapturerConfig::ImageSlides{
                            .change_interval = TimeDelta::Seconds(5)}}};

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // Ignore estimate during rampup.
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1200),
                                              DataRate::KilobitsPerSec(2500))));
}

TEST(ScreamTest, MaybeTest(ScreencastSlideChange500Kbit30msRttNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(500), TimeDelta::Millis(15));
  params.caller_to_callee_path = params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(500), TimeDelta::Millis(15));
  params.caller_video_conf = {
      .generator = {.image_slides =
                        test::FrameGeneratorCapturerConfig::ImageSlides{
                            .change_interval = TimeDelta::Seconds(3)}}};

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // Ignore estimate during rampup.
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(200),
                                              DataRate::KilobitsPerSec(700))));
}

TEST(ScreamTest, MaybeTest(ScreencastSlideChangeRepeatedDelaySpikes)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  params.caller_to_callee_path = CreateNetworkPathWithRepeatedPause(
      s, DataRate::KilobitsPerSec(4000), TimeDelta::Millis(500),
      TimeDelta::Seconds(4));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(2000), TimeDelta::Millis(25));
  params.caller_video_conf = {
      .generator = {.image_slides =
                        test::FrameGeneratorCapturerConfig::ImageSlides{
                            .change_interval = TimeDelta::Seconds(5)}}};
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  EXPECT_THAT(result.caller(), Each(AvailableSendBitrateIsBetween(
                                   DataRate::KilobitsPerSec(500),
                                   DataRate::KilobitsPerSec(4300))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity5MbitRepeatedDelaySpikesNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  params.caller_to_callee_path = CreateNetworkPathWithRepeatedPause(
      s, DataRate::KilobitsPerSec(5000), TimeDelta::Millis(100),
      TimeDelta::Millis(200));
  params.callee_to_caller_path = CreateNetworkPathWithRepeatedPause(
      s, DataRate::KilobitsPerSec(5000), TimeDelta::Millis(100),
      TimeDelta::Millis(200));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1200),
                                              DataRate::KilobitsPerSec(5000))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity2MbitRepeatedDelaySpikesNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  params.caller_to_callee_path = CreateNetworkPathWithRepeatedPause(
      s, DataRate::KilobitsPerSec(2000), TimeDelta::Millis(100),
      TimeDelta::Millis(200));
  params.callee_to_caller_path = CreateNetworkPathWithRepeatedPause(
      s, DataRate::KilobitsPerSec(2000), TimeDelta::Millis(100),
      TimeDelta::Millis(200));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(700),
                                              DataRate::KilobitsPerSec(2000))));
}

TEST(ScreamTest, MaybeTest(RampupFastOnLinkCapacity50Mbit20MsRttNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(1),
                             .stats_interval = TimeDelta::Millis(100)};
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(50000), TimeDelta::Millis(10));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(50000), TimeDelta::Millis(10));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  // After 400ms.
  EXPECT_THAT(result.caller_stats[3],
              AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(1200),
                                            DataRate::KilobitsPerSec(2500)));
}

TEST(ScreamTest, MaybeTest(LinkCapacity100Kbit50msRttNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(100), TimeDelta::Millis(25));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(100), TimeDelta::Millis(25));
  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(result.caller(), Each(AvailableSendBitrateIsBetween(
                                   DataRate::KilobitsPerSec(10),
                                   DataRate::KilobitsPerSec(150))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity1MbitRtt50msWithShortQueuesNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(1).delay_ms(25);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path = CreateNetworkPath(
      network_builder.packet_queue_length(3), /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(
      GetPacketsLost(result.callee_stats.back()) /
          static_cast<double>(GetPacketsSent(result.caller_stats.back())),
      Lt(0.07));

  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(200),
                                              DataRate::KilobitsPerSec(1100))));
}

TEST(ScreamTest,
     MaybeTest(LinkCapacity1MbitRtt50msWith10PercentRandomLossNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(1).delay_ms(25);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder.loss(0.1), /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  ASSERT_GE(GetPacketsLost(result.callee_stats.back()),
            0.05 * GetPacketsSent(result.caller_stats.back()));

  // Ignore estimate during rampup.
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(100),
                                              DataRate::KilobitsPerSec(1100))));
}

TEST(ScreamTest, MaybeTest(LowBweOnLinkWith5PercentUniformLoss)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(3).delay_ms(40);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder.loss(0.05), /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  ASSERT_GE(GetPacketsLost(result.callee_stats.back()),
            0.02 * GetPacketsSent(result.caller_stats.back()));

  // Ignore estimate during rampup.
  ASSERT_GT(result.caller().subspan(2).size(), 0u);
  EXPECT_THAT(result.caller().subspan(2), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(100),
                                              DataRate::KilobitsPerSec(1100))));
}

TEST(ScreamTest, MaybeTest(Ignores1PercentUniformLossOnLinkWith80msRtt)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(3).delay_ms(40);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder.loss(0.01), /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  ASSERT_GE(GetPacketsLost(result.callee_stats.back()),
            0.005 * GetPacketsSent(result.caller_stats.back()));

  // Ignore estimate during rampup.
  ASSERT_GT(result.caller().subspan(2).size(), 0u);
  EXPECT_THAT(result.caller().subspan(2), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1000),
                                              DataRate::KilobitsPerSec(3000))));
}

TEST(ScreamTest, MaybeTest(IgnoresPacketReorderingOnLinkWith80msRtt)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(3).delay_ms(40);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.caller_to_callee_path = CreateNetworkPath(
      network_builder.allow_reordering().delay_standard_deviation_ms(5),
      /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // Ignore estimate during rampup.
  ASSERT_GT(result.caller().subspan(2).size(), 0u);
  EXPECT_THAT(result.caller().subspan(2), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(1000),
                                              DataRate::KilobitsPerSec(3000))));
}

TEST(ScreamTest, MaybeTest(ReturnLinkWithBurstLoss)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params{.test_duration = TimeDelta::Seconds(20)};
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(1).delay_ms(25);
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);

  params.callee_to_caller_path =
      CreateNetworkPath(network_builder.loss(0.2).avg_burst_loss_length(3),
                        /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // Audio packets are sent even if congestion window is full and ensures
  // feedback is eventually received even if feedback packets are lost.
  EXPECT_GT(GetPacketsSent(result.caller_stats.back()),
            GetPacketsSent(result.caller_stats[5]));

  ASSERT_GT(result.caller().subspan(1).size(), 0u);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(300),
                                              DataRate::KilobitsPerSec(1300))));
}

TEST(ScreamTest, MaybeTest(SendVideoOnlyReturnLinkWithBurstLoss)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.send_audio = false;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(1).delay_ms(25);
  params.send_audio = false;
  params.caller_to_callee_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder.loss(0.2).avg_burst_loss_length(3),
                        /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);

  // Keep alive packets are used for ensuring feedback is eventually received
  // even if feedback packets are lost. Due to that the pacer pace out all
  // packets to fast if queued too long, BWE drop to a very low value.
  EXPECT_GT(GetPacketsSent(result.caller_stats.back()),
            GetPacketsSent(result.caller_stats[5]));

  ASSERT_GT(result.caller().subspan(1).size(), 0u);
  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(10),
                                              DataRate::KilobitsPerSec(1200))));
}

// Test that Scream adapt to a link with traffic policing on the network path
// from caller to calee.
TEST(ScreamTest, MaybeTest(LinkCapacity5MbitPolicedTo256Kbit)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  NetworkEmulationManager::SimulatedNetworkNode::Builder network_builder =
      s.net()->NodeBuilder().capacity_Mbps(5).delay_ms(25);
  params.caller_to_callee_path = {
      s.net()->NodeBuilder().capacity_Mbps(5).delay_ms(25).Build().node,
      TokenBucketNetworkBehaviorNodeBuilder(s.net())
          .burst(DataSize::Bytes(16384))  // 0.5s at 256kbps.
          .rate(DataRate::KilobitsPerSec(256))
          .Build()};
  params.callee_to_caller_path =
      CreateNetworkPath(network_builder, /*use_dual_pi= */ false);

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  EXPECT_THAT(
      GetPacketsLost(result.callee_stats.back()) /
          static_cast<double>(GetPacketsSent(result.caller_stats.back())),
      AllOf(Lt(0.11), Gt(0.01)));

  EXPECT_THAT(result.caller().subspan(1), Each(AvailableSendBitrateIsBetween(
                                              DataRate::KilobitsPerSec(150),
                                              DataRate::KilobitsPerSec(900))));
}

TEST(ScreamTest, MaybeTest(LinkCapacity5MbitWithCrossTrafficNoEcn)) {
  PeerScenario s(*testing::UnitTest::GetInstance()->current_test_info());
  SendMediaTestParams params;
  params.test_duration = TimeDelta::Seconds(30);
  params.caller_to_callee_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(5000), TimeDelta::Millis(25));
  params.callee_to_caller_path =
      CreateNetworkPath(s, /*use_dual_pi= */ false,
                        DataRate::KilobitsPerSec(5000), TimeDelta::Millis(25));

  // Simulate a file upload on the path from caller to calee.
  webrtc::TcpMessageRoute* tcp_route = s.net()->CreateTcpRoute(
      s.net()->CreateRoute({params.caller_to_callee_path}),
      s.net()->CreateRoute({params.callee_to_caller_path}));
  Timestamp start_time = s.net()->Now();
  Timestamp tcp_message_delivered_time = Timestamp::MinusInfinity();
  s.net()->time_controller()->GetMainThread()->PostDelayedTask(
      [&]() {
        tcp_route->SendMessage(
            /*size=*/2'000'000,
            /*on_received=*/[&tcp_message_delivered_time, &s]() {
              tcp_message_delivered_time = s.net()->Now();
            });
      },
      TimeDelta::Seconds(3));

  SendMediaTestResult result = SendMediaInOneDirection(std::move(params), s);
  ASSERT_TRUE(tcp_message_delivered_time.IsFinite());

  int index_where_available_bitrate_should_have_recovered =
      (tcp_message_delivered_time - start_time).seconds<int>() + 10;
  EXPECT_THAT(
      result.caller().subspan(
          index_where_available_bitrate_should_have_recovered),
      Each(AvailableSendBitrateIsBetween(DataRate::KilobitsPerSec(1500),
                                         DataRate::KilobitsPerSec(5000))));
}
}  // namespace
}  // namespace webrtc
