From b907f1f9f88189edd54c3f42ba8f2bdacf3d37b6 Mon Sep 17 00:00:00 2001 From: Artem Titov Date: Thu, 2 Apr 2020 00:07:23 +0200 Subject: [PATCH] Extract test peer creation into separate file Extract test peer creation into separate file to simplify code and increase readability. Also it is 1st step in bigger refactoring of PC level test fixture implementation to make it more granular and reusable. Change-Id: I687a17bda33a8eebc1ef0ddc0d54572e095fd709 Bug: webrtc:11479 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/172628 Reviewed-by: Mirko Bonadei Commit-Queue: Artem Titov Cr-Commit-Position: refs/heads/master@{#30980} --- test/DEPS | 4 + test/pc/e2e/BUILD.gn | 35 +- test/pc/e2e/peer_connection_quality_test.cc | 13 +- test/pc/e2e/test_peer.cc | 343 +------------------- test/pc/e2e/test_peer.h | 50 +-- test/pc/e2e/test_peer_factory.cc | 330 +++++++++++++++++++ test/pc/e2e/test_peer_factory.h | 71 ++++ 7 files changed, 437 insertions(+), 409 deletions(-) create mode 100644 test/pc/e2e/test_peer_factory.cc create mode 100644 test/pc/e2e/test_peer_factory.h diff --git a/test/DEPS b/test/DEPS index c4634f864c..9bf5867bc5 100644 --- a/test/DEPS +++ b/test/DEPS @@ -54,6 +54,10 @@ specific_include_rules = { "+pc", "+p2p", ], + ".*test_peer_factory\.(h|cc)": [ + "+pc", + "+p2p", + ], ".*network_emulation_pc_unittest\.cc": [ "+pc/peer_connection_wrapper.h", "+pc/test/mock_peer_connection_observers.h", diff --git a/test/pc/e2e/BUILD.gn b/test/pc/e2e/BUILD.gn index 492736fb33..c01c749dc8 100644 --- a/test/pc/e2e/BUILD.gn +++ b/test/pc/e2e/BUILD.gn @@ -220,35 +220,41 @@ if (rtc_include_tests) { "test_peer.cc", "test_peer.h", ] + deps = [ + ":peer_connection_quality_test_params", + "../../../api:frame_generator_api", + "../../../api:scoped_refptr", + "../../../modules/audio_processing:api", + "../../../pc:peerconnection_wrapper", + "//third_party/abseil-cpp/absl/memory", + ] + } + + rtc_library("test_peer_factory") { + visibility = [ "*" ] + testonly = true + sources = [ + "test_peer_factory.cc", + "test_peer_factory.h", + ] deps = [ ":echo_emulation", ":peer_connection_quality_test_params", + ":test_peer", ":video_quality_analyzer_injection_helper", - "../../../api:frame_generator_api", + "../..:copy_to_file_audio_capturer", "../../../api:peer_connection_quality_test_fixture_api", - "../../../api:scoped_refptr", "../../../api/rtc_event_log:rtc_event_log_factory", - "../../../api/task_queue", "../../../api/task_queue:default_task_queue_factory", "../../../api/video_codecs:builtin_video_decoder_factory", "../../../api/video_codecs:builtin_video_encoder_factory", "../../../media:rtc_audio_video", - "../../../media:rtc_media_base", "../../../media:rtc_media_engine_defaults", - "../../../modules/audio_device:audio_device_api", "../../../modules/audio_device:audio_device_impl", - "../../../modules/audio_processing:api", - "../../../modules/audio_processing/aec_dump:aec_dump", + "../../../modules/audio_processing/aec_dump", "../../../p2p:rtc_p2p", - "../../../pc:pc_test_utils", - "../../../pc:peerconnection_wrapper", - "../../../rtc_base", - "../../../rtc_base:rtc_base_approved", "../../../rtc_base:rtc_task_queue", - "../../../test:copy_to_file_audio_capturer", - "../../../test:video_test_common", "//third_party/abseil-cpp/absl/memory", - "//third_party/abseil-cpp/absl/types:optional", ] } @@ -269,6 +275,7 @@ if (rtc_include_tests) { ":single_process_encoded_image_data_injector", ":stats_poller", ":test_peer", + ":test_peer_factory", ":video_quality_analyzer_injection_helper", ":video_quality_metrics_reporter", "../..:field_trial", diff --git a/test/pc/e2e/peer_connection_quality_test.cc b/test/pc/e2e/peer_connection_quality_test.cc index f16389ff69..bf25443eab 100644 --- a/test/pc/e2e/peer_connection_quality_test.cc +++ b/test/pc/e2e/peer_connection_quality_test.cc @@ -37,6 +37,7 @@ #include "test/pc/e2e/analyzer/video/default_video_quality_analyzer.h" #include "test/pc/e2e/analyzer/video/video_quality_metrics_reporter.h" #include "test/pc/e2e/stats_poller.h" +#include "test/pc/e2e/test_peer_factory.h" #include "test/platform_video_capturer.h" #include "test/testsupport/file_utils.h" @@ -278,15 +279,15 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { // Audio streams are intercepted in AudioDeviceModule, so if it is required to // catch output of Alice's stream, Alice's output_dump_file_name should be // passed to Bob's TestPeer setup as audio output file name. - absl::optional alice_remote_audio_config = - TestPeer::CreateRemoteAudioConfig(bob_params->audio_config); - absl::optional bob_remote_audio_config = - TestPeer::CreateRemoteAudioConfig(alice_params->audio_config); + absl::optional alice_remote_audio_config = + RemotePeerAudioConfig::Create(bob_params->audio_config); + absl::optional bob_remote_audio_config = + RemotePeerAudioConfig::Create(alice_params->audio_config); // Copy Alice and Bob video configs to correctly pass them into lambdas. std::vector alice_video_configs = alice_params->video_configs; std::vector bob_video_configs = bob_params->video_configs; - alice_ = TestPeer::CreateTestPeer( + alice_ = TestPeerFactory::CreateTestPeer( std::move(alice_components), std::move(alice_params), std::move(alice_video_generators), std::make_unique( @@ -298,7 +299,7 @@ void PeerConnectionE2EQualityTest::Run(RunParams run_params) { video_quality_analyzer_injection_helper_.get(), signaling_thread.get(), alice_remote_audio_config, run_params.video_encoder_bitrate_multiplier, run_params.echo_emulation_config, task_queue_.get()); - bob_ = TestPeer::CreateTestPeer( + bob_ = TestPeerFactory::CreateTestPeer( std::move(bob_components), std::move(bob_params), std::move(bob_video_generators), std::make_unique( diff --git a/test/pc/e2e/test_peer.cc b/test/pc/e2e/test_peer.cc index 1b80633a0b..a95cd8db5a 100644 --- a/test/pc/e2e/test_peer.cc +++ b/test/pc/e2e/test_peer.cc @@ -9,356 +9,15 @@ */ #include "test/pc/e2e/test_peer.h" +#include #include #include "absl/memory/memory.h" -#include "absl/types/optional.h" -#include "api/rtc_event_log/rtc_event_log_factory.h" #include "api/scoped_refptr.h" -#include "api/task_queue/default_task_queue_factory.h" -#include "api/task_queue/task_queue_factory.h" -#include "api/video_codecs/builtin_video_decoder_factory.h" -#include "api/video_codecs/builtin_video_encoder_factory.h" -#include "media/engine/webrtc_media_engine.h" -#include "media/engine/webrtc_media_engine_defaults.h" -#include "modules/audio_device/include/audio_device.h" -#include "modules/audio_processing/aec_dump/aec_dump_factory.h" #include "modules/audio_processing/include/audio_processing.h" -#include "p2p/client/basic_port_allocator.h" -#include "rtc_base/location.h" -#include "test/pc/e2e/echo/echo_emulation.h" -#include "test/testsupport/copy_to_file_audio_capturer.h" namespace webrtc { namespace webrtc_pc_e2e { -namespace { - -using RemotePeerAudioConfig = - ::webrtc::webrtc_pc_e2e::TestPeer::RemotePeerAudioConfig; -using AudioConfig = - ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::AudioConfig; -using EchoEmulationConfig = ::webrtc::webrtc_pc_e2e:: - PeerConnectionE2EQualityTestFixture::EchoEmulationConfig; - -constexpr int16_t kGeneratedAudioMaxAmplitude = 32000; -constexpr int kDefaultSamplingFrequencyInHz = 48000; - -// Sets mandatory entities in injectable components like |pcf_dependencies| -// and |pc_dependencies| if they are omitted. Also setup required -// dependencies, that won't be specially provided by factory and will be just -// transferred to peer connection creation code. -void SetMandatoryEntities(InjectableComponents* components) { - RTC_DCHECK(components->pcf_dependencies); - RTC_DCHECK(components->pc_dependencies); - - // Setup required peer connection factory dependencies. - if (components->pcf_dependencies->task_queue_factory == nullptr) { - components->pcf_dependencies->task_queue_factory = - CreateDefaultTaskQueueFactory(); - } - if (components->pcf_dependencies->call_factory == nullptr) { - components->pcf_dependencies->call_factory = webrtc::CreateCallFactory(); - } - if (components->pcf_dependencies->event_log_factory == nullptr) { - components->pcf_dependencies->event_log_factory = - std::make_unique( - components->pcf_dependencies->task_queue_factory.get()); - } -} - -class TestPeerComponents { - public: - TestPeerComponents(std::unique_ptr components, - const Params& params, - MockPeerConnectionObserver* observer, - VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, - rtc::Thread* signaling_thread, - absl::optional remote_audio_config, - double bitrate_multiplier, - absl::optional echo_emulation_config, - rtc::TaskQueue* task_queue) - : audio_config_opt_(params.audio_config), - observer_(observer), - video_analyzer_helper_(video_analyzer_helper), - signaling_thread_(signaling_thread), - remote_audio_config_(std::move(remote_audio_config)), - bitrate_multiplier_(bitrate_multiplier), - echo_emulation_config_(std::move(echo_emulation_config)) { - for (auto& video_config : params.video_configs) { - // Stream label should be set by fixture implementation here. - RTC_DCHECK(video_config.stream_label); - bool res = - stream_required_spatial_index_ - .insert({*video_config.stream_label, - video_config.simulcast_config - ? absl::optional(video_config.simulcast_config - ->target_spatial_index) - : absl::nullopt}) - .second; - RTC_DCHECK(res) << "Duplicate video_config.stream_label=" - << *video_config.stream_label; - } - - // Create audio processing, that will be used to create media engine that - // then will be added into peer connection. See CreateMediaEngine(...). - audio_processing_ = webrtc::AudioProcessingBuilder().Create(); - if (params.aec_dump_path) { - audio_processing_->AttachAecDump( - AecDumpFactory::Create(*params.aec_dump_path, -1, task_queue)); - } - - // Create peer connection factory. - PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies( - std::move(components->pcf_dependencies), components->network_thread); - peer_connection_factory_ = - CreateModularPeerConnectionFactory(std::move(pcf_deps)); - - // Create peer connection. - PeerConnectionDependencies pc_deps = - CreatePCDependencies(std::move(components->pc_dependencies)); - peer_connection_ = peer_connection_factory_->CreatePeerConnection( - params.rtc_configuration, std::move(pc_deps)); - peer_connection_->SetBitrate(params.bitrate_params); - } - - rtc::scoped_refptr peer_connection_factory() - const { - return peer_connection_factory_; - } - rtc::scoped_refptr peer_connection() const { - return peer_connection_; - } - rtc::scoped_refptr audio_processing() const { - return audio_processing_; - } - - private: - // Creates PeerConnectionFactoryDependencies objects, providing entities - // from InjectableComponents::PeerConnectionFactoryComponents and also - // creating entities, that are required for correct injection of media quality - // analyzers. - PeerConnectionFactoryDependencies CreatePCFDependencies( - std::unique_ptr pcf_dependencies, - rtc::Thread* network_thread) { - PeerConnectionFactoryDependencies pcf_deps; - pcf_deps.network_thread = network_thread; - pcf_deps.signaling_thread = signaling_thread_; - pcf_deps.media_engine = CreateMediaEngine(pcf_dependencies.get()); - - pcf_deps.call_factory = std::move(pcf_dependencies->call_factory); - pcf_deps.event_log_factory = std::move(pcf_dependencies->event_log_factory); - pcf_deps.task_queue_factory = - std::move(pcf_dependencies->task_queue_factory); - - if (pcf_dependencies->fec_controller_factory != nullptr) { - pcf_deps.fec_controller_factory = - std::move(pcf_dependencies->fec_controller_factory); - } - if (pcf_dependencies->network_controller_factory != nullptr) { - pcf_deps.network_controller_factory = - std::move(pcf_dependencies->network_controller_factory); - } - if (pcf_dependencies->media_transport_factory != nullptr) { - pcf_deps.media_transport_factory = - std::move(pcf_dependencies->media_transport_factory); - } - if (pcf_dependencies->neteq_factory != nullptr) { - pcf_deps.neteq_factory = std::move(pcf_dependencies->neteq_factory); - } - - return pcf_deps; - } - - std::unique_ptr CreateMediaEngine( - PeerConnectionFactoryComponents* pcf_dependencies) { - cricket::MediaEngineDependencies media_deps; - media_deps.task_queue_factory = pcf_dependencies->task_queue_factory.get(); - media_deps.adm = CreateAudioDeviceModule(media_deps.task_queue_factory); - media_deps.audio_processing = audio_processing_; - media_deps.video_encoder_factory = - CreateVideoEncoderFactory(pcf_dependencies); - media_deps.video_decoder_factory = - CreateVideoDecoderFactory(pcf_dependencies); - webrtc::SetMediaEngineDefaults(&media_deps); - return cricket::CreateMediaEngine(std::move(media_deps)); - } - - rtc::scoped_refptr CreateAudioDeviceModule( - TaskQueueFactory* task_queue_factory) { - std::unique_ptr renderer = - CreateAudioRenderer(remote_audio_config_); - std::unique_ptr capturer = - CreateAudioCapturer(audio_config_opt_); - RTC_DCHECK(renderer); - RTC_DCHECK(capturer); - - // Setup echo emulation if required. - if (echo_emulation_config_) { - capturer = std::make_unique( - std::move(capturer), *echo_emulation_config_); - renderer = std::make_unique( - std::move(renderer), - static_cast(capturer.get())); - } - - // Setup input stream dumping if required. - if (audio_config_opt_ && audio_config_opt_->input_dump_file_name) { - capturer = std::make_unique( - std::move(capturer), audio_config_opt_->input_dump_file_name.value()); - } - - return TestAudioDeviceModule::Create(task_queue_factory, - std::move(capturer), - std::move(renderer), /*speed=*/1.f); - } - - std::unique_ptr CreateAudioRenderer( - const absl::optional& config) { - if (!config) { - // Return default renderer because we always require some renderer. - return TestAudioDeviceModule::CreateDiscardRenderer( - kDefaultSamplingFrequencyInHz); - } - if (config->output_file_name) { - return TestAudioDeviceModule::CreateBoundedWavFileWriter( - config->output_file_name.value(), config->sampling_frequency_in_hz); - } - return TestAudioDeviceModule::CreateDiscardRenderer( - config->sampling_frequency_in_hz); - } - - std::unique_ptr CreateAudioCapturer( - const absl::optional& audio_config) { - if (!audio_config) { - // If we have no audio config we still need to provide some audio device. - // In such case use generated capturer. Despite of we provided audio here, - // in test media setup audio stream won't be added into peer connection. - return TestAudioDeviceModule::CreatePulsedNoiseCapturer( - kGeneratedAudioMaxAmplitude, kDefaultSamplingFrequencyInHz); - } - - switch (audio_config->mode) { - case AudioConfig::Mode::kGenerated: - return TestAudioDeviceModule::CreatePulsedNoiseCapturer( - kGeneratedAudioMaxAmplitude, - audio_config->sampling_frequency_in_hz); - case AudioConfig::Mode::kFile: - RTC_DCHECK(audio_config->input_file_name); - return TestAudioDeviceModule::CreateWavFileReader( - audio_config->input_file_name.value(), /*repeat=*/true); - } - } - - std::unique_ptr CreateVideoEncoderFactory( - PeerConnectionFactoryComponents* pcf_dependencies) { - std::unique_ptr video_encoder_factory; - if (pcf_dependencies->video_encoder_factory != nullptr) { - video_encoder_factory = - std::move(pcf_dependencies->video_encoder_factory); - } else { - video_encoder_factory = CreateBuiltinVideoEncoderFactory(); - } - return video_analyzer_helper_->WrapVideoEncoderFactory( - std::move(video_encoder_factory), bitrate_multiplier_, - stream_required_spatial_index_); - } - - std::unique_ptr CreateVideoDecoderFactory( - PeerConnectionFactoryComponents* pcf_dependencies) { - std::unique_ptr video_decoder_factory; - if (pcf_dependencies->video_decoder_factory != nullptr) { - video_decoder_factory = - std::move(pcf_dependencies->video_decoder_factory); - } else { - video_decoder_factory = CreateBuiltinVideoDecoderFactory(); - } - return video_analyzer_helper_->WrapVideoDecoderFactory( - std::move(video_decoder_factory)); - } - - // Creates PeerConnectionDependencies objects, providing entities - // from InjectableComponents::PeerConnectionComponents. - PeerConnectionDependencies CreatePCDependencies( - std::unique_ptr pc_dependencies) { - PeerConnectionDependencies pc_deps(observer_); - - auto port_allocator = std::make_unique( - pc_dependencies->network_manager); - - // This test does not support TCP - int flags = cricket::PORTALLOCATOR_DISABLE_TCP; - port_allocator->set_flags(port_allocator->flags() | flags); - - pc_deps.allocator = std::move(port_allocator); - - if (pc_dependencies->async_resolver_factory != nullptr) { - pc_deps.async_resolver_factory = - std::move(pc_dependencies->async_resolver_factory); - } - if (pc_dependencies->cert_generator != nullptr) { - pc_deps.cert_generator = std::move(pc_dependencies->cert_generator); - } - if (pc_dependencies->tls_cert_verifier != nullptr) { - pc_deps.tls_cert_verifier = std::move(pc_dependencies->tls_cert_verifier); - } - if (pc_dependencies->ice_transport_factory != nullptr) { - pc_deps.ice_transport_factory = - std::move(pc_dependencies->ice_transport_factory); - } - return pc_deps; - } - - rtc::scoped_refptr peer_connection_factory_; - rtc::scoped_refptr peer_connection_; - rtc::scoped_refptr audio_processing_; - - std::map> stream_required_spatial_index_; - absl::optional audio_config_opt_; - MockPeerConnectionObserver* observer_; - VideoQualityAnalyzerInjectionHelper* video_analyzer_helper_; - rtc::Thread* signaling_thread_; - absl::optional remote_audio_config_; - double bitrate_multiplier_; - absl::optional echo_emulation_config_; -}; - -} // namespace - -absl::optional TestPeer::CreateRemoteAudioConfig( - absl::optional config) { - if (!config) { - return absl::nullopt; - } - return RemotePeerAudioConfig(config.value()); -} - -std::unique_ptr TestPeer::CreateTestPeer( - std::unique_ptr components, - std::unique_ptr params, - std::vector> - video_generators, - std::unique_ptr observer, - VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, - rtc::Thread* signaling_thread, - absl::optional remote_audio_config, - double bitrate_multiplier, - absl::optional echo_emulation_config, - rtc::TaskQueue* task_queue) { - RTC_DCHECK(components); - RTC_DCHECK(params); - RTC_DCHECK_EQ(params->video_configs.size(), video_generators.size()); - SetMandatoryEntities(components.get()); - params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan; - - TestPeerComponents tpc(std::move(components), *params, observer.get(), - video_analyzer_helper, signaling_thread, - std::move(remote_audio_config), bitrate_multiplier, - echo_emulation_config, task_queue); - - return absl::WrapUnique(new TestPeer( - tpc.peer_connection_factory(), tpc.peer_connection(), std::move(observer), - std::move(params), std::move(video_generators), tpc.audio_processing())); -} bool TestPeer::AddIceCandidates( std::vector> candidates) { diff --git a/test/pc/e2e/test_peer.h b/test/pc/e2e/test_peer.h index 3487720887..cd6435ca40 100644 --- a/test/pc/e2e/test_peer.h +++ b/test/pc/e2e/test_peer.h @@ -12,20 +12,11 @@ #define TEST_PC_E2E_TEST_PEER_H_ #include -#include #include #include "absl/memory/memory.h" #include "api/test/frame_generator_interface.h" -#include "api/test/peerconnection_quality_test_fixture.h" -#include "media/base/media_engine.h" -#include "modules/audio_device/include/test_audio_device.h" #include "pc/peer_connection_wrapper.h" -#include "pc/test/mock_peer_connection_observers.h" -#include "rtc_base/network.h" -#include "rtc_base/task_queue.h" -#include "rtc_base/thread.h" -#include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h" #include "test/pc/e2e/peer_connection_quality_test_params.h" namespace webrtc { @@ -35,43 +26,6 @@ namespace webrtc_pc_e2e { class TestPeer final : public PeerConnectionWrapper { public: using PeerConnectionWrapper::PeerConnectionWrapper; - using VideoConfig = PeerConnectionE2EQualityTestFixture::VideoConfig; - using AudioConfig = PeerConnectionE2EQualityTestFixture::AudioConfig; - using EchoEmulationConfig = - PeerConnectionE2EQualityTestFixture::EchoEmulationConfig; - - struct RemotePeerAudioConfig { - RemotePeerAudioConfig(AudioConfig config) - : sampling_frequency_in_hz(config.sampling_frequency_in_hz), - output_file_name(config.output_dump_file_name) {} - - int sampling_frequency_in_hz; - absl::optional output_file_name; - }; - - static absl::optional CreateRemoteAudioConfig( - absl::optional config); - - // Setups all components, that should be provided to WebRTC - // PeerConnectionFactory and PeerConnection creation methods, - // also will setup dependencies, that are required for media analyzers - // injection. - // - // |signaling_thread| will be provided by test fixture implementation. - // |params| - describes current peer parameters, like current peer video - // streams and audio streams - static std::unique_ptr CreateTestPeer( - std::unique_ptr components, - std::unique_ptr params, - std::vector> - video_generators, - std::unique_ptr observer, - VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, - rtc::Thread* signaling_thread, - absl::optional remote_audio_config, - double bitrate_multiplier, - absl::optional echo_emulation_config, - rtc::TaskQueue* task_queue); Params* params() const { return params_.get(); } std::unique_ptr ReleaseVideoGenerator( @@ -85,7 +39,8 @@ class TestPeer final : public PeerConnectionWrapper { bool AddIceCandidates( std::vector> candidates); - private: + protected: + friend class TestPeerFactory; TestPeer(rtc::scoped_refptr pc_factory, rtc::scoped_refptr pc, std::unique_ptr observer, @@ -94,6 +49,7 @@ class TestPeer final : public PeerConnectionWrapper { video_generators, rtc::scoped_refptr audio_processing); + private: std::unique_ptr params_; std::vector> video_generators_; rtc::scoped_refptr audio_processing_; diff --git a/test/pc/e2e/test_peer_factory.cc b/test/pc/e2e/test_peer_factory.cc new file mode 100644 index 0000000000..84045091ce --- /dev/null +++ b/test/pc/e2e/test_peer_factory.cc @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2020 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 "test/pc/e2e/test_peer_factory.h" + +#include + +#include "absl/memory/memory.h" +#include "api/task_queue/default_task_queue_factory.h" +#include "api/video_codecs/builtin_video_decoder_factory.h" +#include "api/video_codecs/builtin_video_encoder_factory.h" +#include "media/engine/webrtc_media_engine.h" +#include "media/engine/webrtc_media_engine_defaults.h" +#include "modules/audio_processing/aec_dump/aec_dump_factory.h" +#include "p2p/client/basic_port_allocator.h" +#include "test/pc/e2e/echo/echo_emulation.h" +#include "test/testsupport/copy_to_file_audio_capturer.h" + +namespace webrtc { +namespace webrtc_pc_e2e { +namespace { + +using AudioConfig = + ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::AudioConfig; +using VideoConfig = + ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig; +using EchoEmulationConfig = ::webrtc::webrtc_pc_e2e:: + PeerConnectionE2EQualityTestFixture::EchoEmulationConfig; + +constexpr int16_t kGeneratedAudioMaxAmplitude = 32000; +constexpr int kDefaultSamplingFrequencyInHz = 48000; + +// Sets mandatory entities in injectable components like |pcf_dependencies| +// and |pc_dependencies| if they are omitted. Also setup required +// dependencies, that won't be specially provided by factory and will be just +// transferred to peer connection creation code. +void SetMandatoryEntities(InjectableComponents* components) { + RTC_DCHECK(components->pcf_dependencies); + RTC_DCHECK(components->pc_dependencies); + + // Setup required peer connection factory dependencies. + if (components->pcf_dependencies->task_queue_factory == nullptr) { + components->pcf_dependencies->task_queue_factory = + CreateDefaultTaskQueueFactory(); + } + if (components->pcf_dependencies->call_factory == nullptr) { + components->pcf_dependencies->call_factory = webrtc::CreateCallFactory(); + } + if (components->pcf_dependencies->event_log_factory == nullptr) { + components->pcf_dependencies->event_log_factory = + std::make_unique( + components->pcf_dependencies->task_queue_factory.get()); + } +} + +std::map> +CalculateRequiredSpatialIndexPerStream( + const std::vector& video_configs) { + std::map> out; + for (auto& video_config : video_configs) { + // Stream label should be set by fixture implementation here. + RTC_DCHECK(video_config.stream_label); + absl::optional spatial_index; + if (video_config.simulcast_config) { + spatial_index = video_config.simulcast_config->target_spatial_index; + } + bool res = out.insert({*video_config.stream_label, spatial_index}).second; + RTC_DCHECK(res) << "Duplicate video_config.stream_label=" + << *video_config.stream_label; + } + return out; +} + +std::unique_ptr CreateAudioRenderer( + const absl::optional& config) { + if (!config) { + // Return default renderer because we always require some renderer. + return TestAudioDeviceModule::CreateDiscardRenderer( + kDefaultSamplingFrequencyInHz); + } + if (config->output_file_name) { + return TestAudioDeviceModule::CreateBoundedWavFileWriter( + config->output_file_name.value(), config->sampling_frequency_in_hz); + } + return TestAudioDeviceModule::CreateDiscardRenderer( + config->sampling_frequency_in_hz); +} + +std::unique_ptr CreateAudioCapturer( + const absl::optional& audio_config) { + if (!audio_config) { + // If we have no audio config we still need to provide some audio device. + // In such case use generated capturer. Despite of we provided audio here, + // in test media setup audio stream won't be added into peer connection. + return TestAudioDeviceModule::CreatePulsedNoiseCapturer( + kGeneratedAudioMaxAmplitude, kDefaultSamplingFrequencyInHz); + } + + switch (audio_config->mode) { + case AudioConfig::Mode::kGenerated: + return TestAudioDeviceModule::CreatePulsedNoiseCapturer( + kGeneratedAudioMaxAmplitude, audio_config->sampling_frequency_in_hz); + case AudioConfig::Mode::kFile: + RTC_DCHECK(audio_config->input_file_name); + return TestAudioDeviceModule::CreateWavFileReader( + audio_config->input_file_name.value(), /*repeat=*/true); + } +} + +rtc::scoped_refptr CreateAudioDeviceModule( + absl::optional audio_config, + absl::optional remote_audio_config, + absl::optional echo_emulation_config, + TaskQueueFactory* task_queue_factory) { + std::unique_ptr renderer = + CreateAudioRenderer(remote_audio_config); + std::unique_ptr capturer = + CreateAudioCapturer(audio_config); + RTC_DCHECK(renderer); + RTC_DCHECK(capturer); + + // Setup echo emulation if required. + if (echo_emulation_config) { + capturer = std::make_unique(std::move(capturer), + *echo_emulation_config); + renderer = std::make_unique( + std::move(renderer), + static_cast(capturer.get())); + } + + // Setup input stream dumping if required. + if (audio_config && audio_config->input_dump_file_name) { + capturer = std::make_unique( + std::move(capturer), audio_config->input_dump_file_name.value()); + } + + return TestAudioDeviceModule::Create(task_queue_factory, std::move(capturer), + std::move(renderer), /*speed=*/1.f); +} + +std::unique_ptr CreateMediaEngine( + PeerConnectionFactoryComponents* pcf_dependencies, + rtc::scoped_refptr audio_device_module, + rtc::scoped_refptr audio_processing) { + cricket::MediaEngineDependencies media_deps; + media_deps.task_queue_factory = pcf_dependencies->task_queue_factory.get(); + media_deps.adm = audio_device_module; + media_deps.audio_processing = audio_processing; + media_deps.video_encoder_factory = + std::move(pcf_dependencies->video_encoder_factory); + media_deps.video_decoder_factory = + std::move(pcf_dependencies->video_decoder_factory); + webrtc::SetMediaEngineDefaults(&media_deps); + return cricket::CreateMediaEngine(std::move(media_deps)); +} + +void WrapVideoEncoderFactory( + double bitrate_multiplier, + std::map> stream_required_spatial_index, + PeerConnectionFactoryComponents* pcf_dependencies, + VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) { + std::unique_ptr video_encoder_factory; + if (pcf_dependencies->video_encoder_factory != nullptr) { + video_encoder_factory = std::move(pcf_dependencies->video_encoder_factory); + } else { + video_encoder_factory = CreateBuiltinVideoEncoderFactory(); + } + pcf_dependencies->video_encoder_factory = + video_analyzer_helper->WrapVideoEncoderFactory( + std::move(video_encoder_factory), bitrate_multiplier, + std::move(stream_required_spatial_index)); +} + +void WrapVideoDecoderFactory( + PeerConnectionFactoryComponents* pcf_dependencies, + VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) { + std::unique_ptr video_decoder_factory; + if (pcf_dependencies->video_decoder_factory != nullptr) { + video_decoder_factory = std::move(pcf_dependencies->video_decoder_factory); + } else { + video_decoder_factory = CreateBuiltinVideoDecoderFactory(); + } + pcf_dependencies->video_decoder_factory = + video_analyzer_helper->WrapVideoDecoderFactory( + std::move(video_decoder_factory)); +} + +// Creates PeerConnectionFactoryDependencies objects, providing entities +// from InjectableComponents::PeerConnectionFactoryComponents. +PeerConnectionFactoryDependencies CreatePCFDependencies( + std::unique_ptr pcf_dependencies, + std::unique_ptr media_engine, + rtc::Thread* signaling_thread, + rtc::Thread* network_thread) { + PeerConnectionFactoryDependencies pcf_deps; + pcf_deps.network_thread = network_thread; + pcf_deps.signaling_thread = signaling_thread; + pcf_deps.media_engine = std::move(media_engine); + + pcf_deps.call_factory = std::move(pcf_dependencies->call_factory); + pcf_deps.event_log_factory = std::move(pcf_dependencies->event_log_factory); + pcf_deps.task_queue_factory = std::move(pcf_dependencies->task_queue_factory); + + if (pcf_dependencies->fec_controller_factory != nullptr) { + pcf_deps.fec_controller_factory = + std::move(pcf_dependencies->fec_controller_factory); + } + if (pcf_dependencies->network_controller_factory != nullptr) { + pcf_deps.network_controller_factory = + std::move(pcf_dependencies->network_controller_factory); + } + if (pcf_dependencies->media_transport_factory != nullptr) { + pcf_deps.media_transport_factory = + std::move(pcf_dependencies->media_transport_factory); + } + if (pcf_dependencies->neteq_factory != nullptr) { + pcf_deps.neteq_factory = std::move(pcf_dependencies->neteq_factory); + } + + return pcf_deps; +} + +// Creates PeerConnectionDependencies objects, providing entities +// from InjectableComponents::PeerConnectionComponents. +PeerConnectionDependencies CreatePCDependencies( + MockPeerConnectionObserver* observer, + std::unique_ptr pc_dependencies) { + PeerConnectionDependencies pc_deps(observer); + + auto port_allocator = std::make_unique( + pc_dependencies->network_manager); + + // This test does not support TCP + int flags = cricket::PORTALLOCATOR_DISABLE_TCP; + port_allocator->set_flags(port_allocator->flags() | flags); + + pc_deps.allocator = std::move(port_allocator); + + if (pc_dependencies->async_resolver_factory != nullptr) { + pc_deps.async_resolver_factory = + std::move(pc_dependencies->async_resolver_factory); + } + if (pc_dependencies->cert_generator != nullptr) { + pc_deps.cert_generator = std::move(pc_dependencies->cert_generator); + } + if (pc_dependencies->tls_cert_verifier != nullptr) { + pc_deps.tls_cert_verifier = std::move(pc_dependencies->tls_cert_verifier); + } + if (pc_dependencies->ice_transport_factory != nullptr) { + pc_deps.ice_transport_factory = + std::move(pc_dependencies->ice_transport_factory); + } + return pc_deps; +} + +} // namespace + +absl::optional RemotePeerAudioConfig::Create( + absl::optional config) { + if (!config) { + return absl::nullopt; + } + return RemotePeerAudioConfig(config.value()); +} + +std::unique_ptr TestPeerFactory::CreateTestPeer( + std::unique_ptr components, + std::unique_ptr params, + std::vector> + video_generators, + std::unique_ptr observer, + VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, + rtc::Thread* signaling_thread, + absl::optional remote_audio_config, + double bitrate_multiplier, + absl::optional echo_emulation_config, + rtc::TaskQueue* task_queue) { + RTC_DCHECK(components); + RTC_DCHECK(params); + RTC_DCHECK_EQ(params->video_configs.size(), video_generators.size()); + SetMandatoryEntities(components.get()); + params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan; + + // Create peer connection factory. + rtc::scoped_refptr audio_processing = + webrtc::AudioProcessingBuilder().Create(); + if (params->aec_dump_path) { + audio_processing->AttachAecDump( + AecDumpFactory::Create(*params->aec_dump_path, -1, task_queue)); + } + rtc::scoped_refptr audio_device_module = + CreateAudioDeviceModule( + params->audio_config, remote_audio_config, echo_emulation_config, + components->pcf_dependencies->task_queue_factory.get()); + WrapVideoEncoderFactory( + bitrate_multiplier, + CalculateRequiredSpatialIndexPerStream(params->video_configs), + components->pcf_dependencies.get(), video_analyzer_helper); + WrapVideoDecoderFactory(components->pcf_dependencies.get(), + video_analyzer_helper); + std::unique_ptr media_engine = + CreateMediaEngine(components->pcf_dependencies.get(), audio_device_module, + audio_processing); + PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies( + std::move(components->pcf_dependencies), std::move(media_engine), + signaling_thread, components->network_thread); + rtc::scoped_refptr peer_connection_factory = + CreateModularPeerConnectionFactory(std::move(pcf_deps)); + + // Create peer connection. + PeerConnectionDependencies pc_deps = CreatePCDependencies( + observer.get(), std::move(components->pc_dependencies)); + rtc::scoped_refptr peer_connection = + peer_connection_factory->CreatePeerConnection(params->rtc_configuration, + std::move(pc_deps)); + peer_connection->SetBitrate(params->bitrate_params); + + return absl::WrapUnique(new TestPeer( + peer_connection_factory, peer_connection, std::move(observer), + std::move(params), std::move(video_generators), audio_processing)); +} + +} // namespace webrtc_pc_e2e +} // namespace webrtc diff --git a/test/pc/e2e/test_peer_factory.h b/test/pc/e2e/test_peer_factory.h new file mode 100644 index 0000000000..155449eb2a --- /dev/null +++ b/test/pc/e2e/test_peer_factory.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 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 TEST_PC_E2E_TEST_PEER_FACTORY_H_ +#define TEST_PC_E2E_TEST_PEER_FACTORY_H_ + +#include +#include +#include +#include + +#include "api/rtc_event_log/rtc_event_log_factory.h" +#include "api/test/peerconnection_quality_test_fixture.h" +#include "modules/audio_device/include/test_audio_device.h" +#include "rtc_base/task_queue.h" +#include "test/pc/e2e/analyzer/video/video_quality_analyzer_injection_helper.h" +#include "test/pc/e2e/peer_connection_quality_test_params.h" +#include "test/pc/e2e/test_peer.h" + +namespace webrtc { +namespace webrtc_pc_e2e { + +struct RemotePeerAudioConfig { + explicit RemotePeerAudioConfig( + PeerConnectionE2EQualityTestFixture::AudioConfig config) + : sampling_frequency_in_hz(config.sampling_frequency_in_hz), + output_file_name(config.output_dump_file_name) {} + + static absl::optional Create( + absl::optional config); + + int sampling_frequency_in_hz; + absl::optional output_file_name; +}; + +class TestPeerFactory { + public: + // Setups all components, that should be provided to WebRTC + // PeerConnectionFactory and PeerConnection creation methods, + // also will setup dependencies, that are required for media analyzers + // injection. + // + // |signaling_thread| will be provided by test fixture implementation. + // |params| - describes current peer parameters, like current peer video + // streams and audio streams + static std::unique_ptr CreateTestPeer( + std::unique_ptr components, + std::unique_ptr params, + std::vector> + video_generators, + std::unique_ptr observer, + VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, + rtc::Thread* signaling_thread, + absl::optional remote_audio_config, + double bitrate_multiplier, + absl::optional + echo_emulation_config, + rtc::TaskQueue* task_queue); +}; + +} // namespace webrtc_pc_e2e +} // namespace webrtc + +#endif // TEST_PC_E2E_TEST_PEER_FACTORY_H_