Add cross trafic emulation api

Bug: webrtc:12344
Change-Id: I958dc4deda4af4576818600c31aecdf48285172f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/200981
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Commit-Queue: Andrey Logvin <landrey@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32989}
diff --git a/api/test/network_emulation/BUILD.gn b/api/test/network_emulation/BUILD.gn
index fb7bedc..58cd27d 100644
--- a/api/test/network_emulation/BUILD.gn
+++ b/api/test/network_emulation/BUILD.gn
@@ -12,6 +12,7 @@
   visibility = [ "*" ]
 
   sources = [
+    "cross_traffic.h",
     "network_emulation_interfaces.cc",
     "network_emulation_interfaces.h",
   ]
@@ -22,9 +23,28 @@
     "../../../rtc_base:checks",
     "../../../rtc_base:rtc_base_approved",
     "../../numerics",
+    "../../task_queue",
     "../../units:data_rate",
     "../../units:data_size",
+    "../../units:time_delta",
     "../../units:timestamp",
   ]
   absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
 }
+
+rtc_library("create_cross_traffic") {
+  visibility = [ "*" ]
+  testonly = true
+
+  sources = [
+    "create_cross_traffic.cc",
+    "create_cross_traffic.h",
+  ]
+
+  deps = [
+    ":network_emulation",
+    "../..:network_emulation_manager_api",
+    "../../../rtc_base/task_utils:repeating_task",
+    "../../../test/network:emulated_network",
+  ]
+}
diff --git a/api/test/network_emulation/create_cross_traffic.cc b/api/test/network_emulation/create_cross_traffic.cc
new file mode 100644
index 0000000..36a535c
--- /dev/null
+++ b/api/test/network_emulation/create_cross_traffic.cc
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) 2021 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 "api/test/network_emulation/create_cross_traffic.h"
+
+#include <memory>
+
+#include "rtc_base/task_utils/repeating_task.h"
+#include "test/network/cross_traffic.h"
+
+namespace webrtc {
+
+std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic(
+    CrossTrafficRoute* traffic_route,
+    RandomWalkConfig config) {
+  return std::make_unique<test::RandomWalkCrossTraffic>(config, traffic_route);
+}
+
+std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic(
+    CrossTrafficRoute* traffic_route,
+    PulsedPeaksConfig config) {
+  return std::make_unique<test::PulsedPeaksCrossTraffic>(config, traffic_route);
+}
+
+std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic(
+    EmulatedRoute* send_route,
+    EmulatedRoute* ret_route,
+    FakeTcpConfig config) {
+  return std::make_unique<test::FakeTcpCrossTraffic>(config, send_route,
+                                                     ret_route);
+}
+
+}  // namespace webrtc
diff --git a/api/test/network_emulation/create_cross_traffic.h b/api/test/network_emulation/create_cross_traffic.h
new file mode 100644
index 0000000..42fc855
--- /dev/null
+++ b/api/test/network_emulation/create_cross_traffic.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
+#define API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
+
+#include <memory>
+
+#include "api/test/network_emulation/cross_traffic.h"
+#include "api/test/network_emulation_manager.h"
+
+namespace webrtc {
+
+// This API is still in development and can be changed without prior notice.
+
+std::unique_ptr<CrossTrafficGenerator> CreateRandomWalkCrossTraffic(
+    CrossTrafficRoute* traffic_route,
+    RandomWalkConfig config);
+
+std::unique_ptr<CrossTrafficGenerator> CreatePulsedPeaksCrossTraffic(
+    CrossTrafficRoute* traffic_route,
+    PulsedPeaksConfig config);
+
+std::unique_ptr<CrossTrafficGenerator> CreateFakeTcpCrossTraffic(
+    EmulatedRoute* send_route,
+    EmulatedRoute* ret_route,
+    FakeTcpConfig config);
+
+}  // namespace webrtc
+
+#endif  // API_TEST_NETWORK_EMULATION_CREATE_CROSS_TRAFFIC_H_
diff --git a/api/test/network_emulation/cross_traffic.h b/api/test/network_emulation/cross_traffic.h
new file mode 100644
index 0000000..85343e4
--- /dev/null
+++ b/api/test/network_emulation/cross_traffic.h
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2021 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 API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
+#define API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
+
+#include "api/task_queue/task_queue_base.h"
+#include "api/test/network_emulation/network_emulation_interfaces.h"
+#include "api/units/data_rate.h"
+#include "api/units/data_size.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+
+namespace webrtc {
+
+// This API is still in development and can be changed without prior notice.
+
+// Represents the endpoint for cross traffic that is going through the network.
+// It can be used to emulate unexpected network load.
+class CrossTrafficRoute {
+ public:
+  virtual ~CrossTrafficRoute() = default;
+
+  // Triggers sending of dummy packets with size |packet_size| bytes.
+  virtual void TriggerPacketBurst(size_t num_packets, size_t packet_size) = 0;
+  // Sends a packet over the nodes. The content of the packet is unspecified;
+  // only the size metter for the emulation purposes.
+  virtual void SendPacket(size_t packet_size) = 0;
+  // Sends a packet over the nodes and runs |action| when it has been delivered.
+  virtual void NetworkDelayedAction(size_t packet_size,
+                                    std::function<void()> action) = 0;
+};
+
+// Describes a way of generating cross traffic on some route. Used by
+// NetworkEmulationManager to produce cross traffic during some period of time.
+class CrossTrafficGenerator {
+ public:
+  virtual ~CrossTrafficGenerator() = default;
+
+  // Time between Process calls.
+  virtual TimeDelta GetProcessInterval() const = 0;
+
+  // Called periodically by NetworkEmulationManager. Generates traffic on the
+  // route.
+  virtual void Process(Timestamp at_time) = 0;
+};
+
+// Config of a cross traffic generator. Generated traffic rises and falls
+// randomly.
+struct RandomWalkConfig {
+  int random_seed = 1;
+  DataRate peak_rate = DataRate::KilobitsPerSec(100);
+  DataSize min_packet_size = DataSize::Bytes(200);
+  TimeDelta min_packet_interval = TimeDelta::Millis(1);
+  TimeDelta update_interval = TimeDelta::Millis(200);
+  double variance = 0.6;
+  double bias = -0.1;
+};
+
+// Config of a cross traffic generator. Generated traffic has form of periodic
+// peaks alternating with periods of silence.
+struct PulsedPeaksConfig {
+  DataRate peak_rate = DataRate::KilobitsPerSec(100);
+  DataSize min_packet_size = DataSize::Bytes(200);
+  TimeDelta min_packet_interval = TimeDelta::Millis(1);
+  TimeDelta send_duration = TimeDelta::Millis(100);
+  TimeDelta hold_duration = TimeDelta::Millis(2000);
+};
+
+struct FakeTcpConfig {
+  DataSize packet_size = DataSize::Bytes(1200);
+  DataSize send_limit = DataSize::PlusInfinity();
+  TimeDelta process_interval = TimeDelta::Millis(200);
+  TimeDelta packet_timeout = TimeDelta::Seconds(1);
+};
+
+}  // namespace webrtc
+
+#endif  // API_TEST_NETWORK_EMULATION_CROSS_TRAFFIC_H_
diff --git a/api/test/network_emulation_manager.h b/api/test/network_emulation_manager.h
index 80efb0e..4857c87 100644
--- a/api/test/network_emulation_manager.h
+++ b/api/test/network_emulation_manager.h
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include "api/array_view.h"
+#include "api/test/network_emulation/cross_traffic.h"
 #include "api/test/network_emulation/network_emulation_interfaces.h"
 #include "api/test/simulated_network.h"
 #include "api/test/time_controller.h"
@@ -223,7 +224,8 @@
 
   // Removes route previously created by CreateRoute(...).
   // Caller mustn't call this function with route, that have been already
-  // removed earlier.
+  // removed earlier. Removing a route that is currently in use will lead to
+  // packets being dropped.
   virtual void ClearRoute(EmulatedRoute* route) = 0;
 
   // Creates a simulated TCP connection using |send_route| for traffic and
@@ -233,6 +235,20 @@
   virtual TcpMessageRoute* CreateTcpRoute(EmulatedRoute* send_route,
                                           EmulatedRoute* ret_route) = 0;
 
+  // Creates a route over the given |via_nodes|. Returns an object that can be
+  // used to emulate network load with cross traffic over the created route.
+  virtual CrossTrafficRoute* CreateCrossTrafficRoute(
+      const std::vector<EmulatedNetworkNode*>& via_nodes) = 0;
+
+  // Starts generating cross traffic using given |generator|. Takes ownership
+  // over the generator.
+  virtual CrossTrafficGenerator* StartCrossTraffic(
+      std::unique_ptr<CrossTrafficGenerator> generator) = 0;
+
+  // Stops generating cross traffic that was started using given |generator|.
+  // The |generator| shouldn't be used after and the reference may be invalid.
+  virtual void StopCrossTraffic(CrossTrafficGenerator* generator) = 0;
+
   // Creates EmulatedNetworkManagerInterface which can be used then to inject
   // network emulation layer into PeerConnection. |endpoints| - are available
   // network interfaces for PeerConnection. If endpoint is enabled, it will be
diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn
index 231ff5e..750e910 100644
--- a/modules/congestion_controller/BUILD.gn
+++ b/modules/congestion_controller/BUILD.gn
@@ -46,6 +46,8 @@
     sources = [ "receive_side_congestion_controller_unittest.cc" ]
     deps = [
       ":congestion_controller",
+      "../../api/test/network_emulation",
+      "../../api/test/network_emulation:create_cross_traffic",
       "../../system_wrappers",
       "../../test:test_support",
       "../../test/scenario",
diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn
index e3be246..a5bcf57 100644
--- a/modules/congestion_controller/goog_cc/BUILD.gn
+++ b/modules/congestion_controller/goog_cc/BUILD.gn
@@ -283,6 +283,8 @@
       ":probe_controller",
       ":pushback_controller",
       "../../../api/rtc_event_log",
+      "../../../api/test/network_emulation",
+      "../../../api/test/network_emulation:create_cross_traffic",
       "../../../api/transport:field_trial_based_config",
       "../../../api/transport:goog_cc",
       "../../../api/transport:network_control",
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 0510cb9..8eb4a00 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
@@ -10,6 +10,8 @@
 
 #include <queue>
 
+#include "api/test/network_emulation/create_cross_traffic.h"
+#include "api/test/network_emulation/cross_traffic.h"
 #include "api/transport/goog_cc_factory.h"
 #include "api/units/data_rate.h"
 #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
@@ -547,8 +549,9 @@
   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());
+    auto* tcp_traffic = s.net()->StartCrossTraffic(CreateFakeTcpCrossTraffic(
+        s.net()->CreateRoute(send_net), s.net()->CreateRoute(ret_net),
+        FakeTcpConfig()));
     s.RunFor(TimeDelta::Seconds(2));
     // Allow the ccongestion controller to recover.
     s.net()->StopCrossTraffic(tcp_traffic);
@@ -836,7 +839,9 @@
   auto* route = s.CreateRoutes(
       client, send_net, s.CreateClient("return", CallClientConfig()), ret_net);
   s.CreateVideoStream(route->forward(), VideoStreamConfig());
-  s.net()->StartFakeTcpCrossTraffic(send_net, ret_net, FakeTcpConfig());
+  s.net()->StartCrossTraffic(CreateFakeTcpCrossTraffic(
+      s.net()->CreateRoute(send_net), s.net()->CreateRoute(ret_net),
+      FakeTcpConfig()));
   s.RunFor(TimeDelta::Seconds(10));
 
   // Currently only testing for the upper limit as we in practice back out
diff --git a/modules/congestion_controller/receive_side_congestion_controller_unittest.cc b/modules/congestion_controller/receive_side_congestion_controller_unittest.cc
index b584623..5622c84 100644
--- a/modules/congestion_controller/receive_side_congestion_controller_unittest.cc
+++ b/modules/congestion_controller/receive_side_congestion_controller_unittest.cc
@@ -10,6 +10,8 @@
 
 #include "modules/congestion_controller/include/receive_side_congestion_controller.h"
 
+#include "api/test/network_emulation/create_cross_traffic.h"
+#include "api/test/network_emulation/cross_traffic.h"
 #include "modules/pacing/packet_router.h"
 #include "system_wrappers/include/clock.h"
 #include "test/gmock.h"
@@ -109,7 +111,9 @@
   VideoStreamConfig video;
   video.stream.packet_feedback = false;
   s.CreateVideoStream(route->forward(), video);
-  s.net()->StartFakeTcpCrossTraffic(send_net, ret_net, FakeTcpConfig());
+  s.net()->StartCrossTraffic(CreateFakeTcpCrossTraffic(
+      s.net()->CreateRoute(send_net), s.net()->CreateRoute(ret_net),
+      FakeTcpConfig()));
   s.RunFor(TimeDelta::Seconds(30));
   // For some reason we get outcompeted by TCP here, this should probably be
   // fixed and a lower bound should be added to the test.
diff --git a/test/network/BUILD.gn b/test/network/BUILD.gn
index 383f149..e250ccb 100644
--- a/test/network/BUILD.gn
+++ b/test/network/BUILD.gn
@@ -12,6 +12,7 @@
   visibility = [
     ":*",
     "../../api:create_network_emulation_manager",
+    "../../api/test/network_emulation:create_cross_traffic",
   ]
   if (rtc_include_tests) {
     visibility += [
diff --git a/test/network/cross_traffic.cc b/test/network/cross_traffic.cc
index 56e7635..ae5b156 100644
--- a/test/network/cross_traffic.cc
+++ b/test/network/cross_traffic.cc
@@ -24,7 +24,7 @@
 namespace test {
 
 RandomWalkCrossTraffic::RandomWalkCrossTraffic(RandomWalkConfig config,
-                                               TrafficRoute* traffic_route)
+                                               CrossTrafficRoute* traffic_route)
     : config_(config),
       traffic_route_(traffic_route),
       random_(config_.random_seed) {
@@ -56,6 +56,10 @@
   }
 }
 
+TimeDelta RandomWalkCrossTraffic::GetProcessInterval() const {
+  return config_.min_packet_interval;
+}
+
 DataRate RandomWalkCrossTraffic::TrafficRate() const {
   RTC_DCHECK_RUN_ON(&sequence_checker_);
   return config_.peak_rate * intensity_;
@@ -70,8 +74,9 @@
       32);
 }
 
-PulsedPeaksCrossTraffic::PulsedPeaksCrossTraffic(PulsedPeaksConfig config,
-                                                 TrafficRoute* traffic_route)
+PulsedPeaksCrossTraffic::PulsedPeaksCrossTraffic(
+    PulsedPeaksConfig config,
+    CrossTrafficRoute* traffic_route)
     : config_(config), traffic_route_(traffic_route) {
   sequence_checker_.Detach();
 }
@@ -102,6 +107,10 @@
   }
 }
 
+TimeDelta PulsedPeaksCrossTraffic::GetProcessInterval() const {
+  return config_.min_packet_interval;
+}
+
 DataRate PulsedPeaksCrossTraffic::TrafficRate() const {
   RTC_DCHECK_RUN_ON(&sequence_checker_);
   return sending_ ? config_.peak_rate : DataRate::Zero();
@@ -240,21 +249,13 @@
   }
 }
 
-FakeTcpCrossTraffic::FakeTcpCrossTraffic(Clock* clock,
-                                         FakeTcpConfig config,
+FakeTcpCrossTraffic::FakeTcpCrossTraffic(FakeTcpConfig config,
                                          EmulatedRoute* send_route,
                                          EmulatedRoute* ret_route)
-    : clock_(clock), conf_(config), route_(this, send_route, ret_route) {}
+    : conf_(config), route_(this, send_route, ret_route) {}
 
-void FakeTcpCrossTraffic::Start(TaskQueueBase* task_queue) {
-  repeating_task_handle_ = RepeatingTaskHandle::Start(task_queue, [this] {
-    Process(clock_->CurrentTime());
-    return conf_.process_interval;
-  });
-}
-
-void FakeTcpCrossTraffic::Stop() {
-  repeating_task_handle_.Stop();
+TimeDelta FakeTcpCrossTraffic::GetProcessInterval() const {
+  return conf_.process_interval;
 }
 
 void FakeTcpCrossTraffic::Process(Timestamp at_time) {
diff --git a/test/network/cross_traffic.h b/test/network/cross_traffic.h
index 942b863..9ed41a9 100644
--- a/test/network/cross_traffic.h
+++ b/test/network/cross_traffic.h
@@ -15,41 +15,34 @@
 #include <map>
 #include <memory>
 
+#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/random.h"
 #include "rtc_base/synchronization/sequence_checker.h"
-#include "test/network/traffic_route.h"
+#include "test/network/network_emulation.h"
 #include "test/scenario/column_printer.h"
 
 namespace webrtc {
 namespace test {
 
-struct RandomWalkConfig {
-  int random_seed = 1;
-  DataRate peak_rate = DataRate::KilobitsPerSec(100);
-  DataSize min_packet_size = DataSize::Bytes(200);
-  TimeDelta min_packet_interval = TimeDelta::Millis(1);
-  TimeDelta update_interval = TimeDelta::Millis(200);
-  double variance = 0.6;
-  double bias = -0.1;
-};
-
-class RandomWalkCrossTraffic {
+class RandomWalkCrossTraffic final : public CrossTrafficGenerator {
  public:
-  RandomWalkCrossTraffic(RandomWalkConfig config, TrafficRoute* traffic_route);
+  RandomWalkCrossTraffic(RandomWalkConfig config,
+                         CrossTrafficRoute* traffic_route);
   ~RandomWalkCrossTraffic();
 
-  void Process(Timestamp at_time);
+  void Process(Timestamp at_time) override;
+  TimeDelta GetProcessInterval() const override;
   DataRate TrafficRate() const;
   ColumnPrinter StatsPrinter();
 
  private:
   SequenceChecker sequence_checker_;
   const RandomWalkConfig config_;
-  TrafficRoute* const traffic_route_ RTC_PT_GUARDED_BY(sequence_checker_);
+  CrossTrafficRoute* const traffic_route_ RTC_PT_GUARDED_BY(sequence_checker_);
   webrtc::Random random_ RTC_GUARDED_BY(sequence_checker_);
 
   Timestamp last_process_time_ RTC_GUARDED_BY(sequence_checker_) =
@@ -62,28 +55,21 @@
   DataSize pending_size_ RTC_GUARDED_BY(sequence_checker_) = DataSize::Zero();
 };
 
-struct PulsedPeaksConfig {
-  DataRate peak_rate = DataRate::KilobitsPerSec(100);
-  DataSize min_packet_size = DataSize::Bytes(200);
-  TimeDelta min_packet_interval = TimeDelta::Millis(1);
-  TimeDelta send_duration = TimeDelta::Millis(100);
-  TimeDelta hold_duration = TimeDelta::Millis(2000);
-};
-
-class PulsedPeaksCrossTraffic {
+class PulsedPeaksCrossTraffic final : public CrossTrafficGenerator {
  public:
   PulsedPeaksCrossTraffic(PulsedPeaksConfig config,
-                          TrafficRoute* traffic_route);
+                          CrossTrafficRoute* traffic_route);
   ~PulsedPeaksCrossTraffic();
 
-  void Process(Timestamp at_time);
+  void Process(Timestamp at_time) override;
+  TimeDelta GetProcessInterval() const override;
   DataRate TrafficRate() const;
   ColumnPrinter StatsPrinter();
 
  private:
   SequenceChecker sequence_checker_;
   const PulsedPeaksConfig config_;
-  TrafficRoute* const traffic_route_ RTC_PT_GUARDED_BY(sequence_checker_);
+  CrossTrafficRoute* const traffic_route_ RTC_PT_GUARDED_BY(sequence_checker_);
 
   Timestamp last_update_time_ RTC_GUARDED_BY(sequence_checker_) =
       Timestamp::MinusInfinity();
@@ -149,23 +135,17 @@
   TimeDelta last_rtt_ = TimeDelta::Zero();
 };
 
-struct FakeTcpConfig {
-  DataSize packet_size = DataSize::Bytes(1200);
-  DataSize send_limit = DataSize::PlusInfinity();
-  TimeDelta process_interval = TimeDelta::Millis(200);
-  TimeDelta packet_timeout = TimeDelta::Seconds(1);
-};
-
 class FakeTcpCrossTraffic
-    : public TwoWayFakeTrafficRoute<int, int>::TrafficHandlerInterface {
+    : public TwoWayFakeTrafficRoute<int, int>::TrafficHandlerInterface,
+      public CrossTrafficGenerator {
  public:
-  FakeTcpCrossTraffic(Clock* clock,
-                      FakeTcpConfig config,
+  FakeTcpCrossTraffic(FakeTcpConfig config,
                       EmulatedRoute* send_route,
                       EmulatedRoute* ret_route);
-  void Start(TaskQueueBase* task_queue);
-  void Stop();
-  void Process(Timestamp at_time);
+
+  TimeDelta GetProcessInterval() const override;
+  void Process(Timestamp at_time) override;
+
   void OnRequest(int sequence_number, Timestamp at_time) override;
   void OnResponse(int sequence_number, Timestamp at_time) override;
 
@@ -174,7 +154,6 @@
   void SendPackets(Timestamp at_time);
 
  private:
-  Clock* const clock_;
   const FakeTcpConfig conf_;
   TwoWayFakeTrafficRoute<int, int> route_;
 
@@ -187,7 +166,6 @@
   Timestamp last_reduction_time_ = Timestamp::MinusInfinity();
   TimeDelta last_rtt_ = TimeDelta::Zero();
   DataSize total_sent_ = DataSize::Zero();
-  RepeatingTaskHandle repeating_task_handle_;
 };
 
 }  // namespace test
diff --git a/test/network/cross_traffic_unittest.cc b/test/network/cross_traffic_unittest.cc
index c8d848f..c8191a3 100644
--- a/test/network/cross_traffic_unittest.cc
+++ b/test/network/cross_traffic_unittest.cc
@@ -25,6 +25,7 @@
 #include "test/gmock.h"
 #include "test/gtest.h"
 #include "test/network/network_emulation_manager.h"
+#include "test/network/traffic_route.h"
 #include "test/time_controller/simulated_time_controller.h"
 
 namespace webrtc {
@@ -61,7 +62,8 @@
 
 TEST(CrossTrafficTest, TriggerPacketBurst) {
   TrafficCounterFixture fixture;
-  TrafficRoute traffic(&fixture.clock, &fixture.counter, &fixture.endpoint);
+  CrossTrafficRouteImpl traffic(&fixture.clock, &fixture.counter,
+                                &fixture.endpoint);
   traffic.TriggerPacketBurst(100, 1000);
 
   EXPECT_EQ(fixture.counter.packets_count_, 100);
@@ -70,7 +72,8 @@
 
 TEST(CrossTrafficTest, PulsedPeaksCrossTraffic) {
   TrafficCounterFixture fixture;
-  TrafficRoute traffic(&fixture.clock, &fixture.counter, &fixture.endpoint);
+  CrossTrafficRouteImpl traffic(&fixture.clock, &fixture.counter,
+                                &fixture.endpoint);
 
   PulsedPeaksConfig config;
   config.peak_rate = DataRate::KilobitsPerSec(1000);
@@ -95,7 +98,8 @@
 
 TEST(CrossTrafficTest, RandomWalkCrossTraffic) {
   TrafficCounterFixture fixture;
-  TrafficRoute traffic(&fixture.clock, &fixture.counter, &fixture.endpoint);
+  CrossTrafficRouteImpl traffic(&fixture.clock, &fixture.counter,
+                                &fixture.endpoint);
 
   RandomWalkConfig config;
   config.peak_rate = DataRate::KilobitsPerSec(1000);
diff --git a/test/network/network_emulation_manager.cc b/test/network/network_emulation_manager.cc
index 57706fc..9ffe9e3 100644
--- a/test/network/network_emulation_manager.cc
+++ b/test/network/network_emulation_manager.cc
@@ -18,6 +18,7 @@
 #include "call/simulated_network.h"
 #include "rtc_base/fake_network.h"
 #include "test/network/emulated_turn_server.h"
+#include "test/network/traffic_route.h"
 #include "test/time_controller/real_time_controller.h"
 #include "test/time_controller/simulated_time_controller.h"
 
@@ -175,7 +176,19 @@
       RTC_FROM_HERE);
 }
 
-TrafficRoute* NetworkEmulationManagerImpl::CreateTrafficRoute(
+TcpMessageRoute* NetworkEmulationManagerImpl::CreateTcpRoute(
+    EmulatedRoute* send_route,
+    EmulatedRoute* ret_route) {
+  auto tcp_route = std::make_unique<TcpMessageRouteImpl>(
+      clock_, task_queue_.Get(), send_route, ret_route);
+  auto* route_ptr = tcp_route.get();
+  task_queue_.PostTask([this, tcp_route = std::move(tcp_route)]() mutable {
+    tcp_message_routes_.push_back(std::move(tcp_route));
+  });
+  return route_ptr;
+}
+
+CrossTrafficRoute* NetworkEmulationManagerImpl::CreateCrossTrafficRoute(
     const std::vector<EmulatedNetworkNode*>& via_nodes) {
   RTC_CHECK(!via_nodes.empty());
   EmulatedEndpoint* endpoint = CreateEndpoint(EmulatedEndpointConfig());
@@ -189,88 +202,40 @@
   }
   cur_node->router()->SetReceiver(endpoint->GetPeerLocalAddress(), endpoint);
 
-  std::unique_ptr<TrafficRoute> traffic_route =
-      std::make_unique<TrafficRoute>(clock_, via_nodes[0], endpoint);
-  TrafficRoute* out = traffic_route.get();
+  std::unique_ptr<CrossTrafficRoute> traffic_route =
+      std::make_unique<CrossTrafficRouteImpl>(clock_, via_nodes[0], endpoint);
+  CrossTrafficRoute* out = traffic_route.get();
   traffic_routes_.push_back(std::move(traffic_route));
   return out;
 }
 
-RandomWalkCrossTraffic*
-NetworkEmulationManagerImpl::CreateRandomWalkCrossTraffic(
-    TrafficRoute* traffic_route,
-    RandomWalkConfig config) {
-  auto traffic =
-      std::make_unique<RandomWalkCrossTraffic>(config, traffic_route);
-  RandomWalkCrossTraffic* out = traffic.get();
+CrossTrafficGenerator* NetworkEmulationManagerImpl::StartCrossTraffic(
+    std::unique_ptr<CrossTrafficGenerator> generator) {
+  CrossTrafficGenerator* out = generator.get();
+  task_queue_.PostTask([this, generator = std::move(generator)]() mutable {
+    auto* generator_ptr = generator.get();
 
-  task_queue_.PostTask(
-      [this, config, traffic = std::move(traffic)]() mutable {
-        auto* traffic_ptr = traffic.get();
-        random_cross_traffics_.push_back(std::move(traffic));
-        RepeatingTaskHandle::Start(task_queue_.Get(),
-                                   [this, config, traffic_ptr] {
-                                     traffic_ptr->Process(Now());
-                                     return config.min_packet_interval;
-                                   });
-      });
-  return out;
-}
+    auto repeating_task_handle =
+        RepeatingTaskHandle::Start(task_queue_.Get(), [this, generator_ptr] {
+          generator_ptr->Process(Now());
+          return generator_ptr->GetProcessInterval();
+        });
 
-PulsedPeaksCrossTraffic*
-NetworkEmulationManagerImpl::CreatePulsedPeaksCrossTraffic(
-    TrafficRoute* traffic_route,
-    PulsedPeaksConfig config) {
-  auto traffic =
-      std::make_unique<PulsedPeaksCrossTraffic>(config, traffic_route);
-  PulsedPeaksCrossTraffic* out = traffic.get();
-  task_queue_.PostTask(
-      [this, config, traffic = std::move(traffic)]() mutable {
-        auto* traffic_ptr = traffic.get();
-        pulsed_cross_traffics_.push_back(std::move(traffic));
-        RepeatingTaskHandle::Start(task_queue_.Get(),
-                                   [this, config, traffic_ptr] {
-                                     traffic_ptr->Process(Now());
-                                     return config.min_packet_interval;
-                                   });
-      });
-  return out;
-}
-
-FakeTcpCrossTraffic* NetworkEmulationManagerImpl::StartFakeTcpCrossTraffic(
-    std::vector<EmulatedNetworkNode*> send_link,
-    std::vector<EmulatedNetworkNode*> ret_link,
-    FakeTcpConfig config) {
-  auto traffic = std::make_unique<FakeTcpCrossTraffic>(
-      clock_, config, CreateRoute(send_link), CreateRoute(ret_link));
-  auto* traffic_ptr = traffic.get();
-  task_queue_.PostTask([this, traffic = std::move(traffic)]() mutable {
-    traffic->Start(task_queue_.Get());
-    tcp_cross_traffics_.push_back(std::move(traffic));
+    cross_traffics_.push_back(CrossTrafficSource(
+        std::move(generator), std::move(repeating_task_handle)));
   });
-  return traffic_ptr;
-}
-
-TcpMessageRoute* NetworkEmulationManagerImpl::CreateTcpRoute(
-    EmulatedRoute* send_route,
-    EmulatedRoute* ret_route) {
-  auto tcp_route = std::make_unique<TcpMessageRouteImpl>(
-      clock_, task_queue_.Get(), send_route, ret_route);
-  auto* route_ptr = tcp_route.get();
-  task_queue_.PostTask([this, tcp_route = std::move(tcp_route)]() mutable {
-    tcp_message_routes_.push_back(std::move(tcp_route));
-  });
-  return route_ptr;
+  return out;
 }
 
 void NetworkEmulationManagerImpl::StopCrossTraffic(
-    FakeTcpCrossTraffic* traffic) {
+    CrossTrafficGenerator* generator) {
   task_queue_.PostTask([=]() {
-    traffic->Stop();
-    tcp_cross_traffics_.remove_if(
-        [=](const std::unique_ptr<FakeTcpCrossTraffic>& ptr) {
-          return ptr.get() == traffic;
-        });
+    auto it = std::find_if(cross_traffics_.begin(), cross_traffics_.end(),
+                           [=](const CrossTrafficSource& el) {
+                             return el.first.get() == generator;
+                           });
+    it->second.Stop();
+    cross_traffics_.erase(it);
   });
 }
 
diff --git a/test/network/network_emulation_manager.h b/test/network/network_emulation_manager.h
index b2b41b3..d6e8786 100644
--- a/test/network/network_emulation_manager.h
+++ b/test/network/network_emulation_manager.h
@@ -34,7 +34,6 @@
 #include "test/network/emulated_turn_server.h"
 #include "test/network/fake_network_socket_server.h"
 #include "test/network/network_emulation.h"
-#include "test/network/traffic_route.h"
 
 namespace webrtc {
 namespace test {
@@ -64,23 +63,15 @@
 
   void ClearRoute(EmulatedRoute* route) override;
 
-  TrafficRoute* CreateTrafficRoute(
-      const std::vector<EmulatedNetworkNode*>& via_nodes);
-  RandomWalkCrossTraffic* CreateRandomWalkCrossTraffic(
-      TrafficRoute* traffic_route,
-      RandomWalkConfig config);
-  PulsedPeaksCrossTraffic* CreatePulsedPeaksCrossTraffic(
-      TrafficRoute* traffic_route,
-      PulsedPeaksConfig config);
-  FakeTcpCrossTraffic* StartFakeTcpCrossTraffic(
-      std::vector<EmulatedNetworkNode*> send_link,
-      std::vector<EmulatedNetworkNode*> ret_link,
-      FakeTcpConfig config);
-
   TcpMessageRoute* CreateTcpRoute(EmulatedRoute* send_route,
                                   EmulatedRoute* ret_route) override;
 
-  void StopCrossTraffic(FakeTcpCrossTraffic* traffic);
+  CrossTrafficRoute* CreateCrossTrafficRoute(
+      const std::vector<EmulatedNetworkNode*>& via_nodes) override;
+
+  CrossTrafficGenerator* StartCrossTraffic(
+      std::unique_ptr<CrossTrafficGenerator> generator) override;
+  void StopCrossTraffic(CrossTrafficGenerator* generator) override;
 
   EmulatedNetworkManagerInterface* CreateEmulatedNetworkManagerInterface(
       const std::vector<EmulatedEndpoint*>& endpoints) override;
@@ -97,6 +88,9 @@
       EmulatedTURNServerConfig config) override;
 
  private:
+  using CrossTrafficSource =
+      std::pair<std::unique_ptr<CrossTrafficGenerator>, RepeatingTaskHandle>;
+
   absl::optional<rtc::IPAddress> GetNextIPv4Address();
   const std::unique_ptr<TimeController> time_controller_;
   Clock* const clock_;
@@ -111,10 +105,8 @@
   std::vector<std::unique_ptr<EmulatedEndpoint>> endpoints_;
   std::vector<std::unique_ptr<EmulatedNetworkNode>> network_nodes_;
   std::vector<std::unique_ptr<EmulatedRoute>> routes_;
-  std::vector<std::unique_ptr<TrafficRoute>> traffic_routes_;
-  std::vector<std::unique_ptr<RandomWalkCrossTraffic>> random_cross_traffics_;
-  std::vector<std::unique_ptr<PulsedPeaksCrossTraffic>> pulsed_cross_traffics_;
-  std::list<std::unique_ptr<FakeTcpCrossTraffic>> tcp_cross_traffics_;
+  std::vector<std::unique_ptr<CrossTrafficRoute>> traffic_routes_;
+  std::vector<CrossTrafficSource> cross_traffics_;
   std::list<std::unique_ptr<TcpMessageRouteImpl>> tcp_message_routes_;
   std::vector<std::unique_ptr<EndpointsContainer>> endpoints_containers_;
   std::vector<std::unique_ptr<EmulatedNetworkManager>> network_managers_;
diff --git a/test/network/traffic_route.cc b/test/network/traffic_route.cc
index 9858633..d42d8e2 100644
--- a/test/network/traffic_route.cc
+++ b/test/network/traffic_route.cc
@@ -53,9 +53,10 @@
 
 }  // namespace
 
-TrafficRoute::TrafficRoute(Clock* clock,
-                           EmulatedNetworkReceiverInterface* receiver,
-                           EmulatedEndpoint* endpoint)
+CrossTrafficRouteImpl::CrossTrafficRouteImpl(
+    Clock* clock,
+    EmulatedNetworkReceiverInterface* receiver,
+    EmulatedEndpoint* endpoint)
     : clock_(clock), receiver_(receiver), endpoint_(endpoint) {
   null_receiver_ = std::make_unique<NullReceiver>();
   absl::optional<uint16_t> port =
@@ -63,16 +64,17 @@
   RTC_DCHECK(port);
   null_receiver_port_ = port.value();
 }
-TrafficRoute::~TrafficRoute() = default;
+CrossTrafficRouteImpl::~CrossTrafficRouteImpl() = default;
 
-void TrafficRoute::TriggerPacketBurst(size_t num_packets, size_t packet_size) {
+void CrossTrafficRouteImpl::TriggerPacketBurst(size_t num_packets,
+                                               size_t packet_size) {
   for (size_t i = 0; i < num_packets; ++i) {
     SendPacket(packet_size);
   }
 }
 
-void TrafficRoute::NetworkDelayedAction(size_t packet_size,
-                                        std::function<void()> action) {
+void CrossTrafficRouteImpl::NetworkDelayedAction(size_t packet_size,
+                                                 std::function<void()> action) {
   auto action_receiver = std::make_unique<ActionReceiver>(action, endpoint_);
   absl::optional<uint16_t> port =
       endpoint_->BindReceiver(0, action_receiver.get());
@@ -82,11 +84,11 @@
   SendPacket(packet_size, port.value());
 }
 
-void TrafficRoute::SendPacket(size_t packet_size) {
+void CrossTrafficRouteImpl::SendPacket(size_t packet_size) {
   SendPacket(packet_size, null_receiver_port_);
 }
 
-void TrafficRoute::SendPacket(size_t packet_size, uint16_t dest_port) {
+void CrossTrafficRouteImpl::SendPacket(size_t packet_size, uint16_t dest_port) {
   rtc::CopyOnWriteBuffer data(packet_size);
   std::fill_n(data.MutableData(), data.size(), 0);
   receiver_->OnPacketReceived(EmulatedIpPacket(
diff --git a/test/network/traffic_route.h b/test/network/traffic_route.h
index 1bb34c6..513f487 100644
--- a/test/network/traffic_route.h
+++ b/test/network/traffic_route.h
@@ -14,6 +14,7 @@
 #include <memory>
 #include <vector>
 
+#include "api/test/network_emulation_manager.h"
 #include "rtc_base/copy_on_write_buffer.h"
 #include "system_wrappers/include/clock.h"
 #include "test/network/network_emulation.h"
@@ -23,19 +24,20 @@
 
 // Represents the endpoint for cross traffic that is going through the network.
 // It can be used to emulate unexpected network load.
-class TrafficRoute {
+class CrossTrafficRouteImpl final : public CrossTrafficRoute {
  public:
-  TrafficRoute(Clock* clock,
-               EmulatedNetworkReceiverInterface* receiver,
-               EmulatedEndpoint* endpoint);
-  ~TrafficRoute();
+  CrossTrafficRouteImpl(Clock* clock,
+                        EmulatedNetworkReceiverInterface* receiver,
+                        EmulatedEndpoint* endpoint);
+  ~CrossTrafficRouteImpl();
 
   // Triggers sending of dummy packets with size |packet_size| bytes.
-  void TriggerPacketBurst(size_t num_packets, size_t packet_size);
+  void TriggerPacketBurst(size_t num_packets, size_t packet_size) override;
   // Sends a packet over the nodes and runs |action| when it has been delivered.
-  void NetworkDelayedAction(size_t packet_size, std::function<void()> action);
+  void NetworkDelayedAction(size_t packet_size,
+                            std::function<void()> action) override;
 
-  void SendPacket(size_t packet_size);
+  void SendPacket(size_t packet_size) override;
 
  private:
   void SendPacket(size_t packet_size, uint16_t dest_port);
diff --git a/test/peer_scenario/peer_scenario.cc b/test/peer_scenario/peer_scenario.cc
index c3443aa..ea959c9 100644
--- a/test/peer_scenario/peer_scenario.cc
+++ b/test/peer_scenario/peer_scenario.cc
@@ -77,8 +77,8 @@
     PeerScenarioClient* callee,
     std::vector<EmulatedNetworkNode*> send_link,
     std::vector<EmulatedNetworkNode*> ret_link) {
-  return SignalingRoute(caller, callee, net_.CreateTrafficRoute(send_link),
-                        net_.CreateTrafficRoute(ret_link));
+  return SignalingRoute(caller, callee, net_.CreateCrossTrafficRoute(send_link),
+                        net_.CreateCrossTrafficRoute(ret_link));
 }
 
 void PeerScenario::SimpleConnection(
diff --git a/test/peer_scenario/signaling_route.cc b/test/peer_scenario/signaling_route.cc
index 2e0213d..908d405 100644
--- a/test/peer_scenario/signaling_route.cc
+++ b/test/peer_scenario/signaling_route.cc
@@ -41,7 +41,7 @@
 
 void StartIceSignalingForRoute(PeerScenarioClient* caller,
                                PeerScenarioClient* callee,
-                               TrafficRoute* send_route) {
+                               CrossTrafficRoute* send_route) {
   caller->handlers()->on_ice_candidate.push_back(
       [=](const IceCandidateInterface* candidate) {
         IceMessage msg(candidate);
@@ -56,8 +56,8 @@
 void StartSdpNegotiation(
     PeerScenarioClient* caller,
     PeerScenarioClient* callee,
-    TrafficRoute* send_route,
-    TrafficRoute* ret_route,
+    CrossTrafficRoute* send_route,
+    CrossTrafficRoute* ret_route,
     std::function<void(SessionDescriptionInterface* offer)> munge_offer,
     std::function<void(SessionDescriptionInterface*)> modify_offer,
     std::function<void(const SessionDescriptionInterface&)> exchange_finished) {
@@ -80,8 +80,8 @@
 
 SignalingRoute::SignalingRoute(PeerScenarioClient* caller,
                                PeerScenarioClient* callee,
-                               TrafficRoute* send_route,
-                               TrafficRoute* ret_route)
+                               CrossTrafficRoute* send_route,
+                               CrossTrafficRoute* ret_route)
     : caller_(caller),
       callee_(callee),
       send_route_(send_route),
diff --git a/test/peer_scenario/signaling_route.h b/test/peer_scenario/signaling_route.h
index 7434551..021fc49 100644
--- a/test/peer_scenario/signaling_route.h
+++ b/test/peer_scenario/signaling_route.h
@@ -25,8 +25,8 @@
  public:
   SignalingRoute(PeerScenarioClient* caller,
                  PeerScenarioClient* callee,
-                 TrafficRoute* send_route,
-                 TrafficRoute* ret_route);
+                 CrossTrafficRoute* send_route,
+                 CrossTrafficRoute* ret_route);
 
   void StartIceSignaling();
 
@@ -57,8 +57,8 @@
  private:
   PeerScenarioClient* const caller_;
   PeerScenarioClient* const callee_;
-  TrafficRoute* const send_route_;
-  TrafficRoute* const ret_route_;
+  CrossTrafficRoute* const send_route_;
+  CrossTrafficRoute* const ret_route_;
 };
 
 }  // namespace test
diff --git a/test/scenario/BUILD.gn b/test/scenario/BUILD.gn
index f5c22fc..ede93c6 100644
--- a/test/scenario/BUILD.gn
+++ b/test/scenario/BUILD.gn
@@ -174,6 +174,8 @@
     ]
     deps = [
       ":scenario",
+      "../../api/test/network_emulation",
+      "../../api/test/network_emulation:create_cross_traffic",
       "../../logging:mocks",
       "../../rtc_base:checks",
       "../../rtc_base:rtc_base_approved",
diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc
index c1c664a..239aad9 100644
--- a/test/scenario/scenario.cc
+++ b/test/scenario/scenario.cc
@@ -198,7 +198,7 @@
 void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
                                   size_t num_packets,
                                   size_t packet_size) {
-  network_manager_.CreateTrafficRoute(over_nodes)
+  network_manager_.CreateCrossTrafficRoute(over_nodes)
       ->TriggerPacketBurst(num_packets, packet_size);
 }
 
@@ -206,7 +206,7 @@
     std::vector<EmulatedNetworkNode*> over_nodes,
     size_t packet_size,
     std::function<void()> action) {
-  network_manager_.CreateTrafficRoute(over_nodes)
+  network_manager_.CreateCrossTrafficRoute(over_nodes)
       ->NetworkDelayedAction(packet_size, action);
 }
 
diff --git a/test/scenario/scenario_unittest.cc b/test/scenario/scenario_unittest.cc
index 177ac27..fc370fb 100644
--- a/test/scenario/scenario_unittest.cc
+++ b/test/scenario/scenario_unittest.cc
@@ -11,6 +11,8 @@
 
 #include <atomic>
 
+#include "api/test/network_emulation/create_cross_traffic.h"
+#include "api/test/network_emulation/cross_traffic.h"
 #include "test/field_trial.h"
 #include "test/gtest.h"
 #include "test/logging/memory_log_writer.h"
@@ -44,8 +46,8 @@
   s.CreateAudioStream(route->reverse(), audio_stream_config);
 
   RandomWalkConfig cross_traffic_config;
-  s.net()->CreateRandomWalkCrossTraffic(
-      s.net()->CreateTrafficRoute({alice_net}), cross_traffic_config);
+  s.net()->StartCrossTraffic(CreateRandomWalkCrossTraffic(
+      s.net()->CreateCrossTrafficRoute({alice_net}), cross_traffic_config));
 
   s.NetworkDelayedAction({alice_net, bob_net}, 100,
                          [&packet_received] { packet_received = true; });
diff --git a/test/scenario/video_stream_unittest.cc b/test/scenario/video_stream_unittest.cc
index 52be3f8..95936c7 100644
--- a/test/scenario/video_stream_unittest.cc
+++ b/test/scenario/video_stream_unittest.cc
@@ -9,6 +9,8 @@
  */
 #include <atomic>
 
+#include "api/test/network_emulation/create_cross_traffic.h"
+#include "api/test/network_emulation/cross_traffic.h"
 #include "test/field_trial.h"
 #include "test/gtest.h"
 #include "test/scenario/scenario.h"
@@ -217,8 +219,9 @@
 
   // Trigger cross traffic, run until we have seen 3 consecutive
   // seconds with no VGA frames due to reduced available bandwidth.
-  auto cross_traffic =
-      s.net()->StartFakeTcpCrossTraffic(send_net, ret_net, FakeTcpConfig());
+  auto cross_traffic = s.net()->StartCrossTraffic(CreateFakeTcpCrossTraffic(
+      s.net()->CreateRoute(send_net), s.net()->CreateRoute(ret_net),
+      FakeTcpConfig()));
 
   int num_seconds_without_vga = 0;
   int num_iterations = 0;