| /* |
| * Copyright (c) 2019 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.h" |
| |
| #include <utility> |
| |
| #include "absl/memory/memory.h" |
| #include "absl/types/optional.h" |
| #include "api/audio_codecs/builtin_audio_decoder_factory.h" |
| #include "api/audio_codecs/builtin_audio_encoder_factory.h" |
| #include "api/scoped_refptr.h" |
| #include "api/video_codecs/builtin_video_decoder_factory.h" |
| #include "api/video_codecs/builtin_video_encoder_factory.h" |
| #include "logging/rtc_event_log/rtc_event_log_factory.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/client/basic_port_allocator.h" |
| #include "rtc_base/location.h" |
| #include "test/testsupport/copy_to_file_audio_capturer.h" |
| |
| namespace webrtc { |
| namespace webrtc_pc_e2e { |
| namespace { |
| |
| constexpr int16_t kGeneratedAudioMaxAmplitude = 32000; |
| constexpr int kSamplingFrequencyInHz = 48000; |
| |
| using AudioConfig = PeerConnectionE2EQualityTestFixture::AudioConfig; |
| |
| // 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->call_factory == nullptr) { |
| components->pcf_dependencies->call_factory = webrtc::CreateCallFactory(); |
| } |
| if (components->pcf_dependencies->event_log_factory == nullptr) { |
| components->pcf_dependencies->event_log_factory = |
| webrtc::CreateRtcEventLogFactory(); |
| } |
| } |
| |
| std::unique_ptr<TestAudioDeviceModule::Capturer> CreateAudioCapturer( |
| AudioConfig audio_config) { |
| if (audio_config.mode == AudioConfig::Mode::kGenerated) { |
| return TestAudioDeviceModule::CreatePulsedNoiseCapturer( |
| kGeneratedAudioMaxAmplitude, kSamplingFrequencyInHz); |
| } |
| if (audio_config.mode == AudioConfig::Mode::kFile) { |
| RTC_DCHECK(audio_config.input_file_name); |
| return TestAudioDeviceModule::CreateWavFileReader( |
| audio_config.input_file_name.value()); |
| } |
| RTC_NOTREACHED() << "Unknown audio_config->mode"; |
| return nullptr; |
| } |
| |
| rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModule( |
| absl::optional<AudioConfig> audio_config, |
| absl::optional<std::string> audio_output_file_name) { |
| std::unique_ptr<TestAudioDeviceModule::Capturer> capturer; |
| if (audio_config) { |
| capturer = CreateAudioCapturer(audio_config.value()); |
| } else { |
| // 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. |
| capturer = TestAudioDeviceModule::CreatePulsedNoiseCapturer( |
| kGeneratedAudioMaxAmplitude, kSamplingFrequencyInHz); |
| } |
| RTC_DCHECK(capturer); |
| |
| if (audio_config && audio_config->input_dump_file_name) { |
| capturer = absl::make_unique<test::CopyToFileAudioCapturer>( |
| std::move(capturer), audio_config->input_dump_file_name.value()); |
| } |
| |
| std::unique_ptr<TestAudioDeviceModule::Renderer> renderer; |
| if (audio_output_file_name) { |
| renderer = TestAudioDeviceModule::CreateBoundedWavFileWriter( |
| audio_output_file_name.value(), kSamplingFrequencyInHz); |
| } else { |
| renderer = |
| TestAudioDeviceModule::CreateDiscardRenderer(kSamplingFrequencyInHz); |
| } |
| |
| return TestAudioDeviceModule::CreateTestAudioDeviceModule( |
| std::move(capturer), std::move(renderer), /*speed=*/1.f); |
| } |
| |
| std::unique_ptr<VideoEncoderFactory> CreateVideoEncoderFactory( |
| PeerConnectionFactoryComponents* pcf_dependencies, |
| VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, |
| std::map<std::string, absl::optional<int>> stream_required_spatial_index) { |
| std::unique_ptr<VideoEncoderFactory> 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), |
| std::move(stream_required_spatial_index)); |
| } |
| |
| std::unique_ptr<VideoDecoderFactory> CreateVideoDecoderFactory( |
| PeerConnectionFactoryComponents* pcf_dependencies, |
| VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) { |
| std::unique_ptr<VideoDecoderFactory> 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)); |
| } |
| |
| std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine( |
| PeerConnectionFactoryComponents* pcf_dependencies, |
| absl::optional<AudioConfig> audio_config, |
| std::map<std::string, absl::optional<int>> stream_required_spatial_index, |
| VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, |
| absl::optional<std::string> audio_output_file_name) { |
| rtc::scoped_refptr<AudioDeviceModule> adm = CreateAudioDeviceModule( |
| std::move(audio_config), std::move(audio_output_file_name)); |
| |
| std::unique_ptr<VideoEncoderFactory> video_encoder_factory = |
| CreateVideoEncoderFactory(pcf_dependencies, video_analyzer_helper, |
| std::move(stream_required_spatial_index)); |
| std::unique_ptr<VideoDecoderFactory> video_decoder_factory = |
| CreateVideoDecoderFactory(pcf_dependencies, video_analyzer_helper); |
| |
| return cricket::WebRtcMediaEngineFactory::Create( |
| adm, webrtc::CreateBuiltinAudioEncoderFactory(), |
| webrtc::CreateBuiltinAudioDecoderFactory(), |
| std::move(video_encoder_factory), std::move(video_decoder_factory), |
| /*audio_mixer=*/nullptr, webrtc::AudioProcessingBuilder().Create()); |
| } |
| |
| // 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<PeerConnectionFactoryComponents> pcf_dependencies, |
| absl::optional<AudioConfig> audio_config, |
| std::map<std::string, absl::optional<int>> stream_required_spatial_index, |
| VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, |
| rtc::Thread* network_thread, |
| rtc::Thread* signaling_thread, |
| absl::optional<std::string> audio_output_file_name) { |
| PeerConnectionFactoryDependencies pcf_deps; |
| pcf_deps.network_thread = network_thread; |
| pcf_deps.signaling_thread = signaling_thread; |
| pcf_deps.media_engine = CreateMediaEngine( |
| pcf_dependencies.get(), std::move(audio_config), |
| std::move(stream_required_spatial_index), video_analyzer_helper, |
| std::move(audio_output_file_name)); |
| |
| pcf_deps.call_factory = std::move(pcf_dependencies->call_factory); |
| pcf_deps.event_log_factory = std::move(pcf_dependencies->event_log_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); |
| } |
| |
| return pcf_deps; |
| } |
| |
| // Creates PeerConnectionDependencies objects, providing entities |
| // from InjectableComponents::PeerConnectionComponents. |
| PeerConnectionDependencies CreatePCDependencies( |
| std::unique_ptr<PeerConnectionComponents> pc_dependencies, |
| PeerConnectionObserver* observer) { |
| PeerConnectionDependencies pc_deps(observer); |
| |
| auto port_allocator = absl::make_unique<cricket::BasicPortAllocator>( |
| 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); |
| } |
| return pc_deps; |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<TestPeer> TestPeer::CreateTestPeer( |
| std::unique_ptr<InjectableComponents> components, |
| std::unique_ptr<Params> params, |
| std::unique_ptr<MockPeerConnectionObserver> observer, |
| VideoQualityAnalyzerInjectionHelper* video_analyzer_helper, |
| rtc::Thread* signaling_thread, |
| absl::optional<std::string> audio_output_file_name) { |
| RTC_DCHECK(components); |
| RTC_DCHECK(params); |
| SetMandatoryEntities(components.get()); |
| params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan; |
| |
| std::map<std::string, absl::optional<int>> stream_required_spatial_index; |
| 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.target_spatial_index}) |
| .second; |
| RTC_DCHECK(res) << "Duplicate video_config.stream_label=" |
| << *video_config.stream_label; |
| } |
| |
| // Create peer connection factory. |
| PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies( |
| std::move(components->pcf_dependencies), params->audio_config, |
| std::move(stream_required_spatial_index), video_analyzer_helper, |
| components->network_thread, signaling_thread, |
| std::move(audio_output_file_name)); |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> pcf = |
| CreateModularPeerConnectionFactory(std::move(pcf_deps)); |
| |
| // Create peer connection. |
| PeerConnectionDependencies pc_deps = CreatePCDependencies( |
| std::move(components->pc_dependencies), observer.get()); |
| rtc::scoped_refptr<PeerConnectionInterface> pc = |
| pcf->CreatePeerConnection(params->rtc_configuration, std::move(pc_deps)); |
| |
| return absl::WrapUnique( |
| new TestPeer(pcf, pc, std::move(observer), std::move(params))); |
| } |
| |
| bool TestPeer::AddIceCandidates( |
| rtc::ArrayView<const IceCandidateInterface* const> candidates) { |
| bool success = true; |
| for (const auto* candidate : candidates) { |
| if (!pc()->AddIceCandidate(candidate)) { |
| std::string candidate_str; |
| bool res = candidate->ToString(&candidate_str); |
| RTC_CHECK(res); |
| RTC_LOG(LS_ERROR) << "Failed to add ICE candidate, candidate_str=" |
| << candidate_str; |
| success = false; |
| } |
| } |
| return success; |
| } |
| |
| TestPeer::TestPeer( |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory, |
| rtc::scoped_refptr<PeerConnectionInterface> pc, |
| std::unique_ptr<MockPeerConnectionObserver> observer, |
| std::unique_ptr<Params> params) |
| : PeerConnectionWrapper::PeerConnectionWrapper(std::move(pc_factory), |
| std::move(pc), |
| std::move(observer)), |
| params_(std::move(params)) {} |
| |
| } // namespace webrtc_pc_e2e |
| } // namespace webrtc |