• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "test/pc/e2e/test_peer_factory.h"
11 
12 #include <utility>
13 
14 #include "absl/memory/memory.h"
15 #include "absl/strings/string_view.h"
16 #include "api/task_queue/default_task_queue_factory.h"
17 #include "api/test/create_time_controller.h"
18 #include "api/test/time_controller.h"
19 #include "api/video_codecs/builtin_video_decoder_factory.h"
20 #include "api/video_codecs/builtin_video_encoder_factory.h"
21 #include "media/engine/webrtc_media_engine.h"
22 #include "media/engine/webrtc_media_engine_defaults.h"
23 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
24 #include "p2p/client/basic_port_allocator.h"
25 #include "test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h"
26 #include "test/pc/e2e/echo/echo_emulation.h"
27 #include "test/pc/e2e/peer_configurer.h"
28 #include "test/testsupport/copy_to_file_audio_capturer.h"
29 
30 namespace webrtc {
31 namespace webrtc_pc_e2e {
32 namespace {
33 
34 using AudioConfig =
35     ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::AudioConfig;
36 using VideoConfig =
37     ::webrtc::webrtc_pc_e2e::PeerConnectionE2EQualityTestFixture::VideoConfig;
38 using EchoEmulationConfig = ::webrtc::webrtc_pc_e2e::
39     PeerConnectionE2EQualityTestFixture::EchoEmulationConfig;
40 
41 constexpr int16_t kGeneratedAudioMaxAmplitude = 32000;
42 constexpr int kDefaultSamplingFrequencyInHz = 48000;
43 
44 // Sets mandatory entities in injectable components like |pcf_dependencies|
45 // and |pc_dependencies| if they are omitted. Also setup required
46 // dependencies, that won't be specially provided by factory and will be just
47 // transferred to peer connection creation code.
SetMandatoryEntities(InjectableComponents * components,TimeController & time_controller)48 void SetMandatoryEntities(InjectableComponents* components,
49                           TimeController& time_controller) {
50   RTC_DCHECK(components->pcf_dependencies);
51   RTC_DCHECK(components->pc_dependencies);
52 
53   // Setup required peer connection factory dependencies.
54   if (components->pcf_dependencies->task_queue_factory == nullptr) {
55     components->pcf_dependencies->task_queue_factory =
56         time_controller.CreateTaskQueueFactory();
57   }
58   if (components->pcf_dependencies->call_factory == nullptr) {
59     components->pcf_dependencies->call_factory =
60         CreateTimeControllerBasedCallFactory(&time_controller);
61   }
62   if (components->pcf_dependencies->event_log_factory == nullptr) {
63     components->pcf_dependencies->event_log_factory =
64         std::make_unique<RtcEventLogFactory>(
65             components->pcf_dependencies->task_queue_factory.get());
66   }
67 }
68 
69 // Returns mapping from stream label to optional spatial index.
70 // If we have stream label "Foo" and mapping contains
71 // 1. |absl::nullopt| means "Foo" isn't simulcast/SVC stream
72 // 2. |kAnalyzeAnySpatialStream| means all simulcast/SVC streams are required
73 // 3. Concrete value means that particular simulcast/SVC stream have to be
74 //    analyzed.
75 std::map<std::string, absl::optional<int>>
CalculateRequiredSpatialIndexPerStream(const std::vector<VideoConfig> & video_configs)76 CalculateRequiredSpatialIndexPerStream(
77     const std::vector<VideoConfig>& video_configs) {
78   std::map<std::string, absl::optional<int>> out;
79   for (auto& video_config : video_configs) {
80     // Stream label should be set by fixture implementation here.
81     RTC_DCHECK(video_config.stream_label);
82     absl::optional<int> spatial_index;
83     if (video_config.simulcast_config) {
84       spatial_index = video_config.simulcast_config->target_spatial_index;
85       if (!spatial_index) {
86         spatial_index = kAnalyzeAnySpatialStream;
87       }
88     }
89     bool res = out.insert({*video_config.stream_label, spatial_index}).second;
90     RTC_DCHECK(res) << "Duplicate video_config.stream_label="
91                     << *video_config.stream_label;
92   }
93   return out;
94 }
95 
CreateAudioRenderer(const absl::optional<RemotePeerAudioConfig> & config)96 std::unique_ptr<TestAudioDeviceModule::Renderer> CreateAudioRenderer(
97     const absl::optional<RemotePeerAudioConfig>& config) {
98   if (!config) {
99     // Return default renderer because we always require some renderer.
100     return TestAudioDeviceModule::CreateDiscardRenderer(
101         kDefaultSamplingFrequencyInHz);
102   }
103   if (config->output_file_name) {
104     return TestAudioDeviceModule::CreateBoundedWavFileWriter(
105         config->output_file_name.value(), config->sampling_frequency_in_hz);
106   }
107   return TestAudioDeviceModule::CreateDiscardRenderer(
108       config->sampling_frequency_in_hz);
109 }
110 
CreateAudioCapturer(const absl::optional<AudioConfig> & audio_config)111 std::unique_ptr<TestAudioDeviceModule::Capturer> CreateAudioCapturer(
112     const absl::optional<AudioConfig>& audio_config) {
113   if (!audio_config) {
114     // If we have no audio config we still need to provide some audio device.
115     // In such case use generated capturer. Despite of we provided audio here,
116     // in test media setup audio stream won't be added into peer connection.
117     return TestAudioDeviceModule::CreatePulsedNoiseCapturer(
118         kGeneratedAudioMaxAmplitude, kDefaultSamplingFrequencyInHz);
119   }
120 
121   switch (audio_config->mode) {
122     case AudioConfig::Mode::kGenerated:
123       return TestAudioDeviceModule::CreatePulsedNoiseCapturer(
124           kGeneratedAudioMaxAmplitude, audio_config->sampling_frequency_in_hz);
125     case AudioConfig::Mode::kFile:
126       RTC_DCHECK(audio_config->input_file_name);
127       return TestAudioDeviceModule::CreateWavFileReader(
128           audio_config->input_file_name.value(), /*repeat=*/true);
129   }
130 }
131 
CreateAudioDeviceModule(absl::optional<AudioConfig> audio_config,absl::optional<RemotePeerAudioConfig> remote_audio_config,absl::optional<EchoEmulationConfig> echo_emulation_config,TaskQueueFactory * task_queue_factory)132 rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModule(
133     absl::optional<AudioConfig> audio_config,
134     absl::optional<RemotePeerAudioConfig> remote_audio_config,
135     absl::optional<EchoEmulationConfig> echo_emulation_config,
136     TaskQueueFactory* task_queue_factory) {
137   std::unique_ptr<TestAudioDeviceModule::Renderer> renderer =
138       CreateAudioRenderer(remote_audio_config);
139   std::unique_ptr<TestAudioDeviceModule::Capturer> capturer =
140       CreateAudioCapturer(audio_config);
141   RTC_DCHECK(renderer);
142   RTC_DCHECK(capturer);
143 
144   // Setup echo emulation if required.
145   if (echo_emulation_config) {
146     capturer = std::make_unique<EchoEmulatingCapturer>(std::move(capturer),
147                                                        *echo_emulation_config);
148     renderer = std::make_unique<EchoEmulatingRenderer>(
149         std::move(renderer),
150         static_cast<EchoEmulatingCapturer*>(capturer.get()));
151   }
152 
153   // Setup input stream dumping if required.
154   if (audio_config && audio_config->input_dump_file_name) {
155     capturer = std::make_unique<test::CopyToFileAudioCapturer>(
156         std::move(capturer), audio_config->input_dump_file_name.value());
157   }
158 
159   return TestAudioDeviceModule::Create(task_queue_factory, std::move(capturer),
160                                        std::move(renderer), /*speed=*/1.f);
161 }
162 
CreateMediaEngine(PeerConnectionFactoryComponents * pcf_dependencies,rtc::scoped_refptr<AudioDeviceModule> audio_device_module,rtc::scoped_refptr<AudioProcessing> audio_processing)163 std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine(
164     PeerConnectionFactoryComponents* pcf_dependencies,
165     rtc::scoped_refptr<AudioDeviceModule> audio_device_module,
166     rtc::scoped_refptr<AudioProcessing> audio_processing) {
167   cricket::MediaEngineDependencies media_deps;
168   media_deps.task_queue_factory = pcf_dependencies->task_queue_factory.get();
169   media_deps.adm = audio_device_module;
170   media_deps.audio_processing = audio_processing;
171   media_deps.video_encoder_factory =
172       std::move(pcf_dependencies->video_encoder_factory);
173   media_deps.video_decoder_factory =
174       std::move(pcf_dependencies->video_decoder_factory);
175   webrtc::SetMediaEngineDefaults(&media_deps);
176   return cricket::CreateMediaEngine(std::move(media_deps));
177 }
178 
WrapVideoEncoderFactory(absl::string_view peer_name,double bitrate_multiplier,std::map<std::string,absl::optional<int>> stream_required_spatial_index,PeerConnectionFactoryComponents * pcf_dependencies,VideoQualityAnalyzerInjectionHelper * video_analyzer_helper)179 void WrapVideoEncoderFactory(
180     absl::string_view peer_name,
181     double bitrate_multiplier,
182     std::map<std::string, absl::optional<int>> stream_required_spatial_index,
183     PeerConnectionFactoryComponents* pcf_dependencies,
184     VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) {
185   std::unique_ptr<VideoEncoderFactory> video_encoder_factory;
186   if (pcf_dependencies->video_encoder_factory != nullptr) {
187     video_encoder_factory = std::move(pcf_dependencies->video_encoder_factory);
188   } else {
189     video_encoder_factory = CreateBuiltinVideoEncoderFactory();
190   }
191   pcf_dependencies->video_encoder_factory =
192       video_analyzer_helper->WrapVideoEncoderFactory(
193           peer_name, std::move(video_encoder_factory), bitrate_multiplier,
194           std::move(stream_required_spatial_index));
195 }
196 
WrapVideoDecoderFactory(absl::string_view peer_name,PeerConnectionFactoryComponents * pcf_dependencies,VideoQualityAnalyzerInjectionHelper * video_analyzer_helper)197 void WrapVideoDecoderFactory(
198     absl::string_view peer_name,
199     PeerConnectionFactoryComponents* pcf_dependencies,
200     VideoQualityAnalyzerInjectionHelper* video_analyzer_helper) {
201   std::unique_ptr<VideoDecoderFactory> video_decoder_factory;
202   if (pcf_dependencies->video_decoder_factory != nullptr) {
203     video_decoder_factory = std::move(pcf_dependencies->video_decoder_factory);
204   } else {
205     video_decoder_factory = CreateBuiltinVideoDecoderFactory();
206   }
207   pcf_dependencies->video_decoder_factory =
208       video_analyzer_helper->WrapVideoDecoderFactory(
209           peer_name, std::move(video_decoder_factory));
210 }
211 
212 // Creates PeerConnectionFactoryDependencies objects, providing entities
213 // from InjectableComponents::PeerConnectionFactoryComponents.
CreatePCFDependencies(std::unique_ptr<PeerConnectionFactoryComponents> pcf_dependencies,std::unique_ptr<cricket::MediaEngineInterface> media_engine,rtc::Thread * signaling_thread,rtc::Thread * worker_thread,rtc::Thread * network_thread)214 PeerConnectionFactoryDependencies CreatePCFDependencies(
215     std::unique_ptr<PeerConnectionFactoryComponents> pcf_dependencies,
216     std::unique_ptr<cricket::MediaEngineInterface> media_engine,
217     rtc::Thread* signaling_thread,
218     rtc::Thread* worker_thread,
219     rtc::Thread* network_thread) {
220   PeerConnectionFactoryDependencies pcf_deps;
221   pcf_deps.signaling_thread = signaling_thread;
222   pcf_deps.worker_thread = worker_thread;
223   pcf_deps.network_thread = network_thread;
224   pcf_deps.media_engine = std::move(media_engine);
225 
226   pcf_deps.call_factory = std::move(pcf_dependencies->call_factory);
227   pcf_deps.event_log_factory = std::move(pcf_dependencies->event_log_factory);
228   pcf_deps.task_queue_factory = std::move(pcf_dependencies->task_queue_factory);
229 
230   if (pcf_dependencies->fec_controller_factory != nullptr) {
231     pcf_deps.fec_controller_factory =
232         std::move(pcf_dependencies->fec_controller_factory);
233   }
234   if (pcf_dependencies->network_controller_factory != nullptr) {
235     pcf_deps.network_controller_factory =
236         std::move(pcf_dependencies->network_controller_factory);
237   }
238   if (pcf_dependencies->neteq_factory != nullptr) {
239     pcf_deps.neteq_factory = std::move(pcf_dependencies->neteq_factory);
240   }
241 
242   return pcf_deps;
243 }
244 
245 // Creates PeerConnectionDependencies objects, providing entities
246 // from InjectableComponents::PeerConnectionComponents.
CreatePCDependencies(MockPeerConnectionObserver * observer,std::unique_ptr<PeerConnectionComponents> pc_dependencies)247 PeerConnectionDependencies CreatePCDependencies(
248     MockPeerConnectionObserver* observer,
249     std::unique_ptr<PeerConnectionComponents> pc_dependencies) {
250   PeerConnectionDependencies pc_deps(observer);
251 
252   auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
253       pc_dependencies->network_manager);
254 
255   // This test does not support TCP
256   int flags = cricket::PORTALLOCATOR_DISABLE_TCP;
257   port_allocator->set_flags(port_allocator->flags() | flags);
258 
259   pc_deps.allocator = std::move(port_allocator);
260 
261   if (pc_dependencies->async_resolver_factory != nullptr) {
262     pc_deps.async_resolver_factory =
263         std::move(pc_dependencies->async_resolver_factory);
264   }
265   if (pc_dependencies->cert_generator != nullptr) {
266     pc_deps.cert_generator = std::move(pc_dependencies->cert_generator);
267   }
268   if (pc_dependencies->tls_cert_verifier != nullptr) {
269     pc_deps.tls_cert_verifier = std::move(pc_dependencies->tls_cert_verifier);
270   }
271   if (pc_dependencies->ice_transport_factory != nullptr) {
272     pc_deps.ice_transport_factory =
273         std::move(pc_dependencies->ice_transport_factory);
274   }
275   return pc_deps;
276 }
277 
278 }  // namespace
279 
Create(absl::optional<AudioConfig> config)280 absl::optional<RemotePeerAudioConfig> RemotePeerAudioConfig::Create(
281     absl::optional<AudioConfig> config) {
282   if (!config) {
283     return absl::nullopt;
284   }
285   return RemotePeerAudioConfig(config.value());
286 }
287 
CreateTestPeer(std::unique_ptr<PeerConfigurerImpl> configurer,std::unique_ptr<MockPeerConnectionObserver> observer,absl::optional<RemotePeerAudioConfig> remote_audio_config,double bitrate_multiplier,absl::optional<PeerConnectionE2EQualityTestFixture::EchoEmulationConfig> echo_emulation_config)288 std::unique_ptr<TestPeer> TestPeerFactory::CreateTestPeer(
289     std::unique_ptr<PeerConfigurerImpl> configurer,
290     std::unique_ptr<MockPeerConnectionObserver> observer,
291     absl::optional<RemotePeerAudioConfig> remote_audio_config,
292     double bitrate_multiplier,
293     absl::optional<PeerConnectionE2EQualityTestFixture::EchoEmulationConfig>
294         echo_emulation_config) {
295   std::unique_ptr<InjectableComponents> components =
296       configurer->ReleaseComponents();
297   std::unique_ptr<Params> params = configurer->ReleaseParams();
298   std::vector<PeerConfigurerImpl::VideoSource> video_sources =
299       configurer->ReleaseVideoSources();
300   RTC_DCHECK(components);
301   RTC_DCHECK(params);
302   RTC_DCHECK_EQ(params->video_configs.size(), video_sources.size());
303   SetMandatoryEntities(components.get(), time_controller_);
304   params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
305 
306   // Create peer connection factory.
307   rtc::scoped_refptr<AudioProcessing> audio_processing =
308       webrtc::AudioProcessingBuilder().Create();
309   if (params->aec_dump_path && audio_processing) {
310     audio_processing->CreateAndAttachAecDump(*params->aec_dump_path, -1,
311                                              task_queue_);
312   }
313   rtc::scoped_refptr<AudioDeviceModule> audio_device_module =
314       CreateAudioDeviceModule(
315           params->audio_config, remote_audio_config, echo_emulation_config,
316           components->pcf_dependencies->task_queue_factory.get());
317   WrapVideoEncoderFactory(
318       params->name.value(), bitrate_multiplier,
319       CalculateRequiredSpatialIndexPerStream(params->video_configs),
320       components->pcf_dependencies.get(), video_analyzer_helper_);
321   WrapVideoDecoderFactory(params->name.value(),
322                           components->pcf_dependencies.get(),
323                           video_analyzer_helper_);
324   std::unique_ptr<cricket::MediaEngineInterface> media_engine =
325       CreateMediaEngine(components->pcf_dependencies.get(), audio_device_module,
326                         audio_processing);
327 
328   std::unique_ptr<rtc::Thread> worker_thread =
329       time_controller_.CreateThread("worker_thread");
330   PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies(
331       std::move(components->pcf_dependencies), std::move(media_engine),
332       signaling_thread_, worker_thread.get(), components->network_thread);
333   rtc::scoped_refptr<PeerConnectionFactoryInterface> peer_connection_factory =
334       CreateModularPeerConnectionFactory(std::move(pcf_deps));
335 
336   // Create peer connection.
337   PeerConnectionDependencies pc_deps = CreatePCDependencies(
338       observer.get(), std::move(components->pc_dependencies));
339   rtc::scoped_refptr<PeerConnectionInterface> peer_connection =
340       peer_connection_factory->CreatePeerConnection(params->rtc_configuration,
341                                                     std::move(pc_deps));
342   peer_connection->SetBitrate(params->bitrate_settings);
343 
344   return absl::WrapUnique(new TestPeer(
345       peer_connection_factory, peer_connection, std::move(observer),
346       std::move(params), std::move(video_sources), audio_processing,
347       std::move(worker_thread)));
348 }
349 
350 }  // namespace webrtc_pc_e2e
351 }  // namespace webrtc
352