xref: /aosp_15_r20/external/webrtc/test/scenario/scenario.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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>
13 #include <memory>
14 
15 #include "absl/flags/flag.h"
16 #include "absl/flags/parse.h"
17 #include "absl/strings/string_view.h"
18 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
19 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
20 #include "rtc_base/socket_address.h"
21 #include "test/logging/file_log_writer.h"
22 #include "test/network/network_emulation.h"
23 #include "test/testsupport/file_utils.h"
24 
25 ABSL_FLAG(bool, scenario_logs, false, "Save logs from scenario framework.");
26 ABSL_FLAG(std::string,
27           scenario_logs_root,
28           "",
29           "Output root path, based on project root if unset.");
30 
31 namespace webrtc {
32 namespace test {
33 namespace {
34 
GetScenarioLogManager(absl::string_view file_name)35 std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
36     absl::string_view file_name) {
37   if (absl::GetFlag(FLAGS_scenario_logs) && !file_name.empty()) {
38     std::string output_root = absl::GetFlag(FLAGS_scenario_logs_root);
39     if (output_root.empty())
40       output_root = OutputPath() + "output_data/";
41 
42     auto base_filename = output_root + std::string(file_name) + ".";
43     RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename;
44     return std::make_unique<FileLogWriterFactory>(base_filename);
45   }
46   return nullptr;
47 }
48 }  // namespace
49 
Scenario()50 Scenario::Scenario()
51     : Scenario(std::unique_ptr<LogWriterFactoryInterface>(),
52                /*real_time=*/false) {}
53 
Scenario(const testing::TestInfo * test_info)54 Scenario::Scenario(const testing::TestInfo* test_info)
55     : Scenario(std::string(test_info->test_suite_name()) + "/" +
56                test_info->name()) {}
57 
Scenario(absl::string_view file_name)58 Scenario::Scenario(absl::string_view file_name)
59     : Scenario(file_name, /*real_time=*/false) {}
60 
Scenario(absl::string_view file_name,bool real_time)61 Scenario::Scenario(absl::string_view file_name, bool real_time)
62     : Scenario(GetScenarioLogManager(file_name), real_time) {}
63 
Scenario(std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,bool real_time)64 Scenario::Scenario(
65     std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
66     bool real_time)
67     : log_writer_factory_(std::move(log_writer_factory)),
68       network_manager_(real_time ? TimeMode::kRealTime : TimeMode::kSimulated,
69                        EmulatedNetworkStatsGatheringMode::kDefault),
70       clock_(network_manager_.time_controller()->GetClock()),
71       audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
72       audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),
73       task_queue_(network_manager_.time_controller()
74                       ->GetTaskQueueFactory()
75                       ->CreateTaskQueue("Scenario",
76                                         TaskQueueFactory::Priority::NORMAL)) {}
77 
~Scenario()78 Scenario::~Scenario() {
79   if (start_time_.IsFinite())
80     Stop();
81   for (auto& call_client : clients_) {
82     call_client->transport_->Disconnect();
83     call_client->UnBind();
84   }
85 }
86 
TimePrinter()87 ColumnPrinter Scenario::TimePrinter() {
88   return ColumnPrinter::Lambda(
89       "time",
90       [this](rtc::SimpleStringBuilder& sb) {
91         sb.AppendFormat("%.3lf", Now().seconds<double>());
92       },
93       32);
94 }
95 
CreatePrinter(absl::string_view name,TimeDelta interval,std::vector<ColumnPrinter> printers)96 StatesPrinter* Scenario::CreatePrinter(absl::string_view name,
97                                        TimeDelta interval,
98                                        std::vector<ColumnPrinter> printers) {
99   std::vector<ColumnPrinter> all_printers{TimePrinter()};
100   for (auto& printer : printers)
101     all_printers.push_back(printer);
102   StatesPrinter* printer = new StatesPrinter(GetLogWriter(name), all_printers);
103   printers_.emplace_back(printer);
104   printer->PrintHeaders();
105   if (interval.IsFinite())
106     Every(interval, [printer] { printer->PrintRow(); });
107   return printer;
108 }
109 
CreateClient(absl::string_view name,CallClientConfig config)110 CallClient* Scenario::CreateClient(absl::string_view name,
111                                    CallClientConfig config) {
112   CallClient* client = new CallClient(network_manager_.time_controller(),
113                                       GetLogWriterFactory(name), config);
114   if (config.transport.state_log_interval.IsFinite()) {
115     Every(config.transport.state_log_interval, [this, client]() {
116       client->network_controller_factory_.LogCongestionControllerStats(Now());
117     });
118   }
119   clients_.emplace_back(client);
120   return client;
121 }
122 
CreateClient(absl::string_view name,std::function<void (CallClientConfig *)> config_modifier)123 CallClient* Scenario::CreateClient(
124     absl::string_view name,
125     std::function<void(CallClientConfig*)> config_modifier) {
126   CallClientConfig config;
127   config_modifier(&config);
128   return CreateClient(name, config);
129 }
130 
CreateRoutes(CallClient * first,std::vector<EmulatedNetworkNode * > send_link,CallClient * second,std::vector<EmulatedNetworkNode * > return_link)131 CallClientPair* Scenario::CreateRoutes(
132     CallClient* first,
133     std::vector<EmulatedNetworkNode*> send_link,
134     CallClient* second,
135     std::vector<EmulatedNetworkNode*> return_link) {
136   return CreateRoutes(first, send_link,
137                       DataSize::Bytes(PacketOverhead::kDefault), second,
138                       return_link, DataSize::Bytes(PacketOverhead::kDefault));
139 }
140 
CreateRoutes(CallClient * first,std::vector<EmulatedNetworkNode * > send_link,DataSize first_overhead,CallClient * second,std::vector<EmulatedNetworkNode * > return_link,DataSize second_overhead)141 CallClientPair* Scenario::CreateRoutes(
142     CallClient* first,
143     std::vector<EmulatedNetworkNode*> send_link,
144     DataSize first_overhead,
145     CallClient* second,
146     std::vector<EmulatedNetworkNode*> return_link,
147     DataSize second_overhead) {
148   CallClientPair* client_pair = new CallClientPair(first, second);
149   ChangeRoute(client_pair->forward(), send_link, first_overhead);
150   ChangeRoute(client_pair->reverse(), return_link, second_overhead);
151   client_pairs_.emplace_back(client_pair);
152   return client_pair;
153 }
154 
ChangeRoute(std::pair<CallClient *,CallClient * > clients,std::vector<EmulatedNetworkNode * > over_nodes)155 void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
156                            std::vector<EmulatedNetworkNode*> over_nodes) {
157   ChangeRoute(clients, over_nodes, DataSize::Bytes(PacketOverhead::kDefault));
158 }
159 
ChangeRoute(std::pair<CallClient *,CallClient * > clients,std::vector<EmulatedNetworkNode * > over_nodes,DataSize overhead)160 void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
161                            std::vector<EmulatedNetworkNode*> over_nodes,
162                            DataSize overhead) {
163   EmulatedRoute* route = network_manager_.CreateRoute(over_nodes);
164   uint16_t port = clients.second->Bind(route->to);
165   auto addr = rtc::SocketAddress(route->to->GetPeerLocalAddress(), port);
166   clients.first->transport_->Connect(route->from, addr, overhead);
167 }
168 
CreateSimulationNode(std::function<void (NetworkSimulationConfig *)> config_modifier)169 EmulatedNetworkNode* Scenario::CreateSimulationNode(
170     std::function<void(NetworkSimulationConfig*)> config_modifier) {
171   NetworkSimulationConfig config;
172   config_modifier(&config);
173   return CreateSimulationNode(config);
174 }
175 
CreateSimulationNode(NetworkSimulationConfig config)176 EmulatedNetworkNode* Scenario::CreateSimulationNode(
177     NetworkSimulationConfig config) {
178   return network_manager_.CreateEmulatedNode(
179       SimulationNode::CreateBehavior(config));
180 }
181 
CreateMutableSimulationNode(std::function<void (NetworkSimulationConfig *)> config_modifier)182 SimulationNode* Scenario::CreateMutableSimulationNode(
183     std::function<void(NetworkSimulationConfig*)> config_modifier) {
184   NetworkSimulationConfig config;
185   config_modifier(&config);
186   return CreateMutableSimulationNode(config);
187 }
188 
CreateMutableSimulationNode(NetworkSimulationConfig config)189 SimulationNode* Scenario::CreateMutableSimulationNode(
190     NetworkSimulationConfig config) {
191   std::unique_ptr<SimulatedNetwork> behavior =
192       SimulationNode::CreateBehavior(config);
193   SimulatedNetwork* behavior_ptr = behavior.get();
194   auto* emulated_node =
195       network_manager_.CreateEmulatedNode(std::move(behavior));
196   simulation_nodes_.emplace_back(
197       new SimulationNode(config, behavior_ptr, emulated_node));
198   return simulation_nodes_.back().get();
199 }
200 
TriggerPacketBurst(std::vector<EmulatedNetworkNode * > over_nodes,size_t num_packets,size_t packet_size)201 void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
202                                   size_t num_packets,
203                                   size_t packet_size) {
204   network_manager_.CreateCrossTrafficRoute(over_nodes)
205       ->TriggerPacketBurst(num_packets, packet_size);
206 }
207 
NetworkDelayedAction(std::vector<EmulatedNetworkNode * > over_nodes,size_t packet_size,std::function<void ()> action)208 void Scenario::NetworkDelayedAction(
209     std::vector<EmulatedNetworkNode*> over_nodes,
210     size_t packet_size,
211     std::function<void()> action) {
212   network_manager_.CreateCrossTrafficRoute(over_nodes)
213       ->NetworkDelayedAction(packet_size, action);
214 }
215 
CreateVideoStream(std::pair<CallClient *,CallClient * > clients,std::function<void (VideoStreamConfig *)> config_modifier)216 VideoStreamPair* Scenario::CreateVideoStream(
217     std::pair<CallClient*, CallClient*> clients,
218     std::function<void(VideoStreamConfig*)> config_modifier) {
219   VideoStreamConfig config;
220   config_modifier(&config);
221   return CreateVideoStream(clients, config);
222 }
223 
CreateVideoStream(std::pair<CallClient *,CallClient * > clients,VideoStreamConfig config)224 VideoStreamPair* Scenario::CreateVideoStream(
225     std::pair<CallClient*, CallClient*> clients,
226     VideoStreamConfig config) {
227   video_streams_.emplace_back(
228       new VideoStreamPair(clients.first, clients.second, config));
229   return video_streams_.back().get();
230 }
231 
CreateAudioStream(std::pair<CallClient *,CallClient * > clients,std::function<void (AudioStreamConfig *)> config_modifier)232 AudioStreamPair* Scenario::CreateAudioStream(
233     std::pair<CallClient*, CallClient*> clients,
234     std::function<void(AudioStreamConfig*)> config_modifier) {
235   AudioStreamConfig config;
236   config_modifier(&config);
237   return CreateAudioStream(clients, config);
238 }
239 
CreateAudioStream(std::pair<CallClient *,CallClient * > clients,AudioStreamConfig config)240 AudioStreamPair* Scenario::CreateAudioStream(
241     std::pair<CallClient*, CallClient*> clients,
242     AudioStreamConfig config) {
243   audio_streams_.emplace_back(
244       new AudioStreamPair(clients.first, audio_encoder_factory_, clients.second,
245                           audio_decoder_factory_, config));
246   return audio_streams_.back().get();
247 }
248 
Every(TimeDelta interval,absl::AnyInvocable<void (TimeDelta)> function)249 void Scenario::Every(TimeDelta interval,
250                      absl::AnyInvocable<void(TimeDelta)> function) {
251   RepeatingTaskHandle::DelayedStart(
252       task_queue_.get(), interval,
253       [interval, function = std::move(function)]() mutable {
254         function(interval);
255         return interval;
256       });
257 }
258 
Every(TimeDelta interval,absl::AnyInvocable<void ()> function)259 void Scenario::Every(TimeDelta interval, absl::AnyInvocable<void()> function) {
260   RepeatingTaskHandle::DelayedStart(
261       task_queue_.get(), interval,
262       [interval, function = std::move(function)]() mutable {
263         function();
264         return interval;
265       });
266 }
267 
Post(absl::AnyInvocable<void ()&&> function)268 void Scenario::Post(absl::AnyInvocable<void() &&> function) {
269   task_queue_->PostTask(std::move(function));
270 }
271 
At(TimeDelta offset,absl::AnyInvocable<void ()&&> function)272 void Scenario::At(TimeDelta offset, absl::AnyInvocable<void() &&> function) {
273   RTC_DCHECK_GT(offset, TimeSinceStart());
274   task_queue_->PostDelayedTask(std::move(function), TimeUntilTarget(offset));
275 }
276 
RunFor(TimeDelta duration)277 void Scenario::RunFor(TimeDelta duration) {
278   if (start_time_.IsInfinite())
279     Start();
280   network_manager_.time_controller()->AdvanceTime(duration);
281 }
282 
RunUntil(TimeDelta target_time_since_start)283 void Scenario::RunUntil(TimeDelta target_time_since_start) {
284   RunFor(TimeUntilTarget(target_time_since_start));
285 }
286 
RunUntil(TimeDelta target_time_since_start,TimeDelta check_interval,std::function<bool ()> exit_function)287 void Scenario::RunUntil(TimeDelta target_time_since_start,
288                         TimeDelta check_interval,
289                         std::function<bool()> exit_function) {
290   if (start_time_.IsInfinite())
291     Start();
292   while (check_interval >= TimeUntilTarget(target_time_since_start)) {
293     network_manager_.time_controller()->AdvanceTime(check_interval);
294     if (exit_function())
295       return;
296   }
297   network_manager_.time_controller()->AdvanceTime(
298       TimeUntilTarget(target_time_since_start));
299 }
300 
Start()301 void Scenario::Start() {
302   start_time_ = clock_->CurrentTime();
303   for (auto& stream_pair : video_streams_)
304     stream_pair->receive()->Start();
305   for (auto& stream_pair : audio_streams_)
306     stream_pair->receive()->Start();
307   for (auto& stream_pair : video_streams_) {
308     if (stream_pair->config_.autostart) {
309       stream_pair->send()->Start();
310     }
311   }
312   for (auto& stream_pair : audio_streams_) {
313     if (stream_pair->config_.autostart) {
314       stream_pair->send()->Start();
315     }
316   }
317 }
318 
Stop()319 void Scenario::Stop() {
320   RTC_DCHECK(start_time_.IsFinite());
321   for (auto& stream_pair : video_streams_) {
322     stream_pair->send()->Stop();
323   }
324   for (auto& stream_pair : audio_streams_)
325     stream_pair->send()->Stop();
326   for (auto& stream_pair : video_streams_)
327     stream_pair->receive()->Stop();
328   for (auto& stream_pair : audio_streams_)
329     stream_pair->receive()->Stop();
330   start_time_ = Timestamp::PlusInfinity();
331 }
332 
Now()333 Timestamp Scenario::Now() {
334   return clock_->CurrentTime();
335 }
336 
TimeSinceStart()337 TimeDelta Scenario::TimeSinceStart() {
338   if (start_time_.IsInfinite())
339     return TimeDelta::Zero();
340   return Now() - start_time_;
341 }
342 
TimeUntilTarget(TimeDelta target_time_offset)343 TimeDelta Scenario::TimeUntilTarget(TimeDelta target_time_offset) {
344   return target_time_offset - TimeSinceStart();
345 }
346 
347 }  // namespace test
348 }  // namespace webrtc
349