Adds support to change transport routes in Scenario tests.

This CL makes it possible to change transport routes while running
a scenario based test.

To make this possible in a consistent manner, the scenario test
framework is modified to only allow shared transport for all streams
between two CallClients. This is what typically is done in practice and
it is quite complex to even reason about the implications of using
mixed transports for a single call.

Bug: webrtc:9718
Change-Id: Ib836928feed98aa2bbbe0295e158157a6518348b
Reviewed-on: https://webrtc-review.googlesource.com/c/107200
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25287}
diff --git a/test/scenario/audio_stream.cc b/test/scenario/audio_stream.cc
index 21acebb..8871728 100644
--- a/test/scenario/audio_stream.cc
+++ b/test/scenario/audio_stream.cc
@@ -106,9 +106,7 @@
     }
     if (field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")) {
       TimeDelta min_frame_length = config.encoder.initial_frame_length;
-      ;
       TimeDelta max_frame_length = config.encoder.initial_frame_length;
-      ;
       if (field_trial::IsEnabled("WebRTC-Audio-FrameLengthAdaptation") &&
           !config.adapt.frame.min_rate_for_20_ms.IsZero()) {
         if (!config.adapt.frame.min_rate_for_60_ms.IsZero()) {
@@ -118,7 +116,8 @@
         }
       }
       DataSize rtp_overhead = DataSize::bytes(12);
-      DataSize total_overhead = config.stream.packet_overhead + rtp_overhead;
+      DataSize total_overhead =
+          sender_->transport_.packet_overhead() + rtp_overhead;
       min_rate += total_overhead / max_frame_length;
       max_rate += total_overhead / min_frame_length;
     }
@@ -138,7 +137,7 @@
   send_stream_ = sender_->call_->CreateAudioSendStream(send_config);
   if (field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")) {
     sender->call_->OnAudioTransportOverheadChanged(
-        config.stream.packet_overhead.bytes());
+        sender_->transport_.packet_overhead().bytes());
   }
 }
 
@@ -150,15 +149,6 @@
   send_stream_->Start();
 }
 
-bool SendAudioStream::TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                                       uint64_t receiver,
-                                       Timestamp at_time) {
-  // Removes added overhead before delivering RTCP packet to sender.
-  RTC_DCHECK_GE(packet.size(), config_.stream.packet_overhead.bytes());
-  packet.SetSize(packet.size() - config_.stream.packet_overhead.bytes());
-  sender_->DeliverPacket(MediaType::AUDIO, packet, at_time);
-  return true;
-}
 ReceiveAudioStream::ReceiveAudioStream(
     CallClient* receiver,
     AudioStreamConfig config,
@@ -170,6 +160,7 @@
   recv_config.rtp.local_ssrc = CallTest::kReceiverLocalAudioSsrc;
   recv_config.rtcp_send_transport = feedback_transport;
   recv_config.rtp.remote_ssrc = send_stream->ssrc_;
+  receiver->ssrc_media_types_[recv_config.rtp.remote_ssrc] = MediaType::AUDIO;
   if (config.stream.in_bandwidth_estimation) {
     recv_config.rtp.transport_cc = true;
     recv_config.rtp.extensions = {
@@ -185,49 +176,21 @@
   receiver_->call_->DestroyAudioReceiveStream(receive_stream_);
 }
 
-bool ReceiveAudioStream::TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                                          uint64_t receiver,
-                                          Timestamp at_time) {
-  RTC_DCHECK_GE(packet.size(), config_.stream.packet_overhead.bytes());
-  packet.SetSize(packet.size() - config_.stream.packet_overhead.bytes());
-  receiver_->DeliverPacket(MediaType::AUDIO, packet, at_time);
-  return true;
-}
-
 AudioStreamPair::~AudioStreamPair() = default;
 
 AudioStreamPair::AudioStreamPair(
     CallClient* sender,
-    std::vector<NetworkNode*> send_link,
-    uint64_t send_receiver_id,
     rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
     CallClient* receiver,
-    std::vector<NetworkNode*> return_link,
-    uint64_t return_receiver_id,
     rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
     AudioStreamConfig config)
     : config_(config),
-      send_link_(send_link),
-      return_link_(return_link),
-      send_transport_(sender,
-                      send_link.front(),
-                      send_receiver_id,
-                      config.stream.packet_overhead),
-      return_transport_(receiver,
-                        return_link.front(),
-                        return_receiver_id,
-                        config.stream.packet_overhead),
-      send_stream_(sender, config, encoder_factory, &send_transport_),
+      send_stream_(sender, config, encoder_factory, &sender->transport_),
       receive_stream_(receiver,
                       config,
                       &send_stream_,
                       decoder_factory,
-                      &return_transport_) {
-  NetworkNode::Route(send_transport_.ReceiverId(), send_link_,
-                     &receive_stream_);
-  NetworkNode::Route(return_transport_.ReceiverId(), return_link_,
-                     &send_stream_);
-}
+                      &receiver->transport_) {}
 
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/scenario/audio_stream.h b/test/scenario/audio_stream.h
index 17b8bc3..06a91db 100644
--- a/test/scenario/audio_stream.h
+++ b/test/scenario/audio_stream.h
@@ -24,7 +24,7 @@
 
 // SendAudioStream represents sending of audio. It can be used for starting the
 // stream if neccessary.
-class SendAudioStream : public NetworkReceiverInterface {
+class SendAudioStream {
  public:
   RTC_DISALLOW_COPY_AND_ASSIGN(SendAudioStream);
   ~SendAudioStream();
@@ -38,11 +38,6 @@
                   AudioStreamConfig config,
                   rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
                   Transport* send_transport);
-  // Handles RTCP feedback for this stream.
-  bool TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                        uint64_t receiver,
-                        Timestamp at_time) override;
-
   AudioSendStream* send_stream_ = nullptr;
   CallClient* const sender_;
   const AudioStreamConfig config_;
@@ -50,7 +45,7 @@
 };
 
 // ReceiveAudioStream represents an audio receiver. It can't be used directly.
-class ReceiveAudioStream : public NetworkReceiverInterface {
+class ReceiveAudioStream {
  public:
   RTC_DISALLOW_COPY_AND_ASSIGN(ReceiveAudioStream);
   ~ReceiveAudioStream();
@@ -63,9 +58,6 @@
                      SendAudioStream* send_stream,
                      rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
                      Transport* feedback_transport);
-  bool TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                        uint64_t receiver,
-                        Timestamp at_time) override;
   AudioReceiveStream* receive_stream_ = nullptr;
   CallClient* const receiver_;
   const AudioStreamConfig config_;
@@ -84,23 +76,13 @@
  private:
   friend class Scenario;
   AudioStreamPair(CallClient* sender,
-                  std::vector<NetworkNode*> send_link,
-                  uint64_t send_receiver_id,
                   rtc::scoped_refptr<AudioEncoderFactory> encoder_factory,
-
                   CallClient* receiver,
-                  std::vector<NetworkNode*> return_link,
-                  uint64_t return_receiver_id,
                   rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
                   AudioStreamConfig config);
 
  private:
   const AudioStreamConfig config_;
-  std::vector<NetworkNode*> send_link_;
-  std::vector<NetworkNode*> return_link_;
-  NetworkNodeTransport send_transport_;
-  NetworkNodeTransport return_transport_;
-
   SendAudioStream send_stream_;
   ReceiveAudioStream receive_stream_;
 };
diff --git a/test/scenario/call_client.cc b/test/scenario/call_client.cc
index 47cc3bc..92c582e 100644
--- a/test/scenario/call_client.cc
+++ b/test/scenario/call_client.cc
@@ -21,6 +21,39 @@
 namespace test {
 namespace {
 const char* kPriorityStreamId = "priority-track";
+
+CallClientFakeAudio InitAudio() {
+  CallClientFakeAudio setup;
+  auto capturer = TestAudioDeviceModule::CreatePulsedNoiseCapturer(256, 48000);
+  auto renderer = TestAudioDeviceModule::CreateDiscardRenderer(48000);
+  setup.fake_audio_device = TestAudioDeviceModule::CreateTestAudioDeviceModule(
+      std::move(capturer), std::move(renderer), 1.f);
+  setup.apm = AudioProcessingBuilder().Create();
+  setup.fake_audio_device->Init();
+  AudioState::Config audio_state_config;
+  audio_state_config.audio_mixer = AudioMixerImpl::Create();
+  audio_state_config.audio_processing = setup.apm;
+  audio_state_config.audio_device_module = setup.fake_audio_device;
+  setup.audio_state = AudioState::Create(audio_state_config);
+  setup.fake_audio_device->RegisterAudioCallback(
+      setup.audio_state->audio_transport());
+  return setup;
+}
+
+Call* CreateCall(CallClientConfig config,
+                 LoggingNetworkControllerFactory* network_controller_factory_,
+                 rtc::scoped_refptr<AudioState> audio_state) {
+  CallConfig call_config(network_controller_factory_->GetEventLog());
+  call_config.bitrate_config.max_bitrate_bps =
+      config.transport.rates.max_rate.bps_or(-1);
+  call_config.bitrate_config.min_bitrate_bps =
+      config.transport.rates.min_rate.bps();
+  call_config.bitrate_config.start_bitrate_bps =
+      config.transport.rates.start_rate.bps();
+  call_config.network_controller_factory = network_controller_factory_;
+  call_config.audio_state = audio_state;
+  return Call::Create(call_config);
+}
 }
 
 LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
@@ -107,17 +140,13 @@
                        std::string log_filename,
                        CallClientConfig config)
     : clock_(clock),
-      network_controller_factory_(log_filename, config.transport) {
-  CallConfig call_config(network_controller_factory_.GetEventLog());
-  call_config.bitrate_config.max_bitrate_bps =
-      config.transport.rates.max_rate.bps_or(-1);
-  call_config.bitrate_config.min_bitrate_bps =
-      config.transport.rates.min_rate.bps();
-  call_config.bitrate_config.start_bitrate_bps =
-      config.transport.rates.start_rate.bps();
-  call_config.network_controller_factory = &network_controller_factory_;
-  call_config.audio_state = InitAudio();
-  call_.reset(Call::Create(call_config));
+      network_controller_factory_(log_filename, config.transport),
+      fake_audio_setup_(InitAudio()),
+      call_(CreateCall(config,
+                       &network_controller_factory_,
+                       fake_audio_setup_.audio_state)),
+      transport_(clock_, call_.get()),
+      header_parser_(RtpHeaderParser::Create()) {
   if (!config.priority_target_rate.IsZero() &&
       config.priority_target_rate.IsFinite()) {
     call_->SetBitrateAllocationStrategy(
@@ -126,12 +155,13 @@
   }
 }  // namespace test
 
-CallClient::~CallClient() {}
+CallClient::~CallClient() {
+  delete header_parser_;
+}
 
 void CallClient::DeliverPacket(MediaType media_type,
                                rtc::CopyOnWriteBuffer packet,
                                Timestamp at_time) {
-  call_->Receiver()->DeliverPacket(media_type, packet, at_time.us());
 }
 
 ColumnPrinter CallClient::StatsPrinter() {
@@ -149,6 +179,26 @@
   return call_->GetStats();
 }
 
+bool CallClient::TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
+                                  uint64_t receiver,
+                                  Timestamp at_time) {
+  // Removes added overhead before delivering packet to sender.
+  RTC_DCHECK_GE(packet.size(), route_overhead_.at(receiver).bytes());
+  packet.SetSize(packet.size() - route_overhead_.at(receiver).bytes());
+
+  MediaType media_type = MediaType::ANY;
+  if (!RtpHeaderParser::IsRtcp(packet.cdata(), packet.size())) {
+    RTPHeader header;
+    bool success =
+        header_parser_->Parse(packet.cdata(), packet.size(), &header);
+    if (!success)
+      return false;
+    media_type = ssrc_media_types_[header.ssrc];
+  }
+  call_->Receiver()->DeliverPacket(media_type, packet, at_time.us());
+  return true;
+}
+
 uint32_t CallClient::GetNextVideoSsrc() {
   RTC_CHECK_LT(next_video_ssrc_index_, CallTest::kNumSsrcs);
   return CallTest::kVideoSendSsrcs[next_video_ssrc_index_++];
@@ -170,21 +220,7 @@
   return kPriorityStreamId;
 }
 
-rtc::scoped_refptr<AudioState> CallClient::InitAudio() {
-  auto capturer = TestAudioDeviceModule::CreatePulsedNoiseCapturer(256, 48000);
-  auto renderer = TestAudioDeviceModule::CreateDiscardRenderer(48000);
-  fake_audio_device_ = TestAudioDeviceModule::CreateTestAudioDeviceModule(
-      std::move(capturer), std::move(renderer), 1.f);
-  apm_ = AudioProcessingBuilder().Create();
-  fake_audio_device_->Init();
-  AudioState::Config audio_state_config;
-  audio_state_config.audio_mixer = AudioMixerImpl::Create();
-  audio_state_config.audio_processing = apm_;
-  audio_state_config.audio_device_module = fake_audio_device_;
-  auto audio_state = AudioState::Create(audio_state_config);
-  fake_audio_device_->RegisterAudioCallback(audio_state->audio_transport());
-  return audio_state;
-}
+CallClientPair::~CallClientPair() = default;
 
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/scenario/call_client.h b/test/scenario/call_client.h
index 80e2faf..48400cd 100644
--- a/test/scenario/call_client.h
+++ b/test/scenario/call_client.h
@@ -17,8 +17,10 @@
 #include "logging/rtc_event_log/rtc_event_log.h"
 #include "modules/audio_device/include/test_audio_device.h"
 #include "modules/congestion_controller/test/controller_printer.h"
+#include "modules/rtp_rtcp/include/rtp_header_parser.h"
 #include "rtc_base/constructormagic.h"
 #include "test/scenario/column_printer.h"
+#include "test/scenario/network_node.h"
 #include "test/scenario/scenario_config.h"
 
 namespace webrtc {
@@ -45,10 +47,15 @@
   FILE* cc_out_ = nullptr;
 };
 
+struct CallClientFakeAudio {
+  rtc::scoped_refptr<AudioProcessing> apm;
+  rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device;
+  rtc::scoped_refptr<AudioState> audio_state;
+};
 // CallClient represents a participant in a call scenario. It is created by the
 // Scenario class and is used as sender and receiver when setting up a media
 // stream session.
-class CallClient {
+class CallClient : public NetworkReceiverInterface {
  public:
   CallClient(Clock* clock, std::string log_filename, CallClientConfig config);
   RTC_DISALLOW_COPY_AND_ASSIGN(CallClient);
@@ -56,15 +63,24 @@
   ~CallClient();
   ColumnPrinter StatsPrinter();
   Call::Stats GetStats();
+  DataRate send_bandwidth() {
+    return DataRate::bps(GetStats().send_bandwidth_bps);
+  }
+
+  bool TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
+                        uint64_t receiver,
+                        Timestamp at_time) override;
 
  private:
   friend class Scenario;
+  friend class CallClientPair;
   friend class SendVideoStream;
+  friend class VideoStreamPair;
   friend class ReceiveVideoStream;
   friend class SendAudioStream;
   friend class ReceiveAudioStream;
+  friend class AudioStreamPair;
   friend class NetworkNodeTransport;
-  // TODO(srte): Consider using the Columnprinter interface for this.
   void DeliverPacket(MediaType media_type,
                      rtc::CopyOnWriteBuffer packet,
                      Timestamp at_time);
@@ -75,18 +91,37 @@
 
   Clock* clock_;
   LoggingNetworkControllerFactory network_controller_factory_;
+  CallClientFakeAudio fake_audio_setup_;
   std::unique_ptr<Call> call_;
-
-  rtc::scoped_refptr<AudioState> InitAudio();
-
-  rtc::scoped_refptr<AudioProcessing> apm_;
-  rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device_;
+  NetworkNodeTransport transport_;
+  RtpHeaderParser* const header_parser_;
 
   std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory_;
+  // Stores the configured overhead per known incomming route. This is used to
+  // subtract the overhead before processing.
+  std::map<uint64_t, DataSize> route_overhead_;
   int next_video_ssrc_index_ = 0;
   int next_rtx_ssrc_index_ = 0;
   int next_audio_ssrc_index_ = 0;
   int next_priority_index_ = 0;
+  std::map<uint32_t, MediaType> ssrc_media_types_;
+};
+
+class CallClientPair {
+ public:
+  RTC_DISALLOW_COPY_AND_ASSIGN(CallClientPair);
+  ~CallClientPair();
+  CallClient* first() { return first_; }
+  CallClient* second() { return second_; }
+  std::pair<CallClient*, CallClient*> forward() { return {first(), second()}; }
+  std::pair<CallClient*, CallClient*> reverse() { return {second(), first()}; }
+
+ private:
+  friend class Scenario;
+  CallClientPair(CallClient* first, CallClient* second)
+      : first_(first), second_(second) {}
+  CallClient* const first_;
+  CallClient* const second_;
 };
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/scenario/network_node.cc b/test/scenario/network_node.cc
index 87fc32a..b39d67b 100644
--- a/test/scenario/network_node.cc
+++ b/test/scenario/network_node.cc
@@ -170,21 +170,16 @@
       simulated_network_(simulation),
       config_(config) {}
 
-NetworkNodeTransport::NetworkNodeTransport(CallClient* sender,
-                                           NetworkNode* send_net,
-                                           uint64_t receiver,
-                                           DataSize packet_overhead)
-    : sender_(sender),
-      send_net_(send_net),
-      receiver_id_(receiver),
-      packet_overhead_(packet_overhead) {}
+NetworkNodeTransport::NetworkNodeTransport(const Clock* sender_clock,
+                                           Call* sender_call)
+    : sender_clock_(sender_clock), sender_call_(sender_call) {}
 
 NetworkNodeTransport::~NetworkNodeTransport() = default;
 
 bool NetworkNodeTransport::SendRtp(const uint8_t* packet,
                                    size_t length,
                                    const PacketOptions& options) {
-  int64_t send_time_ms = sender_->clock_->TimeInMilliseconds();
+  int64_t send_time_ms = sender_clock_->TimeInMilliseconds();
   rtc::SentPacket sent_packet;
   sent_packet.packet_id = options.packet_id;
   sent_packet.info.included_in_feedback = options.included_in_feedback;
@@ -192,9 +187,12 @@
   sent_packet.send_time_ms = send_time_ms;
   sent_packet.info.packet_size_bytes = length;
   sent_packet.info.packet_type = rtc::PacketType::kData;
-  sender_->call_->OnSentPacket(sent_packet);
+  sender_call_->OnSentPacket(sent_packet);
 
   Timestamp send_time = Timestamp::ms(send_time_ms);
+  rtc::CritScope crit(&crit_sect_);
+  if (!send_net_)
+    return false;
   rtc::CopyOnWriteBuffer buffer(packet, length,
                                 length + packet_overhead_.bytes());
   buffer.SetSize(length + packet_overhead_.bytes());
@@ -203,13 +201,29 @@
 
 bool NetworkNodeTransport::SendRtcp(const uint8_t* packet, size_t length) {
   rtc::CopyOnWriteBuffer buffer(packet, length);
-  Timestamp send_time = Timestamp::ms(sender_->clock_->TimeInMilliseconds());
+  Timestamp send_time = Timestamp::ms(sender_clock_->TimeInMilliseconds());
+  rtc::CritScope crit(&crit_sect_);
   buffer.SetSize(length + packet_overhead_.bytes());
+  if (!send_net_)
+    return false;
   return send_net_->TryDeliverPacket(buffer, receiver_id_, send_time);
 }
 
-uint64_t NetworkNodeTransport::ReceiverId() const {
-  return receiver_id_;
+void NetworkNodeTransport::Connect(NetworkNode* send_node,
+                                   uint64_t receiver_id,
+                                   DataSize packet_overhead) {
+  rtc::CritScope crit(&crit_sect_);
+  send_net_ = send_node;
+  receiver_id_ = receiver_id;
+  packet_overhead_ = packet_overhead;
+
+  rtc::NetworkRoute route;
+  route.connected = true;
+  route.local_network_id = receiver_id;
+  route.remote_network_id = receiver_id;
+  std::string transport_name = "dummy";
+  sender_call_->GetTransportControllerSend()->OnNetworkRouteChanged(
+      transport_name, route);
 }
 
 CrossTrafficSource::CrossTrafficSource(NetworkReceiverInterface* target,
diff --git a/test/scenario/network_node.h b/test/scenario/network_node.h
index af6db0a..4e90f6f 100644
--- a/test/scenario/network_node.h
+++ b/test/scenario/network_node.h
@@ -18,10 +18,10 @@
 
 #include "api/call/transport.h"
 #include "api/units/timestamp.h"
+#include "call/call.h"
 #include "call/simulated_network.h"
 #include "rtc_base/constructormagic.h"
 #include "rtc_base/copyonwritebuffer.h"
-#include "test/scenario/call_client.h"
 #include "test/scenario/column_printer.h"
 #include "test/scenario/scenario_config.h"
 
@@ -119,23 +119,30 @@
 
 class NetworkNodeTransport : public Transport {
  public:
-  NetworkNodeTransport(CallClient* sender,
-                       NetworkNode* send_net,
-                       uint64_t receiver,
-                       DataSize packet_overhead);
+  NetworkNodeTransport(const Clock* sender_clock, Call* sender_call);
   ~NetworkNodeTransport() override;
 
   bool SendRtp(const uint8_t* packet,
                size_t length,
                const PacketOptions& options) override;
   bool SendRtcp(const uint8_t* packet, size_t length) override;
-  uint64_t ReceiverId() const;
+
+  void Connect(NetworkNode* send_node,
+               uint64_t receiver_id,
+               DataSize packet_overhead);
+
+  DataSize packet_overhead() {
+    rtc::CritScope crit(&crit_sect_);
+    return packet_overhead_;
+  }
 
  private:
-  CallClient* const sender_;
-  NetworkNode* const send_net_;
-  const uint64_t receiver_id_;
-  const DataSize packet_overhead_;
+  rtc::CriticalSection crit_sect_;
+  const Clock* const sender_clock_;
+  Call* const sender_call_;
+  NetworkNode* send_net_ RTC_GUARDED_BY(crit_sect_) = nullptr;
+  uint64_t receiver_id_ RTC_GUARDED_BY(crit_sect_) = 0;
+  DataSize packet_overhead_ RTC_GUARDED_BY(crit_sect_) = DataSize::Zero();
 };
 
 // CrossTrafficSource is created by a Scenario and generates cross traffic. It
diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc
index 2395a7a..e77e308 100644
--- a/test/scenario/scenario.cc
+++ b/test/scenario/scenario.cc
@@ -123,14 +123,50 @@
   return CreateClient(name, config);
 }
 
+CallClientPair* Scenario::CreateRoutes(CallClient* first,
+                                       std::vector<NetworkNode*> send_link,
+                                       CallClient* second,
+                                       std::vector<NetworkNode*> return_link) {
+  return CreateRoutes(first, send_link,
+                      DataSize::bytes(PacketOverhead::kDefault), second,
+                      return_link, DataSize::bytes(PacketOverhead::kDefault));
+}
+
+CallClientPair* Scenario::CreateRoutes(CallClient* first,
+                                       std::vector<NetworkNode*> send_link,
+                                       DataSize first_overhead,
+                                       CallClient* second,
+                                       std::vector<NetworkNode*> return_link,
+                                       DataSize second_overhead) {
+  CallClientPair* client_pair = new CallClientPair(first, second);
+  ChangeRoute(client_pair->forward(), send_link, first_overhead);
+  ChangeRoute(client_pair->reverse(), return_link, second_overhead);
+  client_pairs_.emplace_back(client_pair);
+  return client_pair;
+}
+
+void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
+                           std::vector<NetworkNode*> over_nodes) {
+  ChangeRoute(clients, over_nodes, DataSize::bytes(PacketOverhead::kDefault));
+}
+
+void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
+                           std::vector<NetworkNode*> over_nodes,
+                           DataSize overhead) {
+  uint64_t route_id = next_route_id_++;
+  clients.second->route_overhead_.insert({route_id, overhead});
+  NetworkNode::Route(route_id, over_nodes, clients.second);
+  clients.first->transport_.Connect(over_nodes.front(), route_id, overhead);
+}
+
 SimulatedTimeClient* Scenario::CreateSimulatedTimeClient(
     std::string name,
     SimulatedTimeClientConfig config,
     std::vector<PacketStreamConfig> stream_configs,
     std::vector<NetworkNode*> send_link,
     std::vector<NetworkNode*> return_link) {
-  uint64_t send_id = next_receiver_id_++;
-  uint64_t return_id = next_receiver_id_++;
+  uint64_t send_id = next_route_id_++;
+  uint64_t return_id = next_route_id_++;
   SimulatedTimeClient* client = new SimulatedTimeClient(
       GetFullPathOrEmpty(name), config, stream_configs, send_link, return_link,
       send_id, return_id, Now());
@@ -179,21 +215,21 @@
 void Scenario::TriggerPacketBurst(std::vector<NetworkNode*> over_nodes,
                                   size_t num_packets,
                                   size_t packet_size) {
-  int64_t receiver_id = next_receiver_id_++;
-  NetworkNode::Route(receiver_id, over_nodes, &null_receiver_);
+  int64_t route_id = next_route_id_++;
+  NetworkNode::Route(route_id, over_nodes, &null_receiver_);
   for (size_t i = 0; i < num_packets; ++i)
     over_nodes[0]->TryDeliverPacket(rtc::CopyOnWriteBuffer(packet_size),
-                                    receiver_id, Now());
+                                    route_id, Now());
 }
 
 void Scenario::NetworkDelayedAction(std::vector<NetworkNode*> over_nodes,
                                     size_t packet_size,
                                     std::function<void()> action) {
-  int64_t receiver_id = next_receiver_id_++;
+  int64_t route_id = next_route_id_++;
   action_receivers_.emplace_back(new ActionReceiver(action));
-  NetworkNode::Route(receiver_id, over_nodes, action_receivers_.back().get());
-  over_nodes[0]->TryDeliverPacket(rtc::CopyOnWriteBuffer(packet_size),
-                                  receiver_id, Now());
+  NetworkNode::Route(route_id, over_nodes, action_receivers_.back().get());
+  over_nodes[0]->TryDeliverPacket(rtc::CopyOnWriteBuffer(packet_size), route_id,
+                                  Now());
 }
 
 CrossTrafficSource* Scenario::CreateCrossTraffic(
@@ -207,65 +243,46 @@
 CrossTrafficSource* Scenario::CreateCrossTraffic(
     std::vector<NetworkNode*> over_nodes,
     CrossTrafficConfig config) {
-  int64_t receiver_id = next_receiver_id_++;
+  int64_t route_id = next_route_id_++;
   cross_traffic_sources_.emplace_back(
-      new CrossTrafficSource(over_nodes.front(), receiver_id, config));
+      new CrossTrafficSource(over_nodes.front(), route_id, config));
   CrossTrafficSource* node = cross_traffic_sources_.back().get();
-  NetworkNode::Route(receiver_id, over_nodes, &null_receiver_);
+  NetworkNode::Route(route_id, over_nodes, &null_receiver_);
   Every(config.min_packet_interval,
         [this, node](TimeDelta delta) { node->Process(Now(), delta); });
   return node;
 }
 
 VideoStreamPair* Scenario::CreateVideoStream(
-    CallClient* sender,
-    std::vector<NetworkNode*> send_link,
-    CallClient* receiver,
-    std::vector<NetworkNode*> return_link,
+    std::pair<CallClient*, CallClient*> clients,
     std::function<void(VideoStreamConfig*)> config_modifier) {
   VideoStreamConfig config;
   config_modifier(&config);
-  return CreateVideoStream(sender, send_link, receiver, return_link, config);
+  return CreateVideoStream(clients, config);
 }
 
 VideoStreamPair* Scenario::CreateVideoStream(
-    CallClient* sender,
-    std::vector<NetworkNode*> send_link,
-    CallClient* receiver,
-    std::vector<NetworkNode*> return_link,
+    std::pair<CallClient*, CallClient*> clients,
     VideoStreamConfig config) {
-  uint64_t send_receiver_id = next_receiver_id_++;
-  uint64_t return_receiver_id = next_receiver_id_++;
-
   video_streams_.emplace_back(
-      new VideoStreamPair(sender, send_link, send_receiver_id, receiver,
-                          return_link, return_receiver_id, config));
+      new VideoStreamPair(clients.first, clients.second, config));
   return video_streams_.back().get();
 }
 
 AudioStreamPair* Scenario::CreateAudioStream(
-    CallClient* sender,
-    std::vector<NetworkNode*> send_link,
-    CallClient* receiver,
-    std::vector<NetworkNode*> return_link,
+    std::pair<CallClient*, CallClient*> clients,
     std::function<void(AudioStreamConfig*)> config_modifier) {
   AudioStreamConfig config;
   config_modifier(&config);
-  return CreateAudioStream(sender, send_link, receiver, return_link, config);
+  return CreateAudioStream(clients, config);
 }
 
 AudioStreamPair* Scenario::CreateAudioStream(
-    CallClient* sender,
-    std::vector<NetworkNode*> send_link,
-    CallClient* receiver,
-    std::vector<NetworkNode*> return_link,
+    std::pair<CallClient*, CallClient*> clients,
     AudioStreamConfig config) {
-  uint64_t send_receiver_id = next_receiver_id_++;
-  uint64_t return_receiver_id = next_receiver_id_++;
-
-  audio_streams_.emplace_back(new AudioStreamPair(
-      sender, send_link, send_receiver_id, audio_encoder_factory_, receiver,
-      return_link, return_receiver_id, audio_decoder_factory_, config));
+  audio_streams_.emplace_back(
+      new AudioStreamPair(clients.first, audio_encoder_factory_, clients.second,
+                          audio_decoder_factory_, config));
   return audio_streams_.back().get();
 }
 
diff --git a/test/scenario/scenario.h b/test/scenario/scenario.h
index 05876ac..5ee017c 100644
--- a/test/scenario/scenario.h
+++ b/test/scenario/scenario.h
@@ -78,6 +78,25 @@
       std::string name,
       std::function<void(CallClientConfig*)> config_modifier);
 
+  CallClientPair* CreateRoutes(CallClient* first,
+                               std::vector<NetworkNode*> send_link,
+                               CallClient* second,
+                               std::vector<NetworkNode*> return_link);
+
+  CallClientPair* CreateRoutes(CallClient* first,
+                               std::vector<NetworkNode*> send_link,
+                               DataSize first_overhead,
+                               CallClient* second,
+                               std::vector<NetworkNode*> return_link,
+                               DataSize second_overhead);
+
+  void ChangeRoute(std::pair<CallClient*, CallClient*> clients,
+                   std::vector<NetworkNode*> over_nodes);
+
+  void ChangeRoute(std::pair<CallClient*, CallClient*> clients,
+                   std::vector<NetworkNode*> over_nodes,
+                   DataSize overhead);
+
   SimulatedTimeClient* CreateSimulatedTimeClient(
       std::string name,
       SimulatedTimeClientConfig config,
@@ -86,28 +105,18 @@
       std::vector<NetworkNode*> return_link);
 
   VideoStreamPair* CreateVideoStream(
-      CallClient* sender,
-      std::vector<NetworkNode*> send_link,
-      CallClient* receiver,
-      std::vector<NetworkNode*> return_link,
+      std::pair<CallClient*, CallClient*> clients,
       std::function<void(VideoStreamConfig*)> config_modifier);
-  VideoStreamPair* CreateVideoStream(CallClient* sender,
-                                     std::vector<NetworkNode*> send_link,
-                                     CallClient* receiver,
-                                     std::vector<NetworkNode*> return_link,
-                                     VideoStreamConfig config);
+  VideoStreamPair* CreateVideoStream(
+      std::pair<CallClient*, CallClient*> clients,
+      VideoStreamConfig config);
 
   AudioStreamPair* CreateAudioStream(
-      CallClient* sender,
-      std::vector<NetworkNode*> send_link,
-      CallClient* receiver,
-      std::vector<NetworkNode*> return_link,
+      std::pair<CallClient*, CallClient*> clients,
       std::function<void(AudioStreamConfig*)> config_modifier);
-  AudioStreamPair* CreateAudioStream(CallClient* sender,
-                                     std::vector<NetworkNode*> send_link,
-                                     CallClient* receiver,
-                                     std::vector<NetworkNode*> return_link,
-                                     AudioStreamConfig config);
+  AudioStreamPair* CreateAudioStream(
+      std::pair<CallClient*, CallClient*> clients,
+      AudioStreamConfig config);
 
   CrossTrafficSource* CreateCrossTraffic(
       std::vector<NetworkNode*> over_nodes,
@@ -167,6 +176,7 @@
   rtc::FakeClock event_log_fake_clock_;
 
   std::vector<std::unique_ptr<CallClient>> clients_;
+  std::vector<std::unique_ptr<CallClientPair>> client_pairs_;
   std::vector<std::unique_ptr<NetworkNode>> network_nodes_;
   std::vector<std::unique_ptr<CrossTrafficSource>> cross_traffic_sources_;
   std::vector<std::unique_ptr<VideoStreamPair>> video_streams_;
@@ -179,7 +189,7 @@
   std::vector<std::unique_ptr<PendingActivity>> pending_activities_;
   std::vector<std::unique_ptr<StatesPrinter>> printers_;
 
-  int64_t next_receiver_id_ = 40000;
+  int64_t next_route_id_ = 40000;
   rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory_;
   rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory_;
 
diff --git a/test/scenario/scenario_config.h b/test/scenario/scenario_config.h
index 7bcc8f9..8606d5f4 100644
--- a/test/scenario/scenario_config.h
+++ b/test/scenario/scenario_config.h
@@ -28,7 +28,12 @@
   static constexpr size_t kIpv6 = 40;
   static constexpr size_t kUdp = 8;
   static constexpr size_t kSrtp = 10;
-  static constexpr size_t kTurn = 4;
+  static constexpr size_t kStun = 4;
+  // TURN messages can be sent either with or without an establieshed channel.
+  // In the latter case, a TURN Send/Data Indication is sent which has
+  // significantly more overhead.
+  static constexpr size_t kTurnChannelMessage = 4;
+  static constexpr size_t kTurnIndicationMessage = 36;
   static constexpr size_t kDefault = kIpv4 + kUdp + kSrtp;
 };
 struct TransportControllerConfig {
@@ -117,7 +122,6 @@
     TimeDelta nack_history_time = TimeDelta::ms(1000);
     bool use_flexfec = false;
     bool use_ulpfec = false;
-    DataSize packet_overhead = DataSize::bytes(PacketOverhead::kDefault);
   } stream;
   struct Renderer {
     enum Type { kFake } type = kFake;
@@ -159,7 +163,6 @@
     ~Stream();
     bool in_bandwidth_estimation = false;
     bool rate_allocation_priority = false;
-    DataSize packet_overhead = DataSize::bytes(PacketOverhead::kDefault);
   } stream;
   struct Render {
     std::string sync_group;
diff --git a/test/scenario/scenario_tests/bbr_performance.cc b/test/scenario/scenario_tests/bbr_performance.cc
index e87cc68..28cabc0 100644
--- a/test/scenario/scenario_tests/bbr_performance.cc
+++ b/test/scenario/scenario_tests/bbr_performance.cc
@@ -167,31 +167,31 @@
   net_conf.simulation.delay_std_dev = conf_.scenario.delay_noise;
   SimulationNode* send_net = s.CreateSimulationNode(net_conf);
   SimulationNode* ret_net = s.CreateSimulationNode(net_conf);
-  VideoStreamPair* alice_video = s.CreateVideoStream(
-      alice, {send_net}, bob, {ret_net}, [&](VideoStreamConfig* c) {
+  auto route = s.CreateRoutes(alice, {send_net}, bob, {ret_net});
+
+  VideoStreamPair* alice_video =
+      s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
         c->encoder.fake.max_rate = DataRate::kbps(1800);
       });
-  s.CreateAudioStream(alice, {send_net}, bob, {ret_net},
-                      [&](AudioStreamConfig* c) {
-                        if (conf_.tuning.use_bbr) {
-                          c->stream.in_bandwidth_estimation = true;
-                          c->encoder.fixed_rate = DataRate::kbps(31);
-                        }
-                      });
+  s.CreateAudioStream(route->forward(), [&](AudioStreamConfig* c) {
+    if (conf_.tuning.use_bbr) {
+      c->stream.in_bandwidth_estimation = true;
+      c->encoder.fixed_rate = DataRate::kbps(31);
+    }
+  });
 
   VideoStreamPair* bob_video = nullptr;
   if (conf_.scenario.return_traffic) {
-    bob_video = s.CreateVideoStream(
-        bob, {ret_net}, alice, {send_net}, [&](VideoStreamConfig* c) {
+    bob_video =
+        s.CreateVideoStream(route->reverse(), [&](VideoStreamConfig* c) {
           c->encoder.fake.max_rate = DataRate::kbps(1800);
         });
-    s.CreateAudioStream(bob, {ret_net}, alice, {send_net},
-                        [&](AudioStreamConfig* c) {
-                          if (conf_.tuning.use_bbr) {
-                            c->stream.in_bandwidth_estimation = true;
-                            c->encoder.fixed_rate = DataRate::kbps(31);
-                          }
-                        });
+    s.CreateAudioStream(route->reverse(), [&](AudioStreamConfig* c) {
+      if (conf_.tuning.use_bbr) {
+        c->stream.in_bandwidth_estimation = true;
+        c->encoder.fixed_rate = DataRate::kbps(31);
+      }
+    });
   }
   CrossTrafficConfig cross_config;
   cross_config.peak_rate = conf_.scenario.cross_traffic;
diff --git a/test/scenario/scenario_unittest.cc b/test/scenario/scenario_unittest.cc
index 87647a4..97285d3 100644
--- a/test/scenario/scenario_unittest.cc
+++ b/test/scenario/scenario_unittest.cc
@@ -21,18 +21,19 @@
   NetworkNodeConfig network_config;
   auto alice_net = s.CreateSimulationNode(network_config);
   auto bob_net = s.CreateSimulationNode(network_config);
+  auto route = s.CreateRoutes(alice, {alice_net}, bob, {bob_net});
 
   VideoStreamConfig video_stream_config;
-  s.CreateVideoStream(alice, {alice_net}, bob, {bob_net}, video_stream_config);
-  s.CreateVideoStream(bob, {bob_net}, alice, {alice_net}, video_stream_config);
+  s.CreateVideoStream(route->forward(), video_stream_config);
+  s.CreateVideoStream(route->reverse(), video_stream_config);
 
   AudioStreamConfig audio_stream_config;
   audio_stream_config.encoder.min_rate = DataRate::kbps(6);
   audio_stream_config.encoder.max_rate = DataRate::kbps(64);
   audio_stream_config.encoder.allocate_bitrate = true;
   audio_stream_config.stream.in_bandwidth_estimation = false;
-  s.CreateAudioStream(alice, {alice_net}, bob, {bob_net}, audio_stream_config);
-  s.CreateAudioStream(bob, {bob_net}, alice, {alice_net}, audio_stream_config);
+  s.CreateAudioStream(route->forward(), audio_stream_config);
+  s.CreateAudioStream(route->reverse(), audio_stream_config);
 
   CrossTrafficConfig cross_traffic_config;
   s.CreateCrossTraffic({alice_net}, cross_traffic_config);
diff --git a/test/scenario/simulated_time.cc b/test/scenario/simulated_time.cc
index f29a82c..29de110 100644
--- a/test/scenario/simulated_time.cc
+++ b/test/scenario/simulated_time.cc
@@ -252,11 +252,12 @@
       return_link_(return_link),
       sender_(send_link.front(), send_receiver_id),
       feedback_(config, return_receiver_id, return_link.front()) {
+  current_contraints_.at_time = at_time;
+  current_contraints_.starting_rate = config.transport.rates.start_rate;
+  current_contraints_.min_data_rate = config.transport.rates.min_rate;
+  current_contraints_.max_data_rate = config.transport.rates.max_rate;
   NetworkControllerConfig initial_config;
-  initial_config.constraints.at_time = at_time;
-  initial_config.constraints.starting_rate = config.transport.rates.start_rate;
-  initial_config.constraints.min_data_rate = config.transport.rates.min_rate;
-  initial_config.constraints.max_data_rate = config.transport.rates.max_rate;
+  initial_config.constraints = current_contraints_;
   congestion_controller_ = network_controller_factory_.Create(initial_config);
   for (auto& stream_config : stream_configs)
     packet_streams_.emplace_back(new PacketStream(stream_config));
@@ -336,6 +337,14 @@
   }
 }
 
+void SimulatedTimeClient::TriggerFakeReroute(Timestamp at_time) {
+  NetworkRouteChange msg;
+  msg.at_time = at_time;
+  msg.constraints = current_contraints_;
+  msg.constraints.at_time = at_time;
+  Update(congestion_controller_->OnNetworkRouteChange(msg));
+}
+
 TimeDelta SimulatedTimeClient::GetNetworkControllerProcessInterval() const {
   return network_controller_factory_.GetProcessInterval();
 }
diff --git a/test/scenario/simulated_time.h b/test/scenario/simulated_time.h
index b9c6de1..42f176e 100644
--- a/test/scenario/simulated_time.h
+++ b/test/scenario/simulated_time.h
@@ -129,6 +129,7 @@
   void CongestionProcess(Timestamp at_time);
   void PacerProcess(Timestamp at_time);
   void ProcessFrames(Timestamp at_time);
+  void TriggerFakeReroute(Timestamp at_time);
   TimeDelta GetNetworkControllerProcessInterval() const;
   double target_rate_kbps() const;
 
@@ -144,6 +145,7 @@
   std::vector<NetworkNode*> return_link_;
   SimulatedSender sender_;
   SimulatedFeedback feedback_;
+  TargetRateConstraints current_contraints_;
   DataRate target_rate_ = DataRate::Infinity();
   FILE* packet_log_ = nullptr;
 
diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc
index b85034f..914d981 100644
--- a/test/scenario/video_stream.cc
+++ b/test/scenario/video_stream.cc
@@ -234,16 +234,6 @@
   video_capturer_->Start();
 }
 
-bool SendVideoStream::TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                                       uint64_t receiver,
-                                       Timestamp at_time) {
-  // Removes added overhead before delivering RTCP packet to sender.
-  RTC_DCHECK_GE(packet.size(), config_.stream.packet_overhead.bytes());
-  packet.SetSize(packet.size() - config_.stream.packet_overhead.bytes());
-  sender_->DeliverPacket(MediaType::VIDEO, packet, at_time);
-  return true;
-}
-
 void SendVideoStream::SetCaptureFramerate(int framerate) {
   RTC_CHECK(frame_generator_)
       << "Framerate change only implemented for generators";
@@ -300,11 +290,14 @@
   recv_config.renderer = renderer_.get();
   if (config.stream.use_rtx) {
     recv_config.rtp.rtx_ssrc = send_stream->rtx_ssrcs_[chosen_stream];
+    receiver->ssrc_media_types_[recv_config.rtp.rtx_ssrc] = MediaType::VIDEO;
     recv_config.rtp
         .rtx_associated_payload_types[CallTest::kSendRtxPayloadType] =
         CodecTypeToPayloadType(config.encoder.codec);
   }
   recv_config.rtp.remote_ssrc = send_stream->ssrcs_[chosen_stream];
+  receiver->ssrc_media_types_[recv_config.rtp.remote_ssrc] = MediaType::VIDEO;
+
   VideoReceiveStream::Decoder decoder =
       CreateMatchingDecoder(CodecTypeToPayloadType(config.encoder.codec),
                             CodecTypeToPayloadString(config.encoder.codec));
@@ -316,6 +309,7 @@
     FlexfecReceiveStream::Config flexfec_config(feedback_transport);
     flexfec_config.payload_type = CallTest::kFlexfecPayloadType;
     flexfec_config.remote_ssrc = CallTest::kFlexfecSendSsrc;
+    receiver->ssrc_media_types_[flexfec_config.remote_ssrc] = MediaType::VIDEO;
     flexfec_config.protected_media_ssrcs = send_stream->rtx_ssrcs_;
     flexfec_config.local_ssrc = recv_config.rtp.local_ssrc;
     flecfec_stream_ =
@@ -337,46 +331,18 @@
     receiver_->call_->DestroyFlexfecReceiveStream(flecfec_stream_);
 }
 
-bool ReceiveVideoStream::TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                                          uint64_t receiver,
-                                          Timestamp at_time) {
-  RTC_DCHECK_GE(packet.size(), config_.stream.packet_overhead.bytes());
-  packet.SetSize(packet.size() - config_.stream.packet_overhead.bytes());
-  receiver_->DeliverPacket(MediaType::VIDEO, packet, at_time);
-  return true;
-}
-
 VideoStreamPair::~VideoStreamPair() = default;
 
 VideoStreamPair::VideoStreamPair(CallClient* sender,
-                                 std::vector<NetworkNode*> send_link,
-                                 uint64_t send_receiver_id,
                                  CallClient* receiver,
-                                 std::vector<NetworkNode*> return_link,
-                                 uint64_t return_receiver_id,
                                  VideoStreamConfig config)
     : config_(config),
-      send_link_(send_link),
-      return_link_(return_link),
-      send_transport_(sender,
-                      send_link.front(),
-                      send_receiver_id,
-                      config.stream.packet_overhead),
-      return_transport_(receiver,
-                        return_link.front(),
-                        return_receiver_id,
-                        config.stream.packet_overhead),
-      send_stream_(sender, config, &send_transport_),
+      send_stream_(sender, config, &sender->transport_),
       receive_stream_(receiver,
                       config,
                       &send_stream_,
                       /*chosen_stream=*/0,
-                      &return_transport_) {
-  NetworkNode::Route(send_transport_.ReceiverId(), send_link_,
-                     &receive_stream_);
-  NetworkNode::Route(return_transport_.ReceiverId(), return_link_,
-                     &send_stream_);
-}
+                      &receiver->transport_) {}
 
 }  // namespace test
 }  // namespace webrtc
diff --git a/test/scenario/video_stream.h b/test/scenario/video_stream.h
index e669618..1b5b20a 100644
--- a/test/scenario/video_stream.h
+++ b/test/scenario/video_stream.h
@@ -25,7 +25,7 @@
 namespace test {
 // SendVideoStream provides an interface for changing parameters and retrieving
 // states at run time.
-class SendVideoStream : public NetworkReceiverInterface {
+class SendVideoStream {
  public:
   RTC_DISALLOW_COPY_AND_ASSIGN(SendVideoStream);
   ~SendVideoStream();
@@ -43,9 +43,6 @@
   SendVideoStream(CallClient* sender,
                   VideoStreamConfig config,
                   Transport* send_transport);
-  bool TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                        uint64_t receiver,
-                        Timestamp at_time) override;
 
   std::vector<uint32_t> ssrcs_;
   std::vector<uint32_t> rtx_ssrcs_;
@@ -55,10 +52,12 @@
   std::unique_ptr<VideoEncoderFactory> encoder_factory_;
   std::unique_ptr<TestVideoCapturer> video_capturer_;
   FrameGeneratorCapturer* frame_generator_ = nullptr;
+  int next_local_network_id_ = 0;
+  int next_remote_network_id_ = 0;
 };
 
 // ReceiveVideoStream represents a video receiver. It can't be used directly.
-class ReceiveVideoStream : public NetworkReceiverInterface {
+class ReceiveVideoStream {
  public:
   RTC_DISALLOW_COPY_AND_ASSIGN(ReceiveVideoStream);
   ~ReceiveVideoStream();
@@ -71,9 +70,7 @@
                      SendVideoStream* send_stream,
                      size_t chosen_stream,
                      Transport* feedback_transport);
-  bool TryDeliverPacket(rtc::CopyOnWriteBuffer packet,
-                        uint64_t receiver,
-                        Timestamp at_time) override;
+
   VideoReceiveStream* receive_stream_ = nullptr;
   FlexfecReceiveStream* flecfec_stream_ = nullptr;
   std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> renderer_;
@@ -95,18 +92,10 @@
  private:
   friend class Scenario;
   VideoStreamPair(CallClient* sender,
-                  std::vector<NetworkNode*> send_link,
-                  uint64_t send_receiver_id,
                   CallClient* receiver,
-                  std::vector<NetworkNode*> return_link,
-                  uint64_t return_receiver_id,
                   VideoStreamConfig config);
 
   const VideoStreamConfig config_;
-  std::vector<NetworkNode*> send_link_;
-  std::vector<NetworkNode*> return_link_;
-  NetworkNodeTransport send_transport_;
-  NetworkNodeTransport return_transport_;
 
   SendVideoStream send_stream_;
   ReceiveVideoStream receive_stream_;