blob: 239aad9dfed4da289770e01bbda5917410998599 [file] [log] [blame]
Sebastian Jansson98b07e92018-09-27 13:47:01 +02001/*
2 * Copyright 2018 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/scenario/scenario.h"
11
12#include <algorithm>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020013#include <memory>
Sebastian Jansson98b07e92018-09-27 13:47:01 +020014
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020015#include "absl/flags/flag.h"
16#include "absl/flags/parse.h"
Sebastian Jansson98b07e92018-09-27 13:47:01 +020017#include "api/audio_codecs/builtin_audio_decoder_factory.h"
18#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080019#include "rtc_base/socket_address.h"
Sebastian Jansson52de8b02019-01-16 17:25:44 +010020#include "test/logging/file_log_writer.h"
Artem Titov386802e2019-07-05 10:48:17 +020021#include "test/network/network_emulation.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "test/testsupport/file_utils.h"
Sebastian Jansson98b07e92018-09-27 13:47:01 +020023
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020024ABSL_FLAG(bool, scenario_logs, false, "Save logs from scenario framework.");
25ABSL_FLAG(std::string,
26 scenario_logs_root,
27 "",
28 "Output root path, based on project root if unset.");
Sebastian Jansson98b07e92018-09-27 13:47:01 +020029
30namespace webrtc {
31namespace test {
32namespace {
Sebastian Jansson105a10a2019-04-01 09:18:14 +020033
Sebastian Jansson52de8b02019-01-16 17:25:44 +010034std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
35 std::string file_name) {
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020036 if (absl::GetFlag(FLAGS_scenario_logs) && !file_name.empty()) {
37 std::string output_root = absl::GetFlag(FLAGS_scenario_logs_root);
Sebastian Jansson52de8b02019-01-16 17:25:44 +010038 if (output_root.empty())
39 output_root = OutputPath() + "output_data/";
40
41 auto base_filename = output_root + file_name + ".";
42 RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename;
Mirko Bonadei317a1f02019-09-17 17:06:18 +020043 return std::make_unique<FileLogWriterFactory>(base_filename);
Sebastian Jansson52de8b02019-01-16 17:25:44 +010044 }
45 return nullptr;
46}
Jonas Olssona4d87372019-07-05 19:08:33 +020047} // namespace
Sebastian Jansson98b07e92018-09-27 13:47:01 +020048
Sebastian Jansson52de8b02019-01-16 17:25:44 +010049Scenario::Scenario()
Sebastian Janssonebd94f62019-04-03 13:38:15 +020050 : Scenario(std::unique_ptr<LogWriterFactoryInterface>(),
51 /*real_time=*/false) {}
Sebastian Jansson98b07e92018-09-27 13:47:01 +020052
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +010053Scenario::Scenario(const testing::TestInfo* test_info)
54 : Scenario(std::string(test_info->test_suite_name()) + "/" +
55 test_info->name()) {}
56
Sebastian Janssonebd94f62019-04-03 13:38:15 +020057Scenario::Scenario(std::string file_name)
58 : Scenario(file_name, /*real_time=*/false) {}
Sebastian Jansson98b07e92018-09-27 13:47:01 +020059
60Scenario::Scenario(std::string file_name, bool real_time)
Sebastian Jansson52de8b02019-01-16 17:25:44 +010061 : Scenario(GetScenarioLogManager(file_name), real_time) {}
62
63Scenario::Scenario(
64 std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
65 bool real_time)
66 : log_writer_factory_(std::move(log_writer_factory)),
Sebastian Jansson6ce033a2020-01-22 10:12:56 +010067 network_manager_(real_time ? TimeMode::kRealTime : TimeMode::kSimulated),
68 clock_(network_manager_.time_controller()->GetClock()),
Sebastian Jansson98b07e92018-09-27 13:47:01 +020069 audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
Sebastian Jansson105a10a2019-04-01 09:18:14 +020070 audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),
Sebastian Jansson6ce033a2020-01-22 10:12:56 +010071 task_queue_(network_manager_.time_controller()
72 ->GetTaskQueueFactory()
73 ->CreateTaskQueue("Scenario",
74 TaskQueueFactory::Priority::NORMAL)) {}
Sebastian Jansson98b07e92018-09-27 13:47:01 +020075
76Scenario::~Scenario() {
Sebastian Jansson49a78432018-11-20 16:15:29 +010077 if (start_time_.IsFinite())
78 Stop();
Sebastian Jansson77bd3852020-01-17 13:05:54 +010079 for (auto& call_client : clients_) {
Sebastian Jansson4124dab2019-04-01 14:33:53 +020080 call_client->transport_->Disconnect();
Sebastian Jansson77bd3852020-01-17 13:05:54 +010081 call_client->UnBind();
82 }
Sebastian Jansson98b07e92018-09-27 13:47:01 +020083}
84
85ColumnPrinter Scenario::TimePrinter() {
Jonas Olssona4d87372019-07-05 19:08:33 +020086 return ColumnPrinter::Lambda(
87 "time",
88 [this](rtc::SimpleStringBuilder& sb) {
89 sb.AppendFormat("%.3lf", Now().seconds<double>());
90 },
91 32);
Sebastian Jansson98b07e92018-09-27 13:47:01 +020092}
93
94StatesPrinter* Scenario::CreatePrinter(std::string name,
95 TimeDelta interval,
96 std::vector<ColumnPrinter> printers) {
97 std::vector<ColumnPrinter> all_printers{TimePrinter()};
98 for (auto& printer : printers)
99 all_printers.push_back(printer);
Sebastian Jansson52de8b02019-01-16 17:25:44 +0100100 StatesPrinter* printer = new StatesPrinter(GetLogWriter(name), all_printers);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200101 printers_.emplace_back(printer);
102 printer->PrintHeaders();
103 if (interval.IsFinite())
104 Every(interval, [printer] { printer->PrintRow(); });
105 return printer;
106}
107
108CallClient* Scenario::CreateClient(std::string name, CallClientConfig config) {
Sebastian Jansson6ce033a2020-01-22 10:12:56 +0100109 CallClient* client = new CallClient(network_manager_.time_controller(),
110 GetLogWriterFactory(name), config);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200111 if (config.transport.state_log_interval.IsFinite()) {
112 Every(config.transport.state_log_interval, [this, client]() {
113 client->network_controller_factory_.LogCongestionControllerStats(Now());
114 });
115 }
116 clients_.emplace_back(client);
117 return client;
118}
119
120CallClient* Scenario::CreateClient(
121 std::string name,
122 std::function<void(CallClientConfig*)> config_modifier) {
123 CallClientConfig config;
124 config_modifier(&config);
125 return CreateClient(name, config);
126}
127
Artem Titov37d18482019-01-08 15:41:45 +0100128CallClientPair* Scenario::CreateRoutes(
129 CallClient* first,
130 std::vector<EmulatedNetworkNode*> send_link,
131 CallClient* second,
132 std::vector<EmulatedNetworkNode*> return_link) {
Sebastian Jansson800e1212018-10-22 11:49:03 +0200133 return CreateRoutes(first, send_link,
Danil Chapovalovcad3e0e2020-02-17 18:46:07 +0100134 DataSize::Bytes(PacketOverhead::kDefault), second,
135 return_link, DataSize::Bytes(PacketOverhead::kDefault));
Sebastian Jansson800e1212018-10-22 11:49:03 +0200136}
137
Artem Titov37d18482019-01-08 15:41:45 +0100138CallClientPair* Scenario::CreateRoutes(
139 CallClient* first,
140 std::vector<EmulatedNetworkNode*> send_link,
141 DataSize first_overhead,
142 CallClient* second,
143 std::vector<EmulatedNetworkNode*> return_link,
144 DataSize second_overhead) {
Sebastian Jansson800e1212018-10-22 11:49:03 +0200145 CallClientPair* client_pair = new CallClientPair(first, second);
146 ChangeRoute(client_pair->forward(), send_link, first_overhead);
147 ChangeRoute(client_pair->reverse(), return_link, second_overhead);
148 client_pairs_.emplace_back(client_pair);
149 return client_pair;
150}
151
152void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
Artem Titov37d18482019-01-08 15:41:45 +0100153 std::vector<EmulatedNetworkNode*> over_nodes) {
Danil Chapovalovcad3e0e2020-02-17 18:46:07 +0100154 ChangeRoute(clients, over_nodes, DataSize::Bytes(PacketOverhead::kDefault));
Sebastian Jansson800e1212018-10-22 11:49:03 +0200155}
156
157void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
Artem Titov37d18482019-01-08 15:41:45 +0100158 std::vector<EmulatedNetworkNode*> over_nodes,
Sebastian Jansson800e1212018-10-22 11:49:03 +0200159 DataSize overhead) {
Sebastian Jansson77bd3852020-01-17 13:05:54 +0100160 EmulatedRoute* route = network_manager_.CreateRoute(over_nodes);
161 uint16_t port = clients.second->Bind(route->to);
162 auto addr = rtc::SocketAddress(route->to->GetPeerLocalAddress(), port);
163 clients.first->transport_->Connect(route->from, addr, overhead);
Sebastian Jansson800e1212018-10-22 11:49:03 +0200164}
165
Sebastian Janssonef86d142019-04-15 14:42:42 +0200166EmulatedNetworkNode* Scenario::CreateSimulationNode(
167 std::function<void(NetworkSimulationConfig*)> config_modifier) {
168 NetworkSimulationConfig config;
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200169 config_modifier(&config);
170 return CreateSimulationNode(config);
171}
172
Sebastian Janssonef86d142019-04-15 14:42:42 +0200173EmulatedNetworkNode* Scenario::CreateSimulationNode(
174 NetworkSimulationConfig config) {
Sebastian Janssona4c22b92019-04-15 21:10:00 +0200175 return network_manager_.CreateEmulatedNode(
176 SimulationNode::CreateBehavior(config));
Sebastian Janssonef86d142019-04-15 14:42:42 +0200177}
178
179SimulationNode* Scenario::CreateMutableSimulationNode(
180 std::function<void(NetworkSimulationConfig*)> config_modifier) {
181 NetworkSimulationConfig config;
182 config_modifier(&config);
183 return CreateMutableSimulationNode(config);
184}
185
186SimulationNode* Scenario::CreateMutableSimulationNode(
187 NetworkSimulationConfig config) {
Sebastian Janssona4c22b92019-04-15 21:10:00 +0200188 std::unique_ptr<SimulatedNetwork> behavior =
189 SimulationNode::CreateBehavior(config);
190 SimulatedNetwork* behavior_ptr = behavior.get();
191 auto* emulated_node =
192 network_manager_.CreateEmulatedNode(std::move(behavior));
193 simulation_nodes_.emplace_back(
194 new SimulationNode(config, behavior_ptr, emulated_node));
195 return simulation_nodes_.back().get();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200196}
197
Artem Titov37d18482019-01-08 15:41:45 +0100198void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200199 size_t num_packets,
200 size_t packet_size) {
Andrey Logvinf9ee0e02021-01-14 09:50:32 +0000201 network_manager_.CreateCrossTrafficRoute(over_nodes)
Sebastian Janssona4c22b92019-04-15 21:10:00 +0200202 ->TriggerPacketBurst(num_packets, packet_size);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200203}
204
Artem Titov37d18482019-01-08 15:41:45 +0100205void Scenario::NetworkDelayedAction(
206 std::vector<EmulatedNetworkNode*> over_nodes,
207 size_t packet_size,
208 std::function<void()> action) {
Andrey Logvinf9ee0e02021-01-14 09:50:32 +0000209 network_manager_.CreateCrossTrafficRoute(over_nodes)
Sebastian Janssona4c22b92019-04-15 21:10:00 +0200210 ->NetworkDelayedAction(packet_size, action);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200211}
212
213VideoStreamPair* Scenario::CreateVideoStream(
Sebastian Jansson800e1212018-10-22 11:49:03 +0200214 std::pair<CallClient*, CallClient*> clients,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200215 std::function<void(VideoStreamConfig*)> config_modifier) {
216 VideoStreamConfig config;
217 config_modifier(&config);
Sebastian Jansson800e1212018-10-22 11:49:03 +0200218 return CreateVideoStream(clients, config);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200219}
220
221VideoStreamPair* Scenario::CreateVideoStream(
Sebastian Jansson800e1212018-10-22 11:49:03 +0200222 std::pair<CallClient*, CallClient*> clients,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200223 VideoStreamConfig config) {
Sebastian Janssoncf2df2f2019-04-02 11:51:28 +0200224 video_streams_.emplace_back(
225 new VideoStreamPair(clients.first, clients.second, config));
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200226 return video_streams_.back().get();
227}
228
229AudioStreamPair* Scenario::CreateAudioStream(
Sebastian Jansson800e1212018-10-22 11:49:03 +0200230 std::pair<CallClient*, CallClient*> clients,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200231 std::function<void(AudioStreamConfig*)> config_modifier) {
232 AudioStreamConfig config;
233 config_modifier(&config);
Sebastian Jansson800e1212018-10-22 11:49:03 +0200234 return CreateAudioStream(clients, config);
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200235}
236
237AudioStreamPair* Scenario::CreateAudioStream(
Sebastian Jansson800e1212018-10-22 11:49:03 +0200238 std::pair<CallClient*, CallClient*> clients,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200239 AudioStreamConfig config) {
Sebastian Jansson800e1212018-10-22 11:49:03 +0200240 audio_streams_.emplace_back(
241 new AudioStreamPair(clients.first, audio_encoder_factory_, clients.second,
242 audio_decoder_factory_, config));
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200243 return audio_streams_.back().get();
244}
245
Sebastian Jansson123f3452019-03-13 11:22:52 +0100246void Scenario::Every(TimeDelta interval,
247 std::function<void(TimeDelta)> function) {
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200248 RepeatingTaskHandle::DelayedStart(task_queue_.Get(), interval,
249 [interval, function] {
250 function(interval);
251 return interval;
252 });
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200253}
254
Sebastian Jansson123f3452019-03-13 11:22:52 +0100255void Scenario::Every(TimeDelta interval, std::function<void()> function) {
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200256 RepeatingTaskHandle::DelayedStart(task_queue_.Get(), interval,
257 [interval, function] {
258 function();
259 return interval;
260 });
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200261}
262
Sebastian Jansson3d4d94a2020-01-14 14:25:41 +0100263void Scenario::Post(std::function<void()> function) {
264 task_queue_.PostTask(function);
265}
266
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200267void Scenario::At(TimeDelta offset, std::function<void()> function) {
Sebastian Jansson5a000162019-04-12 11:21:32 +0200268 RTC_DCHECK_GT(offset, TimeSinceStart());
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200269 task_queue_.PostDelayedTask(function, TimeUntilTarget(offset).ms());
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200270}
271
272void Scenario::RunFor(TimeDelta duration) {
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200273 if (start_time_.IsInfinite())
274 Start();
Sebastian Jansson6ce033a2020-01-22 10:12:56 +0100275 network_manager_.time_controller()->AdvanceTime(duration);
Sebastian Jansson49a78432018-11-20 16:15:29 +0100276}
277
Sebastian Jansson123f3452019-03-13 11:22:52 +0100278void Scenario::RunUntil(TimeDelta target_time_since_start) {
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200279 RunFor(TimeUntilTarget(target_time_since_start));
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200280}
281
Sebastian Jansson123f3452019-03-13 11:22:52 +0100282void Scenario::RunUntil(TimeDelta target_time_since_start,
283 TimeDelta check_interval,
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200284 std::function<bool()> exit_function) {
Sebastian Jansson49a78432018-11-20 16:15:29 +0100285 if (start_time_.IsInfinite())
286 Start();
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200287 while (check_interval >= TimeUntilTarget(target_time_since_start)) {
Sebastian Jansson6ce033a2020-01-22 10:12:56 +0100288 network_manager_.time_controller()->AdvanceTime(check_interval);
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200289 if (exit_function())
290 return;
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200291 }
Sebastian Jansson6ce033a2020-01-22 10:12:56 +0100292 network_manager_.time_controller()->AdvanceTime(
293 TimeUntilTarget(target_time_since_start));
Sebastian Jansson49a78432018-11-20 16:15:29 +0100294}
295
296void Scenario::Start() {
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200297 start_time_ = clock_->CurrentTime();
Sebastian Jansson49a78432018-11-20 16:15:29 +0100298 for (auto& stream_pair : video_streams_)
299 stream_pair->receive()->Start();
300 for (auto& stream_pair : audio_streams_)
301 stream_pair->receive()->Start();
302 for (auto& stream_pair : video_streams_) {
303 if (stream_pair->config_.autostart) {
304 stream_pair->send()->Start();
305 }
306 }
307 for (auto& stream_pair : audio_streams_) {
308 if (stream_pair->config_.autostart) {
309 stream_pair->send()->Start();
310 }
311 }
312}
313
314void Scenario::Stop() {
315 RTC_DCHECK(start_time_.IsFinite());
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200316 for (auto& stream_pair : video_streams_) {
Sebastian Janssonbdfadd62019-02-08 13:34:57 +0100317 stream_pair->send()->Stop();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200318 }
319 for (auto& stream_pair : audio_streams_)
Sebastian Janssonbdfadd62019-02-08 13:34:57 +0100320 stream_pair->send()->Stop();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200321 for (auto& stream_pair : video_streams_)
Sebastian Janssonbdfadd62019-02-08 13:34:57 +0100322 stream_pair->receive()->Stop();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200323 for (auto& stream_pair : audio_streams_)
Sebastian Janssonbdfadd62019-02-08 13:34:57 +0100324 stream_pair->receive()->Stop();
Sebastian Jansson49a78432018-11-20 16:15:29 +0100325 start_time_ = Timestamp::PlusInfinity();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200326}
327
328Timestamp Scenario::Now() {
Sebastian Janssonb64ad0e2019-06-19 09:39:34 +0200329 return clock_->CurrentTime();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200330}
331
Sebastian Jansson123f3452019-03-13 11:22:52 +0100332TimeDelta Scenario::TimeSinceStart() {
Sebastian Jansson49a78432018-11-20 16:15:29 +0100333 if (start_time_.IsInfinite())
334 return TimeDelta::Zero();
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200335 return Now() - start_time_;
336}
337
Sebastian Jansson105a10a2019-04-01 09:18:14 +0200338TimeDelta Scenario::TimeUntilTarget(TimeDelta target_time_offset) {
339 return target_time_offset - TimeSinceStart();
340}
341
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200342} // namespace test
343} // namespace webrtc