Introduce a mode that lets NetworkEmulationManager ignore DTLS handshake sizes.

Bug: b/169531206
Change-Id: I02c19385ff7078944f7509ecc07358b4315f7b08
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/350181
Commit-Queue: Sergey Sukhanov <sergeysu@webrtc.org>
Reviewed-by: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42261}
diff --git a/api/test/create_network_emulation_manager.cc b/api/test/create_network_emulation_manager.cc
index 14a7a6a..36c496f 100644
--- a/api/test/create_network_emulation_manager.cc
+++ b/api/test/create_network_emulation_manager.cc
@@ -12,6 +12,7 @@
 #include "api/test/create_network_emulation_manager.h"
 
 #include <memory>
+#include <utility>
 
 #include "api/field_trials_view.h"
 #include "test/network/network_emulation_manager.h"
@@ -19,11 +20,18 @@
 namespace webrtc {
 
 std::unique_ptr<NetworkEmulationManager> CreateNetworkEmulationManager(
+    NetworkEmulationManagerConfig config) {
+  return std::make_unique<test::NetworkEmulationManagerImpl>(std::move(config));
+}
+
+std::unique_ptr<NetworkEmulationManager> CreateNetworkEmulationManager(
     TimeMode time_mode,
     EmulatedNetworkStatsGatheringMode stats_gathering_mode,
     const FieldTrialsView* field_trials) {
-  return std::make_unique<test::NetworkEmulationManagerImpl>(
-      time_mode, stats_gathering_mode, field_trials);
+  return CreateNetworkEmulationManager(
+      {.time_mode = time_mode,
+       .stats_gathering_mode = stats_gathering_mode,
+       .field_trials = field_trials});
 }
 
 }  // namespace webrtc
diff --git a/api/test/create_network_emulation_manager.h b/api/test/create_network_emulation_manager.h
index 2f2dfed..d92a0ff 100644
--- a/api/test/create_network_emulation_manager.h
+++ b/api/test/create_network_emulation_manager.h
@@ -20,7 +20,12 @@
 
 // Returns a non-null NetworkEmulationManager instance.
 std::unique_ptr<NetworkEmulationManager> CreateNetworkEmulationManager(
-    TimeMode time_mode = TimeMode::kRealTime,
+    NetworkEmulationManagerConfig config = NetworkEmulationManagerConfig());
+
+[[deprecated("Use version with NetworkEmulationManagerConfig)")]]
+std::unique_ptr<NetworkEmulationManager>
+CreateNetworkEmulationManager(
+    TimeMode time_mode,
     EmulatedNetworkStatsGatheringMode stats_gathering_mode =
         EmulatedNetworkStatsGatheringMode::kDefault,
     const FieldTrialsView* field_trials = nullptr);
diff --git a/api/test/network_emulation_manager.h b/api/test/network_emulation_manager.h
index 6b66d81..2d51ae8 100644
--- a/api/test/network_emulation_manager.h
+++ b/api/test/network_emulation_manager.h
@@ -160,6 +160,26 @@
 // `mode`.
 std::string AbslUnparseFlag(TimeMode mode);
 
+// The construction-time configuration options for NetworkEmulationManager.
+struct NetworkEmulationManagerConfig {
+  // The mode of the underlying time controller.
+  TimeMode time_mode = TimeMode::kRealTime;
+  // The mode that determines the set of metrics to collect into
+  // `EmulatedNetworkStats` and `EmulatedNetworkNodeStats`.
+  EmulatedNetworkStatsGatheringMode stats_gathering_mode =
+      EmulatedNetworkStatsGatheringMode::kDefault;
+  // Field trials that can alter the behavior of NetworkEmulationManager.
+  const FieldTrialsView* field_trials = nullptr;
+  // If this flag is set, NetworkEmulationManager ignores the sizes of peers'
+  // DTLS handshake packets when determining when to let the packets through
+  // a constrained emulated network. Actual hanshake's packet size is ignored
+  // and a hardcoded fake size is used to compute packet's use of link capacity.
+  // This is useful for tests that require deterministic packets scheduling
+  // timing-wise even when the sizes of DTLS hadshake packets are not
+  // deterministic. This mode make sense only together with the simulated time.
+  bool fake_dtls_handshake_sizes = false;
+};
+
 // Provides an API for creating and configuring emulated network layer.
 // All objects returned by this API are owned by NetworkEmulationManager itself
 // and will be deleted when manager will be deleted.
diff --git a/net/dcsctp/socket/dcsctp_socket_network_test.cc b/net/dcsctp/socket/dcsctp_socket_network_test.cc
index d9d9720..801d471 100644
--- a/net/dcsctp/socket/dcsctp_socket_network_test.cc
+++ b/net/dcsctp/socket/dcsctp_socket_network_test.cc
@@ -326,7 +326,7 @@
   DcSctpSocketNetworkTest()
       : options_(MakeOptionsForTest()),
         emulation_(webrtc::CreateNetworkEmulationManager(
-            webrtc::TimeMode::kSimulated)) {}
+            {.time_mode = webrtc::TimeMode::kSimulated})) {}
 
   void MakeNetwork(const webrtc::BuiltInNetworkBehaviorConfig& config) {
     webrtc::EmulatedEndpoint* endpoint_a =
diff --git a/pc/test/svc_e2e_tests.cc b/pc/test/svc_e2e_tests.cc
index 1f1a41f..78342d4 100644
--- a/pc/test/svc_e2e_tests.cc
+++ b/pc/test/svc_e2e_tests.cc
@@ -316,7 +316,7 @@
   }
   test::ScopedFieldTrials override_trials(AppendFieldTrials(trials));
   std::unique_ptr<NetworkEmulationManager> network_emulation_manager =
-      CreateNetworkEmulationManager(TimeMode::kSimulated);
+      CreateNetworkEmulationManager({.time_mode = TimeMode::kSimulated});
   auto analyzer = std::make_unique<SvcVideoQualityAnalyzer>(
       network_emulation_manager->time_controller()->GetClock());
   SvcVideoQualityAnalyzer* analyzer_ptr = analyzer.get();
diff --git a/test/network/cross_traffic_unittest.cc b/test/network/cross_traffic_unittest.cc
index e9412a7..ff1c1e1 100644
--- a/test/network/cross_traffic_unittest.cc
+++ b/test/network/cross_traffic_unittest.cc
@@ -125,8 +125,7 @@
 }
 
 TEST(TcpMessageRouteTest, DeliveredOnLossyNetwork) {
-  NetworkEmulationManagerImpl net(TimeMode::kSimulated,
-                                  EmulatedNetworkStatsGatheringMode::kDefault);
+  NetworkEmulationManagerImpl net({.time_mode = TimeMode::kSimulated});
   BuiltInNetworkBehaviorConfig send;
   // 800 kbps means that the 100 kB message would be delivered in ca 1 second
   // under ideal conditions and no overhead.
diff --git a/test/network/feedback_generator.cc b/test/network/feedback_generator.cc
index e339fd8..9df6e24 100644
--- a/test/network/feedback_generator.cc
+++ b/test/network/feedback_generator.cc
@@ -12,13 +12,14 @@
 #include "absl/memory/memory.h"
 #include "api/transport/network_types.h"
 #include "rtc_base/checks.h"
+#include "test/network/network_emulation_manager.h"
 
 namespace webrtc {
 
 FeedbackGeneratorImpl::FeedbackGeneratorImpl(
     FeedbackGeneratorImpl::Config config)
     : conf_(config),
-      net_(TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault),
+      net_({.time_mode = TimeMode::kSimulated}),
       send_link_{new SimulatedNetwork(conf_.send_link)},
       ret_link_{new SimulatedNetwork(conf_.return_link)},
       route_(this,
diff --git a/test/network/network_emulation.cc b/test/network/network_emulation.cc
index c0954c6..0a67d54 100644
--- a/test/network/network_emulation.cc
+++ b/test/network/network_emulation.cc
@@ -10,6 +10,8 @@
 
 #include "test/network/network_emulation.h"
 
+#include <stdint.h>
+
 #include <algorithm>
 #include <limits>
 #include <memory>
@@ -51,6 +53,17 @@
   return builder.Build();
 }
 
+bool IsDtlsHandshakePacket(const uint8_t* payload, size_t payload_size) {
+  if (payload_size < 14) {
+    return false;
+  }
+  // https://tools.ietf.org/html/rfc6347#section-4.1
+  // https://tools.ietf.org/html/rfc6347#section-4.2.2
+  // https://tools.ietf.org/html/rfc5246#section-7.4
+  return payload[0] == 22 &&
+         (payload[13] == 1 || payload[13] == 2 || payload[13] == 11);
+}
+
 }  // namespace
 
 EmulatedNetworkOutgoingStatsBuilder::EmulatedNetworkOutgoingStatsBuilder(
@@ -311,16 +324,31 @@
   return stats_;
 }
 
+size_t LinkEmulation::GetPacketSizeForEmulation(
+    const EmulatedIpPacket& packet) const {
+  if (fake_dtls_handshake_sizes_ &&
+      IsDtlsHandshakePacket(packet.data.cdata(), packet.data.size())) {
+    // DTLS handshake packets can not have deterministic size unless
+    // the OpenSSL/BoringSSL is configured to have deterministic random,
+    // which is hard. The workaround is - conditionally ignore the actual
+    // size and hardcode the value order of typical handshake packet size.
+    return 1000;
+  }
+  return packet.ip_packet_size();
+}
+
 LinkEmulation::LinkEmulation(
     Clock* clock,
     absl::Nonnull<TaskQueueBase*> task_queue,
     std::unique_ptr<NetworkBehaviorInterface> network_behavior,
     EmulatedNetworkReceiverInterface* receiver,
-    EmulatedNetworkStatsGatheringMode stats_gathering_mode)
+    EmulatedNetworkStatsGatheringMode stats_gathering_mode,
+    bool fake_dtls_handshake_sizes)
     : clock_(clock),
       task_queue_(task_queue),
       network_behavior_(std::move(network_behavior)),
       receiver_(receiver),
+      fake_dtls_handshake_sizes_(fake_dtls_handshake_sizes),
       stats_builder_(stats_gathering_mode) {
   task_queue_->PostTask([&]() {
     RTC_DCHECK_RUN_ON(task_queue_);
@@ -336,8 +364,9 @@
     RTC_DCHECK_RUN_ON(task_queue_);
 
     uint64_t packet_id = next_packet_id_++;
-    bool sent = network_behavior_->EnqueuePacket(PacketInFlightInfo(
-        packet.ip_packet_size(), packet.arrival_time.us(), packet_id));
+    bool sent = network_behavior_->EnqueuePacket(
+        PacketInFlightInfo(GetPacketSizeForEmulation(packet),
+                           packet.arrival_time.us(), packet_id));
     if (sent) {
       packets_.emplace_back(StoredPacket{.id = packet_id,
                                          .sent_time = clock_->CurrentTime(),
@@ -372,7 +401,7 @@
     packet->removed = true;
     stats_builder_.AddPacketTransportTime(
         clock_->CurrentTime() - packet->sent_time,
-        packet->packet.ip_packet_size());
+        GetPacketSizeForEmulation(packet->packet));
 
     if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) {
       packet->packet.arrival_time =
@@ -492,13 +521,15 @@
     Clock* clock,
     absl::Nonnull<TaskQueueBase*> task_queue,
     std::unique_ptr<NetworkBehaviorInterface> network_behavior,
-    EmulatedNetworkStatsGatheringMode stats_gathering_mode)
+    EmulatedNetworkStatsGatheringMode stats_gathering_mode,
+    bool fake_dtls_handshake_sizes)
     : router_(task_queue),
       link_(clock,
             task_queue,
             std::move(network_behavior),
             &router_,
-            stats_gathering_mode) {}
+            stats_gathering_mode,
+            fake_dtls_handshake_sizes) {}
 
 void EmulatedNetworkNode::OnPacketReceived(EmulatedIpPacket packet) {
   link_.OnPacketReceived(std::move(packet));
diff --git a/test/network/network_emulation.h b/test/network/network_emulation.h
index 5fbd033..2feaa35 100644
--- a/test/network/network_emulation.h
+++ b/test/network/network_emulation.h
@@ -12,6 +12,7 @@
 #define TEST_NETWORK_NETWORK_EMULATION_H_
 
 #include <cstdint>
+#include <cstring>
 #include <deque>
 #include <map>
 #include <memory>
@@ -150,7 +151,8 @@
                 absl::Nonnull<TaskQueueBase*> task_queue,
                 std::unique_ptr<NetworkBehaviorInterface> network_behavior,
                 EmulatedNetworkReceiverInterface* receiver,
-                EmulatedNetworkStatsGatheringMode stats_gathering_mode);
+                EmulatedNetworkStatsGatheringMode stats_gathering_mode,
+                bool fake_dtls_handshake_sizes);
   void OnPacketReceived(EmulatedIpPacket packet) override;
 
   EmulatedNetworkNodeStats stats() const;
@@ -164,12 +166,14 @@
   };
   void UpdateProcessSchedule() RTC_RUN_ON(task_queue_);
   void Process(Timestamp at_time) RTC_RUN_ON(task_queue_);
+  size_t GetPacketSizeForEmulation(const EmulatedIpPacket& packet) const;
 
   Clock* const clock_;
   const absl::Nonnull<TaskQueueBase*> task_queue_;
   const std::unique_ptr<NetworkBehaviorInterface> network_behavior_
       RTC_GUARDED_BY(task_queue_);
   EmulatedNetworkReceiverInterface* const receiver_;
+  const bool fake_dtls_handshake_sizes_;
 
   RepeatingTaskHandle process_task_ RTC_GUARDED_BY(task_queue_);
   std::deque<StoredPacket> packets_ RTC_GUARDED_BY(task_queue_);
@@ -224,7 +228,8 @@
       Clock* clock,
       absl::Nonnull<TaskQueueBase*> task_queue,
       std::unique_ptr<NetworkBehaviorInterface> network_behavior,
-      EmulatedNetworkStatsGatheringMode stats_gathering_mode);
+      EmulatedNetworkStatsGatheringMode stats_gathering_mode,
+      bool fake_dtls_handshake_sizes);
   ~EmulatedNetworkNode() override;
 
   EmulatedNetworkNode(const EmulatedNetworkNode&) = delete;
@@ -408,6 +413,7 @@
     RTC_CHECK_GE(size, sizeof(int));
     sent_.emplace(next_packet_id_, packet);
     rtc::CopyOnWriteBuffer buf(size);
+    memset(buf.MutableData(), 0, size);
     reinterpret_cast<int*>(buf.MutableData())[0] = next_packet_id_++;
     route_->from->SendPacket(send_addr_, recv_addr_, buf);
   }
diff --git a/test/network/network_emulation_manager.cc b/test/network/network_emulation_manager.cc
index 05a1a30..0896af3 100644
--- a/test/network/network_emulation_manager.cc
+++ b/test/network/network_emulation_manager.cc
@@ -48,13 +48,13 @@
 }  // namespace
 
 NetworkEmulationManagerImpl::NetworkEmulationManagerImpl(
-    TimeMode mode,
-    EmulatedNetworkStatsGatheringMode stats_gathering_mode,
-    const FieldTrialsView* field_trials)
-    : time_mode_(mode),
-      stats_gathering_mode_(stats_gathering_mode),
-      time_controller_(CreateTimeController(mode, field_trials)),
+    NetworkEmulationManagerConfig config)
+    : time_mode_(config.time_mode),
+      stats_gathering_mode_(config.stats_gathering_mode),
+      time_controller_(
+          CreateTimeController(config.time_mode, config.field_trials)),
       clock_(time_controller_->GetClock()),
+      fake_dtls_handshake_sizes_(config.fake_dtls_handshake_sizes),
       next_node_id_(1),
       next_ip4_address_(kMinIPv4Address),
       task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue(
@@ -79,9 +79,9 @@
 
 EmulatedNetworkNode* NetworkEmulationManagerImpl::CreateEmulatedNode(
     std::unique_ptr<NetworkBehaviorInterface> network_behavior) {
-  auto node = std::make_unique<EmulatedNetworkNode>(clock_, task_queue_.Get(),
-                                                    std::move(network_behavior),
-                                                    stats_gathering_mode_);
+  auto node = std::make_unique<EmulatedNetworkNode>(
+      clock_, task_queue_.Get(), std::move(network_behavior),
+      stats_gathering_mode_, fake_dtls_handshake_sizes_);
   EmulatedNetworkNode* out = node.get();
   task_queue_.PostTask([this, node = std::move(node)]() mutable {
     network_nodes_.push_back(std::move(node));
diff --git a/test/network/network_emulation_manager.h b/test/network/network_emulation_manager.h
index 4b0a764..1c54241 100644
--- a/test/network/network_emulation_manager.h
+++ b/test/network/network_emulation_manager.h
@@ -37,10 +37,7 @@
 
 class NetworkEmulationManagerImpl : public NetworkEmulationManager {
  public:
-  NetworkEmulationManagerImpl(
-      TimeMode mode,
-      EmulatedNetworkStatsGatheringMode stats_gathering_mode,
-      const FieldTrialsView* field_trials = nullptr);
+  explicit NetworkEmulationManagerImpl(NetworkEmulationManagerConfig config);
   ~NetworkEmulationManagerImpl();
 
   EmulatedNetworkNode* CreateEmulatedNode(BuiltInNetworkBehaviorConfig config,
@@ -108,6 +105,7 @@
   const EmulatedNetworkStatsGatheringMode stats_gathering_mode_;
   const std::unique_ptr<TimeController> time_controller_;
   Clock* const clock_;
+  const bool fake_dtls_handshake_sizes_;
   int next_node_id_;
 
   RepeatingTaskHandle process_task_handle_;
diff --git a/test/network/network_emulation_pc_unittest.cc b/test/network/network_emulation_pc_unittest.cc
index 838749c..61fb47c 100644
--- a/test/network/network_emulation_pc_unittest.cc
+++ b/test/network/network_emulation_pc_unittest.cc
@@ -111,8 +111,7 @@
   signaling_thread->Start();
 
   // Setup emulated network
-  NetworkEmulationManagerImpl emulation(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+  NetworkEmulationManagerImpl emulation({.time_mode = TimeMode::kRealTime});
 
   EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode(
       std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
@@ -203,8 +202,7 @@
   signaling_thread->Start();
 
   // Setup emulated network
-  NetworkEmulationManagerImpl emulation(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+  NetworkEmulationManagerImpl emulation({.time_mode = TimeMode::kRealTime});
 
   EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode(
       std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
diff --git a/test/network/network_emulation_unittest.cc b/test/network/network_emulation_unittest.cc
index 4b8e4df..761236c 100644
--- a/test/network/network_emulation_unittest.cc
+++ b/test/network/network_emulation_unittest.cc
@@ -163,7 +163,7 @@
   MockReceiver r_e3_e1_;
 
   NetworkEmulationManagerImpl emulation_{
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault};
+      NetworkEmulationManagerConfig{.time_mode = TimeMode::kRealTime}};
   EmulatedEndpoint* e1_;
   EmulatedEndpoint* e2_;
   EmulatedEndpoint* e3_;
@@ -181,7 +181,7 @@
 
 TEST(NetworkEmulationManagerTest, GeneratedIpv4AddressDoesNotCollide) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kRealTime});
   std::set<rtc::IPAddress> ips;
   EmulatedEndpointConfig config;
   config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv4;
@@ -195,7 +195,7 @@
 
 TEST(NetworkEmulationManagerTest, GeneratedIpv6AddressDoesNotCollide) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kRealTime});
   std::set<rtc::IPAddress> ips;
   EmulatedEndpointConfig config;
   config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv6;
@@ -209,7 +209,7 @@
 
 TEST(NetworkEmulationManagerTest, Run) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kRealTime});
 
   EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode(
       std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
@@ -363,7 +363,8 @@
 
 TEST(NetworkEmulationManagerTest, DebugStatsCollectedInDebugMode) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDebug);
+      {.time_mode = TimeMode::kSimulated,
+       .stats_gathering_mode = EmulatedNetworkStatsGatheringMode::kDebug});
 
   EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode(
       std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
@@ -463,7 +464,7 @@
 
 TEST(NetworkEmulationManagerTest, ThroughputStats) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kRealTime});
 
   EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode(
       std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
@@ -594,7 +595,7 @@
 
 TEST(NetworkEmulationManagerTest, EndpointLoopback) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kSimulated});
   auto endpoint = network_manager.CreateEndpoint(EmulatedEndpointConfig());
 
   MockReceiver receiver;
@@ -611,7 +612,7 @@
   constexpr uint32_t kEndpointIp = 0xC0A80011;  // 192.168.0.17
   constexpr uint32_t kSourceIp = 0xC0A80012;    // 192.168.0.18
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kSimulated});
   EmulatedEndpointConfig endpoint_config;
   endpoint_config.ip = rtc::IPAddress(kEndpointIp);
   endpoint_config.allow_send_packet_with_different_source_ip = true;
@@ -632,7 +633,7 @@
   constexpr uint32_t kDestEndpointIp = 0xC0A80011;  // 192.168.0.17
   constexpr uint32_t kDestIp = 0xC0A80012;          // 192.168.0.18
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kSimulated});
   auto sender_endpoint =
       network_manager.CreateEndpoint(EmulatedEndpointConfig());
   EmulatedEndpointConfig endpoint_config;
@@ -656,7 +657,7 @@
 
 TEST(NetworkEmulationManagerTURNTest, GetIceServerConfig) {
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kRealTime, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kRealTime});
   auto turn = network_manager.CreateTURNServer(EmulatedTURNServerConfig());
 
   EXPECT_GT(turn->GetIceServerConfig().username.size(), 0u);
@@ -667,8 +668,7 @@
 }
 
 TEST(NetworkEmulationManagerTURNTest, ClientTraffic) {
-  NetworkEmulationManagerImpl emulation(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault);
+  NetworkEmulationManagerImpl emulation({.time_mode = TimeMode::kSimulated});
   auto* ep = emulation.CreateEndpoint(EmulatedEndpointConfig());
   auto* turn = emulation.CreateTURNServer(EmulatedTURNServerConfig());
   auto* node = CreateEmulatedNodeWithDefaultBuiltInConfig(&emulation);
@@ -695,7 +695,7 @@
 TEST(LinkEmulationTest, HandlesDeliveryTimeChangedCallback) {
   constexpr uint32_t kEndpointIp = 0xC0A80011;  // 192.168.0.17
   NetworkEmulationManagerImpl network_manager(
-      TimeMode::kSimulated, EmulatedNetworkStatsGatheringMode::kDefault);
+      {.time_mode = TimeMode::kSimulated});
   auto mock_behaviour =
       std::make_unique<::testing::NiceMock<MockNetworkBehaviourInterface>>();
   MockNetworkBehaviourInterface* mock_behaviour_ptr = mock_behaviour.get();
diff --git a/test/pc/e2e/peer_connection_quality_test_metric_names_test.cc b/test/pc/e2e/peer_connection_quality_test_metric_names_test.cc
index 46f7e93..1d59429 100644
--- a/test/pc/e2e/peer_connection_quality_test_metric_names_test.cc
+++ b/test/pc/e2e/peer_connection_quality_test_metric_names_test.cc
@@ -108,7 +108,7 @@
 TEST(PeerConnectionE2EQualityTestMetricNamesTest,
      ExportedMetricsHasCorrectNamesAndAnnotation) {
   std::unique_ptr<NetworkEmulationManager> network_emulation =
-      CreateNetworkEmulationManager(TimeMode::kSimulated);
+      CreateNetworkEmulationManager({.time_mode = TimeMode::kSimulated});
   DefaultMetricsLogger metrics_logger(
       network_emulation->time_controller()->GetClock());
   PeerConnectionE2EQualityTest fixture(
@@ -1124,7 +1124,7 @@
 TEST(PeerConnectionE2EQualityTestMetricNamesTest,
      ExportedNetworkMetricsHaveCustomNetworkLabelIfSet) {
   std::unique_ptr<NetworkEmulationManager> network_emulation =
-      CreateNetworkEmulationManager(TimeMode::kSimulated);
+      CreateNetworkEmulationManager({.time_mode = TimeMode::kSimulated});
   DefaultMetricsLogger metrics_logger(
       network_emulation->time_controller()->GetClock());
   PeerConnectionE2EQualityTest fixture(
diff --git a/test/pc/e2e/peer_connection_quality_test_test.cc b/test/pc/e2e/peer_connection_quality_test_test.cc
index 066fe7d..a63bc29 100644
--- a/test/pc/e2e/peer_connection_quality_test_test.cc
+++ b/test/pc/e2e/peer_connection_quality_test_test.cc
@@ -90,7 +90,7 @@
 
 TEST_F(PeerConnectionE2EQualityTestTest, OutputVideoIsDumpedWhenRequested) {
   std::unique_ptr<NetworkEmulationManager> network_emulation =
-      CreateNetworkEmulationManager(TimeMode::kSimulated);
+      CreateNetworkEmulationManager({.time_mode = TimeMode::kSimulated});
   PeerConnectionE2EQualityTest fixture(
       "test_case", *network_emulation->time_controller(),
       /*audio_quality_analyzer=*/nullptr, /*video_quality_analyzer=*/nullptr,
diff --git a/test/pc/e2e/stats_based_network_quality_metrics_reporter_test.cc b/test/pc/e2e/stats_based_network_quality_metrics_reporter_test.cc
index be55149..6401902 100644
--- a/test/pc/e2e/stats_based_network_quality_metrics_reporter_test.cc
+++ b/test/pc/e2e/stats_based_network_quality_metrics_reporter_test.cc
@@ -77,8 +77,9 @@
 
 TEST(StatsBasedNetworkQualityMetricsReporterTest, DebugStatsAreCollected) {
   std::unique_ptr<NetworkEmulationManager> network_emulation =
-      CreateNetworkEmulationManager(TimeMode::kSimulated,
-                                    EmulatedNetworkStatsGatheringMode::kDebug);
+      CreateNetworkEmulationManager(
+          {.time_mode = TimeMode::kSimulated,
+           .stats_gathering_mode = EmulatedNetworkStatsGatheringMode::kDebug});
   DefaultMetricsLogger metrics_logger(
       network_emulation->time_controller()->GetClock());
   PeerConnectionE2EQualityTest fixture(
diff --git a/test/peer_scenario/peer_scenario.cc b/test/peer_scenario/peer_scenario.cc
index 485e33f..519c382 100644
--- a/test/peer_scenario/peer_scenario.cc
+++ b/test/peer_scenario/peer_scenario.cc
@@ -15,6 +15,7 @@
 #include "rtc_base/string_encode.h"
 #include "rtc_base/strings/string_builder.h"
 #include "test/logging/file_log_writer.h"
+#include "test/network/network_emulation_manager.h"
 #include "test/testsupport/file_utils.h"
 #include "test/time_controller/real_time_controller.h"
 #include "test/time_controller/simulated_time_controller.h"
@@ -55,7 +56,7 @@
     std::unique_ptr<LogWriterFactoryInterface> log_writer_manager,
     TimeMode mode)
     : log_writer_manager_(std::move(log_writer_manager)),
-      net_(mode, EmulatedNetworkStatsGatheringMode::kDefault),
+      net_({.time_mode = mode}),
       signaling_thread_(net_.time_controller()->GetMainThread()) {}
 
 PeerScenarioClient* PeerScenario::CreateClient(
diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc
index 98f59e6..0ff5fc7 100644
--- a/test/scenario/scenario.cc
+++ b/test/scenario/scenario.cc
@@ -20,6 +20,7 @@
 #include "rtc_base/socket_address.h"
 #include "test/logging/file_log_writer.h"
 #include "test/network/network_emulation.h"
+#include "test/network/network_emulation_manager.h"
 #include "test/scenario/video_stream.h"
 #include "test/testsupport/file_utils.h"
 
@@ -66,8 +67,8 @@
     std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
     bool real_time)
     : log_writer_factory_(std::move(log_writer_factory)),
-      network_manager_(real_time ? TimeMode::kRealTime : TimeMode::kSimulated,
-                       EmulatedNetworkStatsGatheringMode::kDefault),
+      network_manager_({.time_mode = real_time ? TimeMode::kRealTime
+                                               : TimeMode::kSimulated}),
       clock_(network_manager_.time_controller()->GetClock()),
       audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
       audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),