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