Allow supplying a custom NetworkControllerInterfaceFactory per-Call in PeerConnectionDependencies

This requires making CallConfig move-only so it can hold a unique_ptr to
the factory, but as discussed with Danil, that seems fine.

Bug: chromium:355610792
Change-Id: Ie52e33faaa4a2af748daeb25f5327b7a532936e2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/357862
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tony Herre <herre@google.com>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42679}
diff --git a/api/enable_media.cc b/api/enable_media.cc
index e9c115b..6ef354b 100644
--- a/api/enable_media.cc
+++ b/api/enable_media.cc
@@ -39,8 +39,8 @@
   MediaFactoryImpl& operator=(const MediaFactoryImpl&) = delete;
   ~MediaFactoryImpl() override = default;
 
-  std::unique_ptr<Call> CreateCall(const CallConfig& config) override {
-    return webrtc::CreateCall(config);
+  std::unique_ptr<Call> CreateCall(CallConfig config) override {
+    return webrtc::CreateCall(std::move(config));
   }
 
   std::unique_ptr<MediaEngineInterface> CreateMediaEngine(
diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h
index a422eae..46b9133 100644
--- a/api/peer_connection_interface.h
+++ b/api/peer_connection_interface.h
@@ -1392,6 +1392,10 @@
   std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier;
   std::unique_ptr<webrtc::VideoBitrateAllocatorFactory>
       video_bitrate_allocator_factory;
+  // Optional network controller factory to use.
+  // Overrides that set in PeerConnectionFactoryDependencies.
+  std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory;
+
   // Optional field trials to use.
   // Overrides those from PeerConnectionFactoryDependencies.
   std::unique_ptr<FieldTrialsView> trials;
diff --git a/api/test/create_time_controller.cc b/api/test/create_time_controller.cc
index cbf1f09..9189e36 100644
--- a/api/test/create_time_controller.cc
+++ b/api/test/create_time_controller.cc
@@ -48,13 +48,12 @@
         absl::Nonnull<std::unique_ptr<MediaFactory>> media_factory)
         : clock_(clock), media_factory_(std::move(media_factory)) {}
 
-    std::unique_ptr<Call> CreateCall(const CallConfig& config) override {
+    std::unique_ptr<Call> CreateCall(CallConfig config) override {
       EnvironmentFactory env_factory(config.env);
       env_factory.Set(clock_);
 
-      CallConfig config_with_custom_clock = config;
-      config_with_custom_clock.env = env_factory.Create();
-      return media_factory_->CreateCall(config_with_custom_clock);
+      config.env = env_factory.Create();
+      return media_factory_->CreateCall(std::move(config));
     }
 
     std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine(
diff --git a/call/call.cc b/call/call.cc
index 817a532..bb8436f 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -183,7 +183,7 @@
                    public TargetTransferRateObserver,
                    public BitrateAllocator::LimitObserver {
  public:
-  Call(const CallConfig& config,
+  Call(CallConfig config,
        std::unique_ptr<RtpTransportControllerSendInterface> transport_send);
   ~Call() override;
 
@@ -467,7 +467,7 @@
   return ss.str();
 }
 
-std::unique_ptr<Call> Call::Create(const CallConfig& config) {
+std::unique_ptr<Call> Call::Create(CallConfig config) {
   std::unique_ptr<RtpTransportControllerSendInterface> transport_send;
   if (config.rtp_transport_controller_send_factory != nullptr) {
     transport_send = config.rtp_transport_controller_send_factory->Create(
@@ -477,7 +477,8 @@
         config.ExtractTransportConfig());
   }
 
-  return std::make_unique<internal::Call>(config, std::move(transport_send));
+  return std::make_unique<internal::Call>(std::move(config),
+                                          std::move(transport_send));
 }
 
 // This method here to avoid subclasses has to implement this method.
@@ -643,7 +644,7 @@
   min_allocated_send_bitrate_bps_ = limits.min_allocatable_rate.bps();
 }
 
-Call::Call(const CallConfig& config,
+Call::Call(CallConfig config,
            std::unique_ptr<RtpTransportControllerSendInterface> transport_send)
     : env_(config.env),
       worker_thread_(GetCurrentTaskQueueOrThread()),
@@ -660,7 +661,7 @@
       num_cpu_cores_(CpuInfo::DetectNumberOfCores()),
       call_stats_(new CallStats(&env_.clock(), worker_thread_)),
       bitrate_allocator_(new BitrateAllocator(this)),
-      config_(config),
+      config_(std::move(config)),
       audio_network_state_(kNetworkDown),
       video_network_state_(kNetworkDown),
       aggregate_network_up_(false),
diff --git a/call/call.h b/call/call.h
index a680335..6ada035 100644
--- a/call/call.h
+++ b/call/call.h
@@ -55,7 +55,7 @@
     int64_t rtt_ms = -1;
   };
 
-  static std::unique_ptr<Call> Create(const CallConfig& config);
+  static std::unique_ptr<Call> Create(CallConfig config);
 
   virtual AudioSendStream* CreateAudioSendStream(
       const AudioSendStream::Config& config) = 0;
diff --git a/call/call_config.cc b/call/call_config.cc
index 0a6ad2c..19d91cf 100644
--- a/call/call_config.cc
+++ b/call/call_config.cc
@@ -20,12 +20,13 @@
     : env(env),
       network_task_queue_(network_task_queue) {}
 
-CallConfig::CallConfig(const CallConfig& config) = default;
-
 RtpTransportConfig CallConfig::ExtractTransportConfig() const {
   RtpTransportConfig transport_config = {.env = env};
   transport_config.bitrate_config = bitrate_config;
-  transport_config.network_controller_factory = network_controller_factory;
+  transport_config.network_controller_factory =
+      per_call_network_controller_factory
+          ? per_call_network_controller_factory.get()
+          : network_controller_factory;
   transport_config.network_state_predictor_factory =
       network_state_predictor_factory;
   transport_config.pacer_burst_interval = pacer_burst_interval;
diff --git a/call/call_config.h b/call/call_config.h
index 6fd9179..724dad4 100644
--- a/call/call_config.h
+++ b/call/call_config.h
@@ -10,6 +10,8 @@
 #ifndef CALL_CALL_CONFIG_H_
 #define CALL_CALL_CONFIG_H_
 
+#include <memory>
+
 #include "api/environment/environment.h"
 #include "api/fec_controller.h"
 #include "api/metronome/metronome.h"
@@ -32,7 +34,9 @@
   explicit CallConfig(const Environment& env,
                       TaskQueueBase* network_task_queue = nullptr);
 
-  CallConfig(const CallConfig&);
+  // Move-only.
+  CallConfig(CallConfig&&) = default;
+  CallConfig& operator=(CallConfig&& other) = default;
 
   ~CallConfig();
 
@@ -57,13 +61,18 @@
   NetworkStatePredictorFactoryInterface* network_state_predictor_factory =
       nullptr;
 
-  // Network controller factory to use for this call.
+  // Call-specific Network controller factory to use. If this is set, it
+  // takes precedence over network_controller_factory.
+  std::unique_ptr<NetworkControllerFactoryInterface>
+      per_call_network_controller_factory;
+  // Network controller factory to use for this call if
+  // per_call_network_controller_factory is null.
   NetworkControllerFactoryInterface* network_controller_factory = nullptr;
 
   // NetEq factory to use for this call.
   NetEqFactory* neteq_factory = nullptr;
 
-  TaskQueueBase* const network_task_queue_ = nullptr;
+  TaskQueueBase* network_task_queue_ = nullptr;
   // RtpTransportControllerSend to use for this call.
   RtpTransportControllerSendFactoryInterface*
       rtp_transport_controller_send_factory = nullptr;
diff --git a/call/call_perf_tests.cc b/call/call_perf_tests.cc
index 452d62c..ff92a52 100644
--- a/call/call_perf_tests.cc
+++ b/call/call_perf_tests.cc
@@ -231,7 +231,7 @@
     sender_config.audio_state = audio_state;
     CallConfig receiver_config = RecvCallConfig();
     receiver_config.audio_state = audio_state;
-    CreateCalls(sender_config, receiver_config);
+    CreateCalls(std::move(sender_config), std::move(receiver_config));
 
     std::copy_if(std::begin(payload_type_map_), std::end(payload_type_map_),
                  std::inserter(audio_pt_map, audio_pt_map.end()),
diff --git a/call/call_unittest.cc b/call/call_unittest.cc
index 7fad99c..aa0b08f 100644
--- a/call/call_unittest.cc
+++ b/call/call_unittest.cc
@@ -65,7 +65,7 @@
         rtc::make_ref_counted<MockAudioDeviceModule>();
     CallConfig config(CreateEnvironment());
     config.audio_state = AudioState::Create(audio_state_config);
-    call_ = Call::Create(config);
+    call_ = Call::Create(std::move(config));
   }
 
   Call* operator->() { return call_.get(); }
diff --git a/call/create_call.cc b/call/create_call.cc
index 8b56574..317a187 100644
--- a/call/create_call.cc
+++ b/call/create_call.cc
@@ -77,14 +77,14 @@
 
 }  // namespace
 
-std::unique_ptr<Call> CreateCall(const CallConfig& config) {
+std::unique_ptr<Call> CreateCall(CallConfig config) {
   std::vector<DegradedCall::TimeScopedNetworkConfig> send_degradation_configs =
       GetNetworkConfigs(config.env.field_trials(), /*send=*/true);
   std::vector<DegradedCall::TimeScopedNetworkConfig>
       receive_degradation_configs =
           GetNetworkConfigs(config.env.field_trials(), /*send=*/false);
 
-  std::unique_ptr<Call> call = Call::Create(config);
+  std::unique_ptr<Call> call = Call::Create(std::move(config));
 
   if (!send_degradation_configs.empty() ||
       !receive_degradation_configs.empty()) {
diff --git a/call/create_call.h b/call/create_call.h
index afba088..c1b7e9e 100644
--- a/call/create_call.h
+++ b/call/create_call.h
@@ -18,7 +18,7 @@
 
 namespace webrtc {
 
-std::unique_ptr<Call> CreateCall(const CallConfig& config);
+std::unique_ptr<Call> CreateCall(CallConfig config);
 
 }  // namespace webrtc
 
diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc
index 0259b02..2046f8c 100644
--- a/media/engine/webrtc_video_engine_unittest.cc
+++ b/media/engine/webrtc_video_engine_unittest.cc
@@ -1429,7 +1429,7 @@
       webrtc::Timestamp::Millis(4711));
   CallConfig call_config(CreateEnvironment(
       time_controller.CreateTaskQueueFactory(), time_controller.GetClock()));
-  const std::unique_ptr<Call> call = Call::Create(call_config);
+  const std::unique_ptr<Call> call = Call::Create(std::move(call_config));
 
   // Create send channel.
   const int send_ssrc = 123;
diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc
index 42e46a2..86125f8 100644
--- a/media/engine/webrtc_voice_engine_unittest.cc
+++ b/media/engine/webrtc_voice_engine_unittest.cc
@@ -3883,7 +3883,7 @@
         webrtc::test::MockAudioDeviceModule::CreateNice();
     call_config.audio_state = webrtc::AudioState::Create(config);
   }
-  std::unique_ptr<Call> call = Call::Create(call_config);
+  std::unique_ptr<Call> call = Call::Create(std::move(call_config));
   cricket::WebRtcVoiceSendChannel channel(
       &engine, cricket::MediaConfig(), cricket::AudioOptions(),
       webrtc::CryptoOptions(), call.get(), webrtc::AudioCodecPairId::Create());
diff --git a/pc/media_factory.h b/pc/media_factory.h
index c867846..efc4f0e 100644
--- a/pc/media_factory.h
+++ b/pc/media_factory.h
@@ -34,7 +34,7 @@
  public:
   virtual ~MediaFactory() = default;
 
-  virtual std::unique_ptr<Call> CreateCall(const CallConfig& config) = 0;
+  virtual std::unique_ptr<Call> CreateCall(CallConfig config) = 0;
   virtual std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine(
       const Environment& env,
       PeerConnectionFactoryDependencies& dependencies) = 0;
diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc
index ed0d347..153ee146 100644
--- a/pc/peer_connection_factory.cc
+++ b/pc/peer_connection_factory.cc
@@ -256,9 +256,13 @@
   dependencies.allocator->SetNetworkIgnoreMask(options().network_ignore_mask);
   dependencies.allocator->SetVpnList(configuration.vpn_list);
 
-  std::unique_ptr<Call> call =
-      worker_thread()->BlockingCall([this, &env, &configuration] {
-        return CreateCall_w(env, configuration);
+  std::unique_ptr<NetworkControllerFactoryInterface>
+      network_controller_factory =
+          std::move(dependencies.network_controller_factory);
+  std::unique_ptr<Call> call = worker_thread()->BlockingCall(
+      [this, &env, &configuration, &network_controller_factory] {
+        return CreateCall_w(env, std::move(configuration),
+                            std::move(network_controller_factory));
       });
 
   auto result = PeerConnection::Create(env, context_, options_, std::move(call),
@@ -305,7 +309,9 @@
 
 std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
     const Environment& env,
-    const PeerConnectionInterface::RTCConfiguration& configuration) {
+    const PeerConnectionInterface::RTCConfiguration& configuration,
+    std::unique_ptr<NetworkControllerFactoryInterface>
+        per_call_network_controller_factory) {
   RTC_DCHECK_RUN_ON(worker_thread());
 
   CallConfig call_config(env, network_thread());
@@ -335,8 +341,12 @@
       network_state_predictor_factory_.get();
   call_config.neteq_factory = neteq_factory_.get();
 
-  if (IsTrialEnabled("WebRTC-Bwe-InjectedCongestionController")) {
-    RTC_LOG(LS_INFO) << "Using injected network controller factory";
+  if (per_call_network_controller_factory != nullptr) {
+    RTC_LOG(LS_INFO) << "Using pc injected network controller factory";
+    call_config.per_call_network_controller_factory =
+        std::move(per_call_network_controller_factory);
+  } else if (IsTrialEnabled("WebRTC-Bwe-InjectedCongestionController")) {
+    RTC_LOG(LS_INFO) << "Using pcf injected network controller factory";
     call_config.network_controller_factory =
         injected_network_controller_factory_.get();
   } else {
@@ -348,7 +358,7 @@
   call_config.decode_metronome = decode_metronome_.get();
   call_config.encode_metronome = encode_metronome_.get();
   call_config.pacer_burst_interval = configuration.pacer_burst_interval;
-  return context_->call_factory()->CreateCall(call_config);
+  return context_->call_factory()->CreateCall(std::move(call_config));
 }
 
 bool PeerConnectionFactory::IsTrialEnabled(absl::string_view key) const {
diff --git a/pc/peer_connection_factory.h b/pc/peer_connection_factory.h
index a8af9f5..357d128 100644
--- a/pc/peer_connection_factory.h
+++ b/pc/peer_connection_factory.h
@@ -133,7 +133,9 @@
 
   std::unique_ptr<Call> CreateCall_w(
       const Environment& env,
-      const PeerConnectionInterface::RTCConfiguration& configuration);
+      const PeerConnectionInterface::RTCConfiguration& configuration,
+      std::unique_ptr<NetworkControllerFactoryInterface>
+          network_controller_factory);
 
   rtc::scoped_refptr<ConnectionContext> context_;
   PeerConnectionFactoryInterface::Options options_
diff --git a/pc/test/enable_fake_media.cc b/pc/test/enable_fake_media.cc
index 5497c60..01860a8 100644
--- a/pc/test/enable_fake_media.cc
+++ b/pc/test/enable_fake_media.cc
@@ -36,8 +36,8 @@
         absl::Nonnull<std::unique_ptr<FakeMediaEngine>> fake)
         : fake_(std::move(fake)) {}
 
-    std::unique_ptr<Call> CreateCall(const CallConfig& config) override {
-      return Call::Create(config);
+    std::unique_ptr<Call> CreateCall(CallConfig config) override {
+      return Call::Create(std::move(config));
     }
 
     std::unique_ptr<MediaEngineInterface> CreateMediaEngine(
diff --git a/test/call_test.cc b/test/call_test.cc
index 734571a..543bf93 100644
--- a/test/call_test.cc
+++ b/test/call_test.cc
@@ -128,7 +128,7 @@
       fake_send_audio_device_->RegisterAudioCallback(
           send_config.audio_state->audio_transport());
     }
-    CreateSenderCall(send_config);
+    CreateSenderCall(std::move(send_config));
     if (test->ShouldCreateReceivers()) {
       CallConfig recv_config = RecvCallConfig();
       test->ModifyReceiverBitrateConfig(&recv_config.bitrate_config);
@@ -141,7 +141,7 @@
         fake_recv_audio_device_->RegisterAudioCallback(
             recv_config.audio_state->audio_transport());
       }
-      CreateReceiverCall(recv_config);
+      CreateReceiverCall(std::move(recv_config));
     }
     test->OnCallsCreated(sender_call_.get(), receiver_call_.get());
     CreateReceiveTransport(test->GetReceiveTransportConfig(), test);
@@ -235,22 +235,22 @@
   CreateCalls(SendCallConfig(), RecvCallConfig());
 }
 
-void CallTest::CreateCalls(const CallConfig& sender_config,
-                           const CallConfig& receiver_config) {
-  CreateSenderCall(sender_config);
-  CreateReceiverCall(receiver_config);
+void CallTest::CreateCalls(CallConfig sender_config,
+                           CallConfig receiver_config) {
+  CreateSenderCall(std::move(sender_config));
+  CreateReceiverCall(std::move(receiver_config));
 }
 
 void CallTest::CreateSenderCall() {
   CreateSenderCall(SendCallConfig());
 }
 
-void CallTest::CreateSenderCall(const CallConfig& config) {
-  sender_call_ = Call::Create(config);
+void CallTest::CreateSenderCall(CallConfig config) {
+  sender_call_ = Call::Create(std::move(config));
 }
 
-void CallTest::CreateReceiverCall(const CallConfig& config) {
-  receiver_call_ = Call::Create(config);
+void CallTest::CreateReceiverCall(CallConfig config) {
+  receiver_call_ = Call::Create(std::move(config));
 }
 
 void CallTest::DestroyCalls() {
diff --git a/test/call_test.h b/test/call_test.h
index 46ea7f7..2446a0f 100644
--- a/test/call_test.h
+++ b/test/call_test.h
@@ -72,11 +72,10 @@
   CallConfig RecvCallConfig() const;
 
   void CreateCalls();
-  void CreateCalls(const CallConfig& sender_config,
-                   const CallConfig& receiver_config);
+  void CreateCalls(CallConfig sender_config, CallConfig receiver_config);
   void CreateSenderCall();
-  void CreateSenderCall(const CallConfig& config);
-  void CreateReceiverCall(const CallConfig& config);
+  void CreateSenderCall(CallConfig config);
+  void CreateReceiverCall(CallConfig config);
   void DestroyCalls();
 
   void CreateVideoSendConfig(VideoSendStream::Config* video_config,
diff --git a/test/fuzzers/utils/rtp_replayer.cc b/test/fuzzers/utils/rtp_replayer.cc
index 1b1b968..e5d26f2 100644
--- a/test/fuzzers/utils/rtp_replayer.cc
+++ b/test/fuzzers/utils/rtp_replayer.cc
@@ -73,7 +73,7 @@
 
   // Setup the video streams based on the configuration.
   CallConfig call_config(CreateEnvironment());
-  std::unique_ptr<Call> call(Call::Create(call_config));
+  std::unique_ptr<Call> call(Call::Create(std::move(call_config)));
   SetupVideoStreams(&receive_stream_configs, stream_state.get(), call.get());
 
   // Start replaying the provided stream now that it has been configured.
diff --git a/test/scenario/call_client.cc b/test/scenario/call_client.cc
index 2ec9fec..607f3da 100644
--- a/test/scenario/call_client.cc
+++ b/test/scenario/call_client.cc
@@ -75,7 +75,7 @@
       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);
+  return Call::Create(std::move(call_config));
 }
 
 std::unique_ptr<RtcEventLog> CreateEventLog(
diff --git a/video/end_to_end_tests/multi_stream_tester.cc b/video/end_to_end_tests/multi_stream_tester.cc
index 9fe3433..abd3238 100644
--- a/video/end_to_end_tests/multi_stream_tester.cc
+++ b/video/end_to_end_tests/multi_stream_tester.cc
@@ -48,7 +48,8 @@
   // to make test more stable.
   auto task_queue = env.task_queue_factory().CreateTaskQueue(
       "TaskQueue", TaskQueueFactory::Priority::HIGH);
-  CallConfig config(env);
+  CallConfig sender_config(env);
+  CallConfig receiver_config(env);
   std::unique_ptr<Call> sender_call;
   std::unique_ptr<Call> receiver_call;
   std::unique_ptr<test::DirectTransport> sender_transport;
@@ -66,8 +67,8 @@
   InternalDecoderFactory decoder_factory;
 
   SendTask(task_queue.get(), [&]() {
-    sender_call = Call::Create(config);
-    receiver_call = Call::Create(config);
+    sender_call = Call::Create(std::move(sender_config));
+    receiver_call = Call::Create(std::move(receiver_config));
     sender_transport = CreateSendTransport(task_queue.get(), sender_call.get());
     receiver_transport =
         CreateReceiveTransport(task_queue.get(), receiver_call.get());
diff --git a/video/end_to_end_tests/stats_tests.cc b/video/end_to_end_tests/stats_tests.cc
index ddeeb41..226f5fc 100644
--- a/video/end_to_end_tests/stats_tests.cc
+++ b/video/end_to_end_tests/stats_tests.cc
@@ -527,8 +527,8 @@
 
   SendTask(task_queue(), [this, &test, &send_config, &recv_config,
                           &encoder_config_with_screenshare]() {
-    CreateSenderCall(send_config);
-    CreateReceiverCall(recv_config);
+    CreateSenderCall(std::move(send_config));
+    CreateReceiverCall(std::move(recv_config));
     CreateReceiveTransport(test.GetReceiveTransportConfig(), &test);
     CreateSendTransport(test.GetReceiveTransportConfig(), &test);
 
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index 0c63953..571547e 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -1241,7 +1241,7 @@
       InitializeAudioDevice(&send_call_config, &recv_call_config,
                             params_.audio.use_real_adm);
 
-    CreateCalls(send_call_config, recv_call_config);
+    CreateCalls(std::move(send_call_config), std::move(recv_call_config));
     send_transport = CreateSendTransport();
     recv_transport = CreateReceiveTransport();
   });
@@ -1468,7 +1468,7 @@
       InitializeAudioDevice(&send_call_config, &recv_call_config,
                             params_.audio.use_real_adm);
 
-    CreateCalls(send_call_config, recv_call_config);
+    CreateCalls(std::move(send_call_config), std::move(recv_call_config));
 
     // TODO(minyue): consider if this is a good transport even for audio only
     // calls.