• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "api/audio_codecs/builtin_audio_decoder_factory.h"
18 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
19 #include "rtc_base/socket_address.h"
20 #include "test/logging/file_log_writer.h"
21 #include "test/network/network_emulation.h"
22 #include "test/testsupport/file_utils.h"
23 
24 ABSL_FLAG(bool, scenario_logs, false, "Save logs from scenario framework.");
25 ABSL_FLAG(std::string,
26           scenario_logs_root,
27           "",
28           "Output root path, based on project root if unset.");
29 
30 namespace webrtc {
31 namespace test {
32 namespace {
33 
GetScenarioLogManager(std::string file_name)34 std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
35     std::string file_name) {
36   if (absl::GetFlag(FLAGS_scenario_logs) && !file_name.empty()) {
37     std::string output_root = absl::GetFlag(FLAGS_scenario_logs_root);
38     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;
43     return std::make_unique<FileLogWriterFactory>(base_filename);
44   }
45   return nullptr;
46 }
47 }  // namespace
48 
Scenario()49 Scenario::Scenario()
50     : Scenario(std::unique_ptr<LogWriterFactoryInterface>(),
51                /*real_time=*/false) {}
52 
Scenario(const testing::TestInfo * test_info)53 Scenario::Scenario(const testing::TestInfo* test_info)
54     : Scenario(std::string(test_info->test_suite_name()) + "/" +
55                test_info->name()) {}
56 
Scenario(std::string file_name)57 Scenario::Scenario(std::string file_name)
58     : Scenario(file_name, /*real_time=*/false) {}
59 
Scenario(std::string file_name,bool real_time)60 Scenario::Scenario(std::string file_name, bool real_time)
61     : Scenario(GetScenarioLogManager(file_name), real_time) {}
62 
Scenario(std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,bool real_time)63 Scenario::Scenario(
64     std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
65     bool real_time)
66     : log_writer_factory_(std::move(log_writer_factory)),
67       network_manager_(real_time ? TimeMode::kRealTime : TimeMode::kSimulated),
68       clock_(network_manager_.time_controller()->GetClock()),
69       audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
70       audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()),
71       task_queue_(network_manager_.time_controller()
72                       ->GetTaskQueueFactory()
73                       ->CreateTaskQueue("Scenario",
74                                         TaskQueueFactory::Priority::NORMAL)) {}
75 
~Scenario()76 Scenario::~Scenario() {
77   if (start_time_.IsFinite())
78     Stop();
79   for (auto& call_client : clients_) {
80     call_client->transport_->Disconnect();
81     call_client->UnBind();
82   }
83 }
84 
TimePrinter()85 ColumnPrinter Scenario::TimePrinter() {
86   return ColumnPrinter::Lambda(
87       "time",
88       [this](rtc::SimpleStringBuilder& sb) {
89         sb.AppendFormat("%.3lf", Now().seconds<double>());
90       },
91       32);
92 }
93 
CreatePrinter(std::string name,TimeDelta interval,std::vector<ColumnPrinter> printers)94 StatesPrinter* 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);
100   StatesPrinter* printer = new StatesPrinter(GetLogWriter(name), all_printers);
101   printers_.emplace_back(printer);
102   printer->PrintHeaders();
103   if (interval.IsFinite())
104     Every(interval, [printer] { printer->PrintRow(); });
105   return printer;
106 }
107 
CreateClient(std::string name,CallClientConfig config)108 CallClient* Scenario::CreateClient(std::string name, CallClientConfig config) {
109   CallClient* client = new CallClient(network_manager_.time_controller(),
110                                       GetLogWriterFactory(name), config);
111   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 
CreateClient(std::string name,std::function<void (CallClientConfig *)> config_modifier)120 CallClient* 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 
CreateRoutes(CallClient * first,std::vector<EmulatedNetworkNode * > send_link,CallClient * second,std::vector<EmulatedNetworkNode * > return_link)128 CallClientPair* Scenario::CreateRoutes(
129     CallClient* first,
130     std::vector<EmulatedNetworkNode*> send_link,
131     CallClient* second,
132     std::vector<EmulatedNetworkNode*> return_link) {
133   return CreateRoutes(first, send_link,
134                       DataSize::Bytes(PacketOverhead::kDefault), second,
135                       return_link, DataSize::Bytes(PacketOverhead::kDefault));
136 }
137 
CreateRoutes(CallClient * first,std::vector<EmulatedNetworkNode * > send_link,DataSize first_overhead,CallClient * second,std::vector<EmulatedNetworkNode * > return_link,DataSize second_overhead)138 CallClientPair* 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) {
145   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 
ChangeRoute(std::pair<CallClient *,CallClient * > clients,std::vector<EmulatedNetworkNode * > over_nodes)152 void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
153                            std::vector<EmulatedNetworkNode*> over_nodes) {
154   ChangeRoute(clients, over_nodes, DataSize::Bytes(PacketOverhead::kDefault));
155 }
156 
ChangeRoute(std::pair<CallClient *,CallClient * > clients,std::vector<EmulatedNetworkNode * > over_nodes,DataSize overhead)157 void Scenario::ChangeRoute(std::pair<CallClient*, CallClient*> clients,
158                            std::vector<EmulatedNetworkNode*> over_nodes,
159                            DataSize overhead) {
160   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);
164 }
165 
CreateSimulationNode(std::function<void (NetworkSimulationConfig *)> config_modifier)166 EmulatedNetworkNode* Scenario::CreateSimulationNode(
167     std::function<void(NetworkSimulationConfig*)> config_modifier) {
168   NetworkSimulationConfig config;
169   config_modifier(&config);
170   return CreateSimulationNode(config);
171 }
172 
CreateSimulationNode(NetworkSimulationConfig config)173 EmulatedNetworkNode* Scenario::CreateSimulationNode(
174     NetworkSimulationConfig config) {
175   return network_manager_.CreateEmulatedNode(
176       SimulationNode::CreateBehavior(config));
177 }
178 
CreateMutableSimulationNode(std::function<void (NetworkSimulationConfig *)> config_modifier)179 SimulationNode* Scenario::CreateMutableSimulationNode(
180     std::function<void(NetworkSimulationConfig*)> config_modifier) {
181   NetworkSimulationConfig config;
182   config_modifier(&config);
183   return CreateMutableSimulationNode(config);
184 }
185 
CreateMutableSimulationNode(NetworkSimulationConfig config)186 SimulationNode* Scenario::CreateMutableSimulationNode(
187     NetworkSimulationConfig config) {
188   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();
196 }
197 
TriggerPacketBurst(std::vector<EmulatedNetworkNode * > over_nodes,size_t num_packets,size_t packet_size)198 void Scenario::TriggerPacketBurst(std::vector<EmulatedNetworkNode*> over_nodes,
199                                   size_t num_packets,
200                                   size_t packet_size) {
201   network_manager_.CreateTrafficRoute(over_nodes)
202       ->TriggerPacketBurst(num_packets, packet_size);
203 }
204 
NetworkDelayedAction(std::vector<EmulatedNetworkNode * > over_nodes,size_t packet_size,std::function<void ()> action)205 void Scenario::NetworkDelayedAction(
206     std::vector<EmulatedNetworkNode*> over_nodes,
207     size_t packet_size,
208     std::function<void()> action) {
209   network_manager_.CreateTrafficRoute(over_nodes)
210       ->NetworkDelayedAction(packet_size, action);
211 }
212 
CreateVideoStream(std::pair<CallClient *,CallClient * > clients,std::function<void (VideoStreamConfig *)> config_modifier)213 VideoStreamPair* Scenario::CreateVideoStream(
214     std::pair<CallClient*, CallClient*> clients,
215     std::function<void(VideoStreamConfig*)> config_modifier) {
216   VideoStreamConfig config;
217   config_modifier(&config);
218   return CreateVideoStream(clients, config);
219 }
220 
CreateVideoStream(std::pair<CallClient *,CallClient * > clients,VideoStreamConfig config)221 VideoStreamPair* Scenario::CreateVideoStream(
222     std::pair<CallClient*, CallClient*> clients,
223     VideoStreamConfig config) {
224   video_streams_.emplace_back(
225       new VideoStreamPair(clients.first, clients.second, config));
226   return video_streams_.back().get();
227 }
228 
CreateAudioStream(std::pair<CallClient *,CallClient * > clients,std::function<void (AudioStreamConfig *)> config_modifier)229 AudioStreamPair* Scenario::CreateAudioStream(
230     std::pair<CallClient*, CallClient*> clients,
231     std::function<void(AudioStreamConfig*)> config_modifier) {
232   AudioStreamConfig config;
233   config_modifier(&config);
234   return CreateAudioStream(clients, config);
235 }
236 
CreateAudioStream(std::pair<CallClient *,CallClient * > clients,AudioStreamConfig config)237 AudioStreamPair* Scenario::CreateAudioStream(
238     std::pair<CallClient*, CallClient*> clients,
239     AudioStreamConfig config) {
240   audio_streams_.emplace_back(
241       new AudioStreamPair(clients.first, audio_encoder_factory_, clients.second,
242                           audio_decoder_factory_, config));
243   return audio_streams_.back().get();
244 }
245 
Every(TimeDelta interval,std::function<void (TimeDelta)> function)246 void Scenario::Every(TimeDelta interval,
247                      std::function<void(TimeDelta)> function) {
248   RepeatingTaskHandle::DelayedStart(task_queue_.Get(), interval,
249                                     [interval, function] {
250                                       function(interval);
251                                       return interval;
252                                     });
253 }
254 
Every(TimeDelta interval,std::function<void ()> function)255 void Scenario::Every(TimeDelta interval, std::function<void()> function) {
256   RepeatingTaskHandle::DelayedStart(task_queue_.Get(), interval,
257                                     [interval, function] {
258                                       function();
259                                       return interval;
260                                     });
261 }
262 
Post(std::function<void ()> function)263 void Scenario::Post(std::function<void()> function) {
264   task_queue_.PostTask(function);
265 }
266 
At(TimeDelta offset,std::function<void ()> function)267 void Scenario::At(TimeDelta offset, std::function<void()> function) {
268   RTC_DCHECK_GT(offset, TimeSinceStart());
269   task_queue_.PostDelayedTask(function, TimeUntilTarget(offset).ms());
270 }
271 
RunFor(TimeDelta duration)272 void Scenario::RunFor(TimeDelta duration) {
273   if (start_time_.IsInfinite())
274     Start();
275   network_manager_.time_controller()->AdvanceTime(duration);
276 }
277 
RunUntil(TimeDelta target_time_since_start)278 void Scenario::RunUntil(TimeDelta target_time_since_start) {
279   RunFor(TimeUntilTarget(target_time_since_start));
280 }
281 
RunUntil(TimeDelta target_time_since_start,TimeDelta check_interval,std::function<bool ()> exit_function)282 void Scenario::RunUntil(TimeDelta target_time_since_start,
283                         TimeDelta check_interval,
284                         std::function<bool()> exit_function) {
285   if (start_time_.IsInfinite())
286     Start();
287   while (check_interval >= TimeUntilTarget(target_time_since_start)) {
288     network_manager_.time_controller()->AdvanceTime(check_interval);
289     if (exit_function())
290       return;
291   }
292   network_manager_.time_controller()->AdvanceTime(
293       TimeUntilTarget(target_time_since_start));
294 }
295 
Start()296 void Scenario::Start() {
297   start_time_ = clock_->CurrentTime();
298   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 
Stop()314 void Scenario::Stop() {
315   RTC_DCHECK(start_time_.IsFinite());
316   for (auto& stream_pair : video_streams_) {
317     stream_pair->send()->Stop();
318   }
319   for (auto& stream_pair : audio_streams_)
320     stream_pair->send()->Stop();
321   for (auto& stream_pair : video_streams_)
322     stream_pair->receive()->Stop();
323   for (auto& stream_pair : audio_streams_)
324     stream_pair->receive()->Stop();
325   start_time_ = Timestamp::PlusInfinity();
326 }
327 
Now()328 Timestamp Scenario::Now() {
329   return clock_->CurrentTime();
330 }
331 
TimeSinceStart()332 TimeDelta Scenario::TimeSinceStart() {
333   if (start_time_.IsInfinite())
334     return TimeDelta::Zero();
335   return Now() - start_time_;
336 }
337 
TimeUntilTarget(TimeDelta target_time_offset)338 TimeDelta Scenario::TimeUntilTarget(TimeDelta target_time_offset) {
339   return target_time_offset - TimeSinceStart();
340 }
341 
342 }  // namespace test
343 }  // namespace webrtc
344