Adds support for real audio devices in video_quality_test.

The old test supported audio but only in combination with a fake ADM.
The new version allows the user to run real video and audio.

Now possible to do:

./out/Debug/video_loopback.exe --audio --use_real_adm

To run the test in loopback using real default audio devices.

By default:

./out/Debug/video_loopback.exe --audio

runs with fake audio devices as before.

Bug: webrtc:9265
Change-Id: Id89924ec0276f929487c71fc6321dcd9cb92693d
Reviewed-on: https://webrtc-review.googlesource.com/96161
Reviewed-by: Minyue Li <minyue@webrtc.org>
Commit-Queue: Henrik Andreassson <henrika@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24463}
diff --git a/api/test/video_quality_test_fixture.h b/api/test/video_quality_test_fixture.h
index deeb848..ed54076 100644
--- a/api/test/video_quality_test_fixture.h
+++ b/api/test/video_quality_test_fixture.h
@@ -63,6 +63,7 @@
       bool enabled;
       bool sync_video;
       bool dtx;
+      bool use_real_adm;
     } audio;
     struct Screenshare {
       bool enabled;
diff --git a/modules/audio_device/BUILD.gn b/modules/audio_device/BUILD.gn
index 6eb02a5..e0c0da8 100644
--- a/modules/audio_device/BUILD.gn
+++ b/modules/audio_device/BUILD.gn
@@ -167,8 +167,6 @@
 # gradually phase out the old design.
 # TODO(henrika): currently only supported on Windows.
 rtc_source_set("audio_device_module_from_input_and_output") {
-  visibility = [ ":*" ]
-
   if (is_win && !build_with_chromium) {
     sources = [
       "include/audio_device_factory.cc",
diff --git a/video/BUILD.gn b/video/BUILD.gn
index a25b42d..02f117e 100644
--- a/video/BUILD.gn
+++ b/video/BUILD.gn
@@ -211,6 +211,9 @@
       "../logging:rtc_event_log_impl_output",
       "../media:rtc_audio_video",
       "../media:rtc_internal_video_codecs",
+      "../modules/audio_device:audio_device_api",
+      "../modules/audio_device:audio_device_module_from_input_and_output",
+      "../modules/audio_device:windows_core_audio_utility",
       "../modules/audio_mixer:audio_mixer_impl",
       "../modules/rtp_rtcp",
       "../modules/video_coding:video_coding",
diff --git a/video/DEPS b/video/DEPS
index 288ecfd..94a394b 100644
--- a/video/DEPS
+++ b/video/DEPS
@@ -4,6 +4,7 @@
   "+logging/rtc_event_log",
   "+media/base",
   "+media/engine",
+  "+modules/audio_device",
   "+modules/audio_mixer",
   "+modules/bitrate_controller",
   "+modules/congestion_controller",
diff --git a/video/video_loopback.cc b/video/video_loopback.cc
index 6f45cf3..52f0a65 100644
--- a/video/video_loopback.cc
+++ b/video/video_loopback.cc
@@ -243,6 +243,10 @@
 
 DEFINE_bool(audio, false, "Add audio stream");
 
+DEFINE_bool(use_real_adm,
+            false,
+            "Use real ADM instead of fake (no effect if audio is false)");
+
 DEFINE_bool(audio_video_sync,
             false,
             "Sync audio and video stream (no effect if"
@@ -307,7 +311,7 @@
                      flags::Clip(),
                      flags::GetCaptureDevice()};
   params.audio = {flags::FLAG_audio, flags::FLAG_audio_video_sync,
-                  flags::FLAG_audio_dtx};
+                  flags::FLAG_audio_dtx, flags::FLAG_use_real_adm};
   params.logging = {flags::FLAG_rtc_event_log_name, flags::FLAG_rtp_dump_name,
                     flags::FLAG_encoded_frame_path};
   params.screenshare[0].enabled = false;
diff --git a/video/video_quality_test.cc b/video/video_quality_test.cc
index a2437d5..2233b31 100644
--- a/video/video_quality_test.cc
+++ b/video/video_quality_test.cc
@@ -20,9 +20,11 @@
 #include "call/fake_network_pipe.h"
 #include "call/simulated_network.h"
 #include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
+#include "media/engine/adm_helpers.h"
 #include "media/engine/internalencoderfactory.h"
 #include "media/engine/vp8_encoder_simulcast_proxy.h"
 #include "media/engine/webrtcvideoengine.h"
+#include "modules/audio_device/include/audio_device.h"
 #include "modules/audio_mixer/audio_mixer_impl.h"
 #include "modules/video_coding/codecs/h264/include/h264.h"
 #include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
@@ -32,6 +34,9 @@
 #include "test/testsupport/fileutils.h"
 #include "test/video_renderer.h"
 #include "video/video_analyzer.h"
+#ifdef WEBRTC_WIN
+#include "modules/audio_device/include/audio_device_factory.h"
+#endif
 
 namespace {
 constexpr char kSyncGroup[] = "av_sync";
@@ -109,7 +114,7 @@
              false, false, ""},
             {false, 640, 480, 30, 50, 800, 800, false, "VP8", 1, -1, 0, false,
              false, false, ""}},
-      audio({false, false, false}),
+      audio({false, false, false, false}),
       screenshare{{false, false, 10, 0}, {false, false, 10, 0}},
       analyzer({"", 0.0, 0.0, 0, "", ""}),
       pipe(),
@@ -871,7 +876,8 @@
   task_queue_.SendTask([this, &send_call_config, &recv_call_config,
                         &send_transport, &recv_transport]() {
     if (params_.audio.enabled)
-      InitializeAudioDevice(&send_call_config, &recv_call_config);
+      InitializeAudioDevice(
+          &send_call_config, &recv_call_config, params_.audio.use_real_adm);
 
     CreateCalls(send_call_config, recv_call_config);
     send_transport = CreateSendTransport();
@@ -969,22 +975,59 @@
   });
 }
 
+rtc::scoped_refptr<AudioDeviceModule> VideoQualityTest::CreateAudioDevice() {
+#ifdef WEBRTC_WIN
+    RTC_LOG(INFO) << "Using latest version of ADM on Windows";
+    // We must initialize the COM library on a thread before we calling any of
+    // the library functions. All COM functions in the ADM will return
+    // CO_E_NOTINITIALIZED otherwise. The legacy ADM for Windows used internal
+    // COM initialization but the new ADM requires COM to be initialized
+    // externally.
+    com_initializer_ = absl::make_unique<webrtc_win::ScopedCOMInitializer>(
+        webrtc_win::ScopedCOMInitializer::kMTA);
+    RTC_CHECK(com_initializer_->Succeeded());
+    RTC_CHECK(webrtc_win::core_audio_utility::IsSupported());
+    RTC_CHECK(webrtc_win::core_audio_utility::IsMMCSSSupported());
+    return CreateWindowsCoreAudioAudioDeviceModule();
+#else
+    // Use legacy factory method on all platforms except Windows.
+    return AudioDeviceModule::Create(AudioDeviceModule::kPlatformDefaultAudio);
+#endif
+}
+
 void VideoQualityTest::InitializeAudioDevice(Call::Config* send_call_config,
-                                             Call::Config* recv_call_config) {
-  rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device =
-      TestAudioDeviceModule::CreateTestAudioDeviceModule(
-          TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
-          TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
+                                             Call::Config* recv_call_config,
+                                             bool use_real_adm) {
+  rtc::scoped_refptr<AudioDeviceModule> audio_device;
+  if (use_real_adm) {
+    // Run test with real ADM (using default audio devices) if user has
+    // explicitly set the --audio and --use_real_adm command-line flags.
+    audio_device = CreateAudioDevice();
+  } else {
+    // By default, create a test ADM which fakes audio.
+    audio_device = TestAudioDeviceModule::CreateTestAudioDeviceModule(
+        TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, 48000),
+        TestAudioDeviceModule::CreateDiscardRenderer(48000), 1.f);
+  }
+  RTC_CHECK(audio_device);
 
   AudioState::Config audio_state_config;
   audio_state_config.audio_mixer = AudioMixerImpl::Create();
   audio_state_config.audio_processing = AudioProcessingBuilder().Create();
-  audio_state_config.audio_device_module = fake_audio_device;
+  audio_state_config.audio_device_module = audio_device;
   send_call_config->audio_state = AudioState::Create(audio_state_config);
-  RTC_CHECK(fake_audio_device->RegisterAudioCallback(
-                send_call_config->audio_state->audio_transport()) == 0);
   recv_call_config->audio_state = AudioState::Create(audio_state_config);
-  fake_audio_device->Init();
+  if (use_real_adm) {
+    // The real ADM requires extra initialization: setting default devices,
+    // setting up number of channels etc. Helper class also calls
+    // AudioDeviceModule::Init().
+    webrtc::adm_helpers::Init(audio_device.get());
+  } else {
+    audio_device->Init();
+  }
+  // Always initialize the ADM before injecting a valid audio transport.
+  RTC_CHECK(audio_device->RegisterAudioCallback(
+            send_call_config->audio_state->audio_transport()) == 0);
 }
 
 void VideoQualityTest::SetupAudio(Transport* transport) {
@@ -1021,6 +1064,7 @@
 }
 
 void VideoQualityTest::RunWithRenderers(const Params& params) {
+  RTC_LOG(INFO) << __FUNCTION__;
   num_video_streams_ = params.call.dual_video ? 2 : 1;
   std::unique_ptr<test::LayerFilteringTransport> send_transport;
   std::unique_ptr<test::DirectTransport> recv_transport;
@@ -1039,7 +1083,8 @@
     Call::Config recv_call_config(&null_event_log);
 
     if (params_.audio.enabled)
-      InitializeAudioDevice(&send_call_config, &recv_call_config);
+      InitializeAudioDevice(
+          &send_call_config, &recv_call_config, params_.audio.use_real_adm);
 
     CreateCalls(send_call_config, recv_call_config);
 
diff --git a/video/video_quality_test.h b/video/video_quality_test.h
index b25d7e1..1bc55ab 100644
--- a/video/video_quality_test.h
+++ b/video/video_quality_test.h
@@ -22,6 +22,9 @@
 #include "test/call_test.h"
 #include "test/frame_generator.h"
 #include "test/layer_filtering_transport.h"
+#ifdef WEBRTC_WIN
+#include "modules/audio_device/win/core_audio_utility_win.h"
+#endif
 
 namespace webrtc {
 
@@ -79,8 +82,11 @@
   void StartThumbnails();
   void StopThumbnails();
   void DestroyThumbnailStreams();
+  // Helper method for creating a real ADM (using hardware) for all platforms.
+  rtc::scoped_refptr<AudioDeviceModule> CreateAudioDevice();
   void InitializeAudioDevice(Call::Config* send_call_config,
-                             Call::Config* recv_call_config);
+                             Call::Config* recv_call_config,
+                             bool use_real_adm);
   void SetupAudio(Transport* transport);
 
   void StartEncodedFrameLogs(VideoSendStream* stream);
@@ -109,6 +115,12 @@
   // separate send streams, the one in CallTest is the number of substreams for
   // a single send stream.
   size_t num_video_streams_;
+
+#ifdef WEBRTC_WIN
+  // Windows Core Audio based ADM needs to run on a COM initialized thread.
+  // Only referenced in combination with --audio --use_real_adm flags.
+  std::unique_ptr<webrtc_win::ScopedCOMInitializer> com_initializer_;
+#endif
 };
 
 }  // namespace webrtc