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/pclf/media_configuration.h"
19 #include "api/test/pclf/peer_configurer.h"
20 #include "api/test/time_controller.h"
21 #include "api/transport/field_trial_based_config.h"
22 #include "api/video_codecs/builtin_video_decoder_factory.h"
23 #include "api/video_codecs/builtin_video_encoder_factory.h"
24 #include "media/engine/webrtc_media_engine.h"
25 #include "media/engine/webrtc_media_engine_defaults.h"
26 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
27 #include "p2p/client/basic_port_allocator.h"
28 #include "rtc_base/thread.h"
29 #include "test/pc/e2e/analyzer/video/quality_analyzing_video_encoder.h"
30 #include "test/pc/e2e/echo/echo_emulation.h"
31 #include "test/testsupport/copy_to_file_audio_capturer.h"
32
33 namespace webrtc {
34 namespace webrtc_pc_e2e {
35 namespace {
36
37 using EmulatedSFUConfigMap =
38 ::webrtc::webrtc_pc_e2e::QualityAnalyzingVideoEncoder::EmulatedSFUConfigMap;
39
40 constexpr int16_t kGeneratedAudioMaxAmplitude = 32000;
41 constexpr int kDefaultSamplingFrequencyInHz = 48000;
42
43 // Sets mandatory entities in injectable components like `pcf_dependencies`
44 // and `pc_dependencies` if they are omitted. Also setup required
45 // dependencies, that won't be specially provided by factory and will be just
46 // transferred to peer connection creation code.
SetMandatoryEntities(InjectableComponents * components,TimeController & time_controller)47 void SetMandatoryEntities(InjectableComponents* components,
48 TimeController& time_controller) {
49 RTC_DCHECK(components->pcf_dependencies);
50 RTC_DCHECK(components->pc_dependencies);
51
52 // Setup required peer connection factory dependencies.
53 if (components->pcf_dependencies->task_queue_factory == nullptr) {
54 components->pcf_dependencies->task_queue_factory =
55 time_controller.CreateTaskQueueFactory();
56 }
57 if (components->pcf_dependencies->call_factory == nullptr) {
58 components->pcf_dependencies->call_factory =
59 CreateTimeControllerBasedCallFactory(&time_controller);
60 }
61 if (components->pcf_dependencies->event_log_factory == nullptr) {
62 components->pcf_dependencies->event_log_factory =
63 std::make_unique<RtcEventLogFactory>(
64 components->pcf_dependencies->task_queue_factory.get());
65 }
66 if (!components->pcf_dependencies->trials) {
67 components->pcf_dependencies->trials =
68 std::make_unique<FieldTrialBasedConfig>();
69 }
70 }
71
72 // Returns mapping from stream label to optional spatial index.
73 // If we have stream label "Foo" and mapping contains
74 // 1. `absl::nullopt` means all simulcast/SVC streams are required
75 // 2. Concrete value means that particular simulcast/SVC stream have to be
76 // analyzed.
CalculateRequiredSpatialIndexPerStream(const std::vector<VideoConfig> & video_configs)77 EmulatedSFUConfigMap CalculateRequiredSpatialIndexPerStream(
78 const std::vector<VideoConfig>& video_configs) {
79 EmulatedSFUConfigMap result;
80 for (auto& video_config : video_configs) {
81 // Stream label should be set by fixture implementation here.
82 RTC_DCHECK(video_config.stream_label);
83 bool res = result
84 .insert({*video_config.stream_label,
85 video_config.emulated_sfu_config})
86 .second;
87 RTC_DCHECK(res) << "Duplicate video_config.stream_label="
88 << *video_config.stream_label;
89 }
90 return result;
91 }
92
CreateAudioRenderer(const absl::optional<RemotePeerAudioConfig> & config)93 std::unique_ptr<TestAudioDeviceModule::Renderer> CreateAudioRenderer(
94 const absl::optional<RemotePeerAudioConfig>& config) {
95 if (!config) {
96 // Return default renderer because we always require some renderer.
97 return TestAudioDeviceModule::CreateDiscardRenderer(
98 kDefaultSamplingFrequencyInHz);
99 }
100 if (config->output_file_name) {
101 return TestAudioDeviceModule::CreateBoundedWavFileWriter(
102 config->output_file_name.value(), config->sampling_frequency_in_hz);
103 }
104 return TestAudioDeviceModule::CreateDiscardRenderer(
105 config->sampling_frequency_in_hz);
106 }
107
CreateAudioCapturer(const absl::optional<AudioConfig> & audio_config)108 std::unique_ptr<TestAudioDeviceModule::Capturer> CreateAudioCapturer(
109 const absl::optional<AudioConfig>& audio_config) {
110 if (!audio_config) {
111 // If we have no audio config we still need to provide some audio device.
112 // In such case use generated capturer. Despite of we provided audio here,
113 // in test media setup audio stream won't be added into peer connection.
114 return TestAudioDeviceModule::CreatePulsedNoiseCapturer(
115 kGeneratedAudioMaxAmplitude, kDefaultSamplingFrequencyInHz);
116 }
117
118 switch (audio_config->mode) {
119 case AudioConfig::Mode::kGenerated:
120 return TestAudioDeviceModule::CreatePulsedNoiseCapturer(
121 kGeneratedAudioMaxAmplitude, audio_config->sampling_frequency_in_hz);
122 case AudioConfig::Mode::kFile:
123 RTC_DCHECK(audio_config->input_file_name);
124 return TestAudioDeviceModule::CreateWavFileReader(
125 audio_config->input_file_name.value(), /*repeat=*/true);
126 }
127 }
128
CreateAudioDeviceModule(absl::optional<AudioConfig> audio_config,absl::optional<RemotePeerAudioConfig> remote_audio_config,absl::optional<EchoEmulationConfig> echo_emulation_config,TaskQueueFactory * task_queue_factory)129 rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceModule(
130 absl::optional<AudioConfig> audio_config,
131 absl::optional<RemotePeerAudioConfig> remote_audio_config,
132 absl::optional<EchoEmulationConfig> echo_emulation_config,
133 TaskQueueFactory* task_queue_factory) {
134 std::unique_ptr<TestAudioDeviceModule::Renderer> renderer =
135 CreateAudioRenderer(remote_audio_config);
136 std::unique_ptr<TestAudioDeviceModule::Capturer> capturer =
137 CreateAudioCapturer(audio_config);
138 RTC_DCHECK(renderer);
139 RTC_DCHECK(capturer);
140
141 // Setup echo emulation if required.
142 if (echo_emulation_config) {
143 capturer = std::make_unique<EchoEmulatingCapturer>(std::move(capturer),
144 *echo_emulation_config);
145 renderer = std::make_unique<EchoEmulatingRenderer>(
146 std::move(renderer),
147 static_cast<EchoEmulatingCapturer*>(capturer.get()));
148 }
149
150 // Setup input stream dumping if required.
151 if (audio_config && audio_config->input_dump_file_name) {
152 capturer = std::make_unique<test::CopyToFileAudioCapturer>(
153 std::move(capturer), audio_config->input_dump_file_name.value());
154 }
155
156 return TestAudioDeviceModule::Create(task_queue_factory, std::move(capturer),
157 std::move(renderer), /*speed=*/1.f);
158 }
159
CreateMediaEngine(PeerConnectionFactoryComponents * pcf_dependencies,rtc::scoped_refptr<AudioDeviceModule> audio_device_module)160 std::unique_ptr<cricket::MediaEngineInterface> CreateMediaEngine(
161 PeerConnectionFactoryComponents* pcf_dependencies,
162 rtc::scoped_refptr<AudioDeviceModule> audio_device_module) {
163 cricket::MediaEngineDependencies media_deps;
164 media_deps.task_queue_factory = pcf_dependencies->task_queue_factory.get();
165 media_deps.adm = audio_device_module;
166 media_deps.audio_processing = pcf_dependencies->audio_processing;
167 media_deps.audio_mixer = pcf_dependencies->audio_mixer;
168 media_deps.video_encoder_factory =
169 std::move(pcf_dependencies->video_encoder_factory);
170 media_deps.video_decoder_factory =
171 std::move(pcf_dependencies->video_decoder_factory);
172 webrtc::SetMediaEngineDefaults(&media_deps);
173 RTC_DCHECK(pcf_dependencies->trials);
174 media_deps.trials = pcf_dependencies->trials.get();
175
176 return cricket::CreateMediaEngine(std::move(media_deps));
177 }
178
WrapVideoEncoderFactory(absl::string_view peer_name,double bitrate_multiplier,EmulatedSFUConfigMap stream_to_sfu_config,PeerConnectionFactoryComponents * pcf_dependencies,VideoQualityAnalyzerInjectionHelper * video_analyzer_helper)179 void WrapVideoEncoderFactory(
180 absl::string_view peer_name,
181 double bitrate_multiplier,
182 EmulatedSFUConfigMap stream_to_sfu_config,
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_to_sfu_config));
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 if (pcf_dependencies->trials != nullptr) {
242 pcf_deps.trials = std::move(pcf_dependencies->trials);
243 }
244
245 return pcf_deps;
246 }
247
248 // Creates PeerConnectionDependencies objects, providing entities
249 // from InjectableComponents::PeerConnectionComponents.
CreatePCDependencies(MockPeerConnectionObserver * observer,uint32_t port_allocator_extra_flags,std::unique_ptr<PeerConnectionComponents> pc_dependencies)250 PeerConnectionDependencies CreatePCDependencies(
251 MockPeerConnectionObserver* observer,
252 uint32_t port_allocator_extra_flags,
253 std::unique_ptr<PeerConnectionComponents> pc_dependencies) {
254 PeerConnectionDependencies pc_deps(observer);
255
256 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
257 pc_dependencies->network_manager, pc_dependencies->packet_socket_factory);
258
259 // This test does not support TCP
260 int flags = port_allocator_extra_flags | cricket::PORTALLOCATOR_DISABLE_TCP;
261 port_allocator->set_flags(port_allocator->flags() | flags);
262
263 pc_deps.allocator = std::move(port_allocator);
264
265 if (pc_dependencies->async_resolver_factory != nullptr) {
266 pc_deps.async_resolver_factory =
267 std::move(pc_dependencies->async_resolver_factory);
268 }
269 if (pc_dependencies->cert_generator != nullptr) {
270 pc_deps.cert_generator = std::move(pc_dependencies->cert_generator);
271 }
272 if (pc_dependencies->tls_cert_verifier != nullptr) {
273 pc_deps.tls_cert_verifier = std::move(pc_dependencies->tls_cert_verifier);
274 }
275 if (pc_dependencies->ice_transport_factory != nullptr) {
276 pc_deps.ice_transport_factory =
277 std::move(pc_dependencies->ice_transport_factory);
278 }
279 return pc_deps;
280 }
281
282 } // namespace
283
Create(absl::optional<AudioConfig> config)284 absl::optional<RemotePeerAudioConfig> RemotePeerAudioConfig::Create(
285 absl::optional<AudioConfig> config) {
286 if (!config) {
287 return absl::nullopt;
288 }
289 return RemotePeerAudioConfig(config.value());
290 }
291
CreateTestPeer(std::unique_ptr<PeerConfigurer> configurer,std::unique_ptr<MockPeerConnectionObserver> observer,absl::optional<RemotePeerAudioConfig> remote_audio_config,absl::optional<EchoEmulationConfig> echo_emulation_config)292 std::unique_ptr<TestPeer> TestPeerFactory::CreateTestPeer(
293 std::unique_ptr<PeerConfigurer> configurer,
294 std::unique_ptr<MockPeerConnectionObserver> observer,
295 absl::optional<RemotePeerAudioConfig> remote_audio_config,
296 absl::optional<EchoEmulationConfig> echo_emulation_config) {
297 std::unique_ptr<InjectableComponents> components =
298 configurer->ReleaseComponents();
299 std::unique_ptr<Params> params = configurer->ReleaseParams();
300 std::unique_ptr<ConfigurableParams> configurable_params =
301 configurer->ReleaseConfigurableParams();
302 std::vector<PeerConfigurer::VideoSource> video_sources =
303 configurer->ReleaseVideoSources();
304 RTC_DCHECK(components);
305 RTC_DCHECK(params);
306 RTC_DCHECK(configurable_params);
307 RTC_DCHECK_EQ(configurable_params->video_configs.size(),
308 video_sources.size());
309 SetMandatoryEntities(components.get(), time_controller_);
310 params->rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
311
312 // Create peer connection factory.
313 if (components->pcf_dependencies->audio_processing == nullptr) {
314 components->pcf_dependencies->audio_processing =
315 webrtc::AudioProcessingBuilder().Create();
316 }
317 if (params->aec_dump_path) {
318 components->pcf_dependencies->audio_processing->CreateAndAttachAecDump(
319 *params->aec_dump_path, -1, task_queue_);
320 }
321 rtc::scoped_refptr<AudioDeviceModule> audio_device_module =
322 CreateAudioDeviceModule(
323 params->audio_config, remote_audio_config, echo_emulation_config,
324 components->pcf_dependencies->task_queue_factory.get());
325 WrapVideoEncoderFactory(
326 params->name.value(), params->video_encoder_bitrate_multiplier,
327 CalculateRequiredSpatialIndexPerStream(
328 configurable_params->video_configs),
329 components->pcf_dependencies.get(), video_analyzer_helper_);
330 WrapVideoDecoderFactory(params->name.value(),
331 components->pcf_dependencies.get(),
332 video_analyzer_helper_);
333 std::unique_ptr<cricket::MediaEngineInterface> media_engine =
334 CreateMediaEngine(components->pcf_dependencies.get(),
335 audio_device_module);
336
337 std::unique_ptr<rtc::Thread> owned_worker_thread =
338 components->worker_thread != nullptr
339 ? nullptr
340 : time_controller_.CreateThread("worker_thread");
341 if (components->worker_thread == nullptr) {
342 components->worker_thread = owned_worker_thread.get();
343 }
344
345 // Store `webrtc::AudioProcessing` into local variable before move of
346 // `components->pcf_dependencies`
347 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing =
348 components->pcf_dependencies->audio_processing;
349 PeerConnectionFactoryDependencies pcf_deps = CreatePCFDependencies(
350 std::move(components->pcf_dependencies), std::move(media_engine),
351 signaling_thread_, components->worker_thread, components->network_thread);
352 rtc::scoped_refptr<PeerConnectionFactoryInterface> peer_connection_factory =
353 CreateModularPeerConnectionFactory(std::move(pcf_deps));
354
355 // Create peer connection.
356 PeerConnectionDependencies pc_deps =
357 CreatePCDependencies(observer.get(), params->port_allocator_extra_flags,
358 std::move(components->pc_dependencies));
359 rtc::scoped_refptr<PeerConnectionInterface> peer_connection =
360 peer_connection_factory
361 ->CreatePeerConnectionOrError(params->rtc_configuration,
362 std::move(pc_deps))
363 .MoveValue();
364 peer_connection->SetBitrate(params->bitrate_settings);
365
366 return absl::WrapUnique(
367 new TestPeer(peer_connection_factory, peer_connection,
368 std::move(observer), std::move(*params),
369 std::move(*configurable_params), std::move(video_sources),
370 audio_processing, std::move(owned_worker_thread)));
371 }
372
373 } // namespace webrtc_pc_e2e
374 } // namespace webrtc
375