Introduce new way to enable media in PeerConnectionFactory

instead of requiring to pass in call_factory and media_engine
webrtc users should set media_factory member and media dependencies into PeerConnectionFactoryDependencies

Bug: webrtc:15574
Change-Id: I2dc584fe7afa41c9f170bdc51533396155cdcb06
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325320
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41049}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 1eb3876..bd0f52e 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -35,6 +35,20 @@
   ]
 }
 
+rtc_source_set("enable_media") {
+  visibility = [ "*" ]
+  sources = [
+    "enable_media.cc",
+    "enable_media.h",
+  ]
+  deps = [
+    ":libjingle_peerconnection_api",
+    "../call",
+    "../media:rtc_audio_video",
+    "../pc:media_factory",
+  ]
+}
+
 if (!build_with_chromium) {
   rtc_library("create_peerconnection_factory") {
     visibility = [ "*" ]
@@ -305,6 +319,7 @@
     ":turn_customizer",
     "../call:rtp_interfaces",
     "../p2p:rtc_p2p",
+    "../pc:media_factory",
     "../rtc_base:copy_on_write_buffer",
     "../rtc_base:logging",
     "../rtc_base:network",
diff --git a/api/call/call_factory_interface.h b/api/call/call_factory_interface.h
index fde8cba..1c12352 100644
--- a/api/call/call_factory_interface.h
+++ b/api/call/call_factory_interface.h
@@ -24,6 +24,9 @@
 // This interface exists to allow webrtc to be optionally built without media
 // support (i.e., if only being used for data channels). PeerConnectionFactory
 // is constructed with a CallFactoryInterface, which may or may not be null.
+// TODO(bugs.webrtc.org/15574): Delete this interface when
+// `PeerConnectionFactoryDependencies::call_factory` is removed in favor of
+// `PeerConnectionFactoryDependencies::media_factory`.
 class CallFactoryInterface {
  public:
   virtual ~CallFactoryInterface() = default;
diff --git a/api/enable_media.cc b/api/enable_media.cc
new file mode 100644
index 0000000..4c97ace
--- /dev/null
+++ b/api/enable_media.cc
@@ -0,0 +1,75 @@
+/*
+ *  Copyright 2023 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/enable_media.h"
+
+#include <memory>
+#include <utility>
+
+#include "api/peer_connection_interface.h"
+#include "call/call_factory.h"
+#include "media/engine/webrtc_media_engine.h"
+#include "media/engine/webrtc_video_engine.h"
+#include "media/engine/webrtc_voice_engine.h"
+#include "pc/media_factory.h"
+
+namespace webrtc {
+namespace {
+
+using ::cricket::CompositeMediaEngine;
+using ::cricket::MediaEngineInterface;
+using ::cricket::WebRtcVideoEngine;
+using ::cricket::WebRtcVoiceEngine;
+
+class MediaFactoryImpl : public MediaFactory {
+ public:
+  MediaFactoryImpl() = default;
+  MediaFactoryImpl(const MediaFactoryImpl&) = delete;
+  MediaFactoryImpl& operator=(const MediaFactoryImpl&) = delete;
+  ~MediaFactoryImpl() override = default;
+
+  std::unique_ptr<Call> CreateCall(const CallConfig& config) override {
+    CallFactory call_factory;
+    return static_cast<CallFactoryInterface&>(call_factory).CreateCall(config);
+  }
+
+  std::unique_ptr<MediaEngineInterface> CreateMediaEngine(
+      PeerConnectionFactoryDependencies& deps) override {
+    std::unique_ptr<FieldTrialsView> fallback_trials;
+    const FieldTrialsView* trials;
+    if (deps.trials) {
+      trials = deps.trials.get();
+    } else {
+      fallback_trials = std::make_unique<FieldTrialBasedConfig>();
+      trials = fallback_trials.get();
+    }
+    auto audio_engine = std::make_unique<WebRtcVoiceEngine>(
+        deps.task_queue_factory.get(), deps.adm.get(),
+        std::move(deps.audio_encoder_factory),
+        std::move(deps.audio_decoder_factory), std::move(deps.audio_mixer),
+        std::move(deps.audio_processing), /*audio_frame_processor=*/nullptr,
+        /*owned_audio_frame_processor=*/std::move(deps.audio_frame_processor),
+        *trials);
+    auto video_engine = std::make_unique<WebRtcVideoEngine>(
+        std::move(deps.video_encoder_factory),
+        std::move(deps.video_decoder_factory), *trials);
+    return std::make_unique<CompositeMediaEngine>(std::move(fallback_trials),
+                                                  std::move(audio_engine),
+                                                  std::move(video_engine));
+  }
+};
+
+}  // namespace
+
+void EnableMedia(PeerConnectionFactoryDependencies& deps) {
+  deps.media_factory = std::make_unique<MediaFactoryImpl>();
+}
+
+}  // namespace webrtc
diff --git a/api/enable_media.h b/api/enable_media.h
new file mode 100644
index 0000000..8e0b66b
--- /dev/null
+++ b/api/enable_media.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright 2023 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_ENABLE_MEDIA_H_
+#define API_ENABLE_MEDIA_H_
+
+#include "api/peer_connection_interface.h"
+
+namespace webrtc {
+
+// Enables media support for PeerConnnectionFactory created from `deps`
+// This function is located in its own build target to allow webrtc users that
+// do not need any media to avoid linking media specific code and thus to reduce
+// binary size.
+void EnableMedia(PeerConnectionFactoryDependencies& deps);
+
+}  // namespace webrtc
+
+#endif  // API_ENABLE_MEDIA_H_
diff --git a/api/peer_connection_interface.cc b/api/peer_connection_interface.cc
index 050b61d..dedfd35 100644
--- a/api/peer_connection_interface.cc
+++ b/api/peer_connection_interface.cc
@@ -12,6 +12,8 @@
 
 #include <utility>
 
+#include "pc/media_factory.h"
+
 namespace webrtc {
 
 PeerConnectionInterface::IceServer::IceServer() = default;
diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h
index 9243190..7c81b16 100644
--- a/api/peer_connection_interface.h
+++ b/api/peer_connection_interface.h
@@ -120,6 +120,8 @@
 #include "api/transport/sctp_transport_factory_interface.h"
 #include "api/turn_customizer.h"
 #include "api/video/video_bitrate_allocator_factory.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
 #include "call/rtp_transport_controller_send_factory_interface.h"
 #include "media/base/media_config.h"
 #include "media/base/media_engine.h"
@@ -145,6 +147,9 @@
 
 namespace webrtc {
 
+// MediaFactory class definition is not part of the api.
+class MediaFactory;
+
 // MediaStream container interface.
 class StreamCollectionInterface : public rtc::RefCountInterface {
  public:
@@ -1427,6 +1432,8 @@
   // called without a `port_allocator`.
   std::unique_ptr<rtc::PacketSocketFactory> packet_socket_factory;
   std::unique_ptr<TaskQueueFactory> task_queue_factory;
+  // TODO(bugs.webrtc.org/15574): Deprecate `media_engine` and `call_factory`
+  // when chromium and webrtc are updated to use `media_factory` instead.
   std::unique_ptr<cricket::MediaEngineInterface> media_engine;
   std::unique_ptr<CallFactoryInterface> call_factory;
   std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory;
@@ -1447,6 +1454,23 @@
   std::unique_ptr<RtpTransportControllerSendFactoryInterface>
       transport_controller_send_factory;
   std::unique_ptr<Metronome> metronome;
+
+  // Media specific dependencies. Unused when `media_factory == nullptr`.
+  rtc::scoped_refptr<AudioDeviceModule> adm;
+  rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory;
+  rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory;
+  rtc::scoped_refptr<AudioMixer> audio_mixer;
+  rtc::scoped_refptr<AudioProcessing> audio_processing;
+  std::unique_ptr<AudioFrameProcessor> audio_frame_processor;
+  std::unique_ptr<VideoEncoderFactory> video_encoder_factory;
+  std::unique_ptr<VideoDecoderFactory> video_decoder_factory;
+
+  // The `media_factory` members allows webrtc to be optionally built without
+  // media support (i.e., if only being used for data channels).
+  // By default media is disabled. To enable media call
+  // `EnableMedia(PeerConnectionFactoryDependencies&)`. Definition of the
+  // `MediaFactory` interface is a webrtc implementation detail.
+  std::unique_ptr<MediaFactory> media_factory;
 };
 
 // PeerConnectionFactoryInterface is the factory interface used for creating
diff --git a/media/engine/webrtc_media_engine.h b/media/engine/webrtc_media_engine.h
index 0f6dce3..fa4046b 100644
--- a/media/engine/webrtc_media_engine.h
+++ b/media/engine/webrtc_media_engine.h
@@ -63,6 +63,8 @@
 // CreateMediaEngine may be called on any thread, though the engine is
 // only expected to be used on one thread, internally called the "worker
 // thread". This is the thread Init must be called on.
+// TODO(bugs.webrtc.org/15574): Deprecate this helper in favor of creating
+// media engine with `PeerConnectionFactoryDependencies::media_factory`.
 RTC_EXPORT std::unique_ptr<MediaEngineInterface> CreateMediaEngine(
     MediaEngineDependencies dependencies);
 
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 7c22a26..7952ffd 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -314,6 +314,15 @@
   ]
 }
 
+rtc_source_set("media_factory") {
+  sources = [ "media_factory.h" ]
+  deps = [
+    "../api:callfactory_api",
+    "../call:call_interfaces",
+    "../media:rtc_media_base",
+  ]
+}
+
 rtc_source_set("media_session") {
   visibility = [ "*" ]  # Used by Chrome
   sources = [
@@ -919,6 +928,7 @@
     "connection_context.h",
   ]
   deps = [
+    ":media_factory",
     "../api:callfactory_api",
     "../api:field_trials_view",
     "../api:libjingle_peerconnection_api",
@@ -2405,6 +2415,7 @@
       "../api:create_peerconnection_factory",
       "../api:dtls_transport_interface",
       "../api:dtmf_sender_interface",
+      "../api:enable_media",
       "../api:fake_frame_decryptor",
       "../api:fake_frame_encryptor",
       "../api:field_trials_view",
diff --git a/pc/connection_context.cc b/pc/connection_context.cc
index f436e27..1347008 100644
--- a/pc/connection_context.cc
+++ b/pc/connection_context.cc
@@ -17,6 +17,7 @@
 #include "api/transport/field_trial_based_config.h"
 #include "media/base/media_engine.h"
 #include "media/sctp/sctp_transport_factory.h"
+#include "pc/media_factory.h"
 #include "rtc_base/helpers.h"
 #include "rtc_base/internal/default_socket_server.h"
 #include "rtc_base/socket_server.h"
@@ -78,6 +79,13 @@
 // Static
 rtc::scoped_refptr<ConnectionContext> ConnectionContext::Create(
     PeerConnectionFactoryDependencies* dependencies) {
+  if (dependencies->media_factory != nullptr) {
+    RTC_CHECK(dependencies->media_engine == nullptr)
+        << "media_factory replaces media_engine. Do not set media_engine.";
+    RTC_CHECK(dependencies->call_factory == nullptr)
+        << "media_factory replaces call_factory. Do not set call_factory.";
+  }
+
   return rtc::scoped_refptr<ConnectionContext>(
       new ConnectionContext(dependencies));
 }
@@ -98,11 +106,16 @@
                                         wraps_current_thread_)),
       trials_(dependencies->trials ? std::move(dependencies->trials)
                                    : std::make_unique<FieldTrialBasedConfig>()),
-      media_engine_(std::move(dependencies->media_engine)),
+      media_engine_(
+          dependencies->media_factory != nullptr
+              ? dependencies->media_factory->CreateMediaEngine(*dependencies)
+              : std::move(dependencies->media_engine)),
       network_monitor_factory_(
           std::move(dependencies->network_monitor_factory)),
       default_network_manager_(std::move(dependencies->network_manager)),
-      call_factory_(std::move(dependencies->call_factory)),
+      call_factory_(dependencies->media_factory != nullptr
+                        ? std::move(dependencies->media_factory)
+                        : std::move(dependencies->call_factory)),
       default_socket_factory_(std::move(dependencies->packet_socket_factory)),
       sctp_factory_(
           MaybeCreateSctpFactory(std::move(dependencies->sctp_factory),
diff --git a/pc/media_factory.h b/pc/media_factory.h
new file mode 100644
index 0000000..323744a
--- /dev/null
+++ b/pc/media_factory.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright 2023 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 PC_MEDIA_FACTORY_H_
+#define PC_MEDIA_FACTORY_H_
+
+#include <memory>
+
+#include "api/call/call_factory_interface.h"
+#include "call/call.h"
+#include "call/call_config.h"
+#include "media/base/media_engine.h"
+
+namespace webrtc {
+
+// PeerConnectionFactoryDependencies is forward declared because of circular
+// dependency between MediaFactory and PeerConnectionFactoryDependencies:
+// PeerConnectionFactoryDependencies keeps an instance of MediaFactory and thus
+// needs to know how to destroy it.
+// MediaFactory mentions PeerConnectionFactoryDependencies in api, but does not
+// need its full definition.
+struct PeerConnectionFactoryDependencies;
+
+// Interface repsponsible for constructing media specific classes for
+// PeerConnectionFactory and PeerConnection.
+// TODO(bugs.webrtc.org/15574): Delete CallFactoryInterface inheritance
+// when call_factory is removed from PeerConnectionFactoryDependencies.
+class MediaFactory : public CallFactoryInterface {
+ public:
+  virtual ~MediaFactory() = default;
+
+  std::unique_ptr<Call> CreateCall(const CallConfig& config) override = 0;
+  virtual std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine(
+      PeerConnectionFactoryDependencies& dependencies) = 0;
+};
+
+}  // namespace webrtc
+
+#endif  // PC_MEDIA_FACTORY_H_
diff --git a/pc/peer_connection_factory_unittest.cc b/pc/peer_connection_factory_unittest.cc
index 11e232c..91772ec 100644
--- a/pc/peer_connection_factory_unittest.cc
+++ b/pc/peer_connection_factory_unittest.cc
@@ -20,6 +20,7 @@
 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
 #include "api/create_peerconnection_factory.h"
 #include "api/data_channel_interface.h"
+#include "api/enable_media.h"
 #include "api/jsep.h"
 #include "api/media_stream_interface.h"
 #include "api/task_queue/default_task_queue_factory.h"
@@ -35,7 +36,6 @@
 #include "api/video_codecs/video_encoder_factory_template_libvpx_vp9_adapter.h"
 #include "api/video_codecs/video_encoder_factory_template_open_h264_adapter.h"
 #include "media/base/fake_frame_source.h"
-#include "media/engine/webrtc_media_engine.h"
 #include "modules/audio_device/include/audio_device.h"
 #include "modules/audio_processing/include/audio_processing.h"
 #include "p2p/base/fake_port_allocator.h"
@@ -272,29 +272,20 @@
   pcf_dependencies.worker_thread = rtc::Thread::Current();
   pcf_dependencies.network_thread = rtc::Thread::Current();
   pcf_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
-  pcf_dependencies.call_factory = CreateCallFactory();
-  pcf_dependencies.trials = std::make_unique<webrtc::FieldTrialBasedConfig>();
+  pcf_dependencies.trials = std::make_unique<FieldTrialBasedConfig>();
 
-  cricket::MediaEngineDependencies media_dependencies;
-  media_dependencies.task_queue_factory =
-      pcf_dependencies.task_queue_factory.get();
-  media_dependencies.adm = rtc::scoped_refptr<webrtc::AudioDeviceModule>(
-      FakeAudioCaptureModule::Create());
-  media_dependencies.audio_encoder_factory =
-      webrtc::CreateBuiltinAudioEncoderFactory();
-  media_dependencies.audio_decoder_factory =
-      webrtc::CreateBuiltinAudioDecoderFactory();
-  media_dependencies.video_encoder_factory =
+  pcf_dependencies.adm = FakeAudioCaptureModule::Create();
+  pcf_dependencies.audio_encoder_factory = CreateBuiltinAudioEncoderFactory();
+  pcf_dependencies.audio_decoder_factory = CreateBuiltinAudioDecoderFactory();
+  pcf_dependencies.video_encoder_factory =
       std::make_unique<VideoEncoderFactoryTemplate<
           LibvpxVp8EncoderTemplateAdapter, LibvpxVp9EncoderTemplateAdapter,
           OpenH264EncoderTemplateAdapter, LibaomAv1EncoderTemplateAdapter>>();
-  media_dependencies.video_decoder_factory =
+  pcf_dependencies.video_decoder_factory =
       std::make_unique<VideoDecoderFactoryTemplate<
           LibvpxVp8DecoderTemplateAdapter, LibvpxVp9DecoderTemplateAdapter,
           OpenH264DecoderTemplateAdapter, Dav1dDecoderTemplateAdapter>>(),
-  media_dependencies.trials = pcf_dependencies.trials.get();
-  pcf_dependencies.media_engine =
-      cricket::CreateMediaEngine(std::move(media_dependencies));
+  EnableMedia(pcf_dependencies);
 
   rtc::scoped_refptr<webrtc::ConnectionContext> context =
       ConnectionContext::Create(&pcf_dependencies);