blob: 28cabc070fda07fb7663a130e4f87795c187f549 [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 "rtc_base/random.h"
11
12#include "rtc_base/experiments/field_trial_parser.h"
13#include "rtc_base/experiments/field_trial_units.h"
14#include "test/field_trial.h"
15#include "test/gtest.h"
16#include "test/scenario/scenario.h"
17
18namespace webrtc {
19namespace test {
20namespace {
21constexpr int64_t kRunTimeMs = 60000;
22
23using ::testing::Values;
24using ::testing::Combine;
25using ::testing::tuple;
26using ::testing::make_tuple;
27
28using Codec = VideoStreamConfig::Encoder::Codec;
29using CodecImpl = VideoStreamConfig::Encoder::Implementation;
30
31struct CallTestConfig {
32 struct Scenario {
33 FieldTrialParameter<int> random_seed;
34 FieldTrialFlag return_traffic;
35 FieldTrialParameter<DataRate> capacity;
36 FieldTrialParameter<TimeDelta> propagation_delay;
37 FieldTrialParameter<DataRate> cross_traffic;
38 FieldTrialParameter<TimeDelta> delay_noise;
39 FieldTrialParameter<double> loss_rate;
40 Scenario()
41 : random_seed("rs", 1),
42 return_traffic("ret"),
43 capacity("bw", DataRate::kbps(300)),
44 propagation_delay("dl", TimeDelta::ms(100)),
45 cross_traffic("ct", DataRate::Zero()),
46 delay_noise("dn", TimeDelta::Zero()),
47 loss_rate("pl", 0) {}
48 void Parse(std::string config_str) {
49 ParseFieldTrial(
50 {&random_seed, &return_traffic, &capacity, &propagation_delay,
51 &cross_traffic, &delay_noise, &loss_rate},
52 config_str);
53 }
54 } scenario;
55 struct Tuning {
56 FieldTrialFlag use_bbr;
57 FieldTrialFlag bbr_no_target_rate;
58 FieldTrialOptional<DataSize> bbr_initial_window;
59 FieldTrialParameter<double> bbr_encoder_gain;
60 Tuning()
61 : use_bbr("bbr"),
62 bbr_no_target_rate("notr"),
63 bbr_initial_window("iw", DataSize::bytes(8000)),
64 bbr_encoder_gain("eg", 0.8) {}
65 void Parse(std::string config_str) {
66 ParseFieldTrial(
67 {
68 &use_bbr, &bbr_no_target_rate, &bbr_initial_window,
69 &bbr_encoder_gain,
70 },
71 config_str);
72 }
73 } tuning;
74
75 void Parse(std::string scenario_string, std::string tuning_string) {
76 scenario.Parse(scenario_string);
77 tuning.Parse(tuning_string);
78 scenario_str = scenario_string;
79 tuning_str = tuning_string;
80 }
81 std::string scenario_str;
82 std::string tuning_str;
83
84 std::string BbrTrial() const {
85 char trial_buf[1024];
86 rtc::SimpleStringBuilder trial(trial_buf);
87 trial << "WebRTC-BweBbrConfig/";
88 trial << "encoder_rate_gain_in_probe_rtt:0.5";
89 trial.AppendFormat(",encoder_rate_gain:%.1lf",
90 tuning.bbr_encoder_gain.Get());
91 if (tuning.bbr_no_target_rate)
92 trial << ",pacing_rate_as_target:1";
93 if (tuning.bbr_initial_window)
94 trial << ",initial_cwin:" << tuning.bbr_initial_window->bytes();
95 trial << "/";
96 return trial.str();
97 }
98 std::string FieldTrials() const {
99 std::string trials = "WebRTC-TaskQueueCongestionControl/Enabled/";
100 if (tuning.use_bbr) {
101 trials +=
102 "WebRTC-BweCongestionController/Enabled,BBR/"
103 "WebRTC-PacerPushbackExperiment/Enabled/"
104 "WebRTC-Pacer-DrainQueue/Disabled/"
105 "WebRTC-Pacer-PadInSilence/Enabled/"
106 "WebRTC-Pacer-BlockAudio/Disabled/"
107 "WebRTC-Audio-SendSideBwe/Enabled/"
108 "WebRTC-SendSideBwe-WithOverhead/Enabled/";
109 trials += BbrTrial();
110 }
111 return trials;
112 }
113
114 std::string Name() const {
115 char raw_name[1024];
116 rtc::SimpleStringBuilder name(raw_name);
117 for (char c : scenario_str + "__tun__" + tuning_str) {
118 if (c == ':') {
119 continue;
120 } else if (c == ',') {
121 name << "_";
122 } else if (c == '%') {
123 name << "p";
124 } else {
125 name << c;
126 }
127 }
128 return name.str();
129 }
130};
131} // namespace
132class BbrScenarioTest
133 : public ::testing::Test,
134 public testing::WithParamInterface<tuple<std::string, std::string>> {
135 public:
136 BbrScenarioTest() {
137 conf_.Parse(::testing::get<0>(GetParam()), ::testing::get<1>(GetParam()));
138 field_trial_.reset(new test::ScopedFieldTrials(conf_.FieldTrials()));
139 }
140 CallTestConfig conf_;
141
142 private:
143 std::unique_ptr<test::ScopedFieldTrials> field_trial_;
144};
145
146TEST_P(BbrScenarioTest, ReceivesVideo) {
147 Scenario s("bbr_test_gen/bbr__" + conf_.Name());
148
149 CallClient* alice = s.CreateClient("send", [&](CallClientConfig* c) {
150 if (conf_.tuning.use_bbr)
151 c->transport.cc = TransportControllerConfig::CongestionController::kBbr;
152 c->transport.state_log_interval = TimeDelta::ms(100);
153 c->transport.rates.min_rate = DataRate::kbps(30);
154 c->transport.rates.max_rate = DataRate::kbps(1800);
155 });
156 CallClient* bob = s.CreateClient("return", [&](CallClientConfig* c) {
157 if (conf_.tuning.use_bbr && conf_.scenario.return_traffic)
158 c->transport.cc = TransportControllerConfig::CongestionController::kBbr;
159 c->transport.state_log_interval = TimeDelta::ms(100);
160 c->transport.rates.min_rate = DataRate::kbps(30);
161 c->transport.rates.max_rate = DataRate::kbps(1800);
162 });
163 NetworkNodeConfig net_conf;
164 net_conf.simulation.bandwidth = conf_.scenario.capacity;
165 net_conf.simulation.delay = conf_.scenario.propagation_delay;
166 net_conf.simulation.loss_rate = conf_.scenario.loss_rate;
167 net_conf.simulation.delay_std_dev = conf_.scenario.delay_noise;
168 SimulationNode* send_net = s.CreateSimulationNode(net_conf);
169 SimulationNode* ret_net = s.CreateSimulationNode(net_conf);
Sebastian Jansson800e1212018-10-22 11:49:03 +0200170 auto route = s.CreateRoutes(alice, {send_net}, bob, {ret_net});
171
172 VideoStreamPair* alice_video =
173 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200174 c->encoder.fake.max_rate = DataRate::kbps(1800);
175 });
Sebastian Jansson800e1212018-10-22 11:49:03 +0200176 s.CreateAudioStream(route->forward(), [&](AudioStreamConfig* c) {
177 if (conf_.tuning.use_bbr) {
178 c->stream.in_bandwidth_estimation = true;
179 c->encoder.fixed_rate = DataRate::kbps(31);
180 }
181 });
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200182
183 VideoStreamPair* bob_video = nullptr;
184 if (conf_.scenario.return_traffic) {
Sebastian Jansson800e1212018-10-22 11:49:03 +0200185 bob_video =
186 s.CreateVideoStream(route->reverse(), [&](VideoStreamConfig* c) {
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200187 c->encoder.fake.max_rate = DataRate::kbps(1800);
188 });
Sebastian Jansson800e1212018-10-22 11:49:03 +0200189 s.CreateAudioStream(route->reverse(), [&](AudioStreamConfig* c) {
190 if (conf_.tuning.use_bbr) {
191 c->stream.in_bandwidth_estimation = true;
192 c->encoder.fixed_rate = DataRate::kbps(31);
193 }
194 });
Sebastian Jansson98b07e92018-09-27 13:47:01 +0200195 }
196 CrossTrafficConfig cross_config;
197 cross_config.peak_rate = conf_.scenario.cross_traffic;
198 cross_config.random_seed = conf_.scenario.random_seed;
199 CrossTrafficSource* cross_traffic =
200 s.CreateCrossTraffic({send_net}, cross_config);
201
202 s.CreatePrinter("send.stats.txt", TimeDelta::ms(100),
203 {alice->StatsPrinter(), alice_video->send()->StatsPrinter(),
204 cross_traffic->StatsPrinter(), send_net->ConfigPrinter()});
205
206 std::vector<ColumnPrinter> return_printers{
207 bob->StatsPrinter(), ColumnPrinter::Fixed("cross_traffic_rate", "0"),
208 ret_net->ConfigPrinter()};
209 if (bob_video)
210 return_printers.push_back(bob_video->send()->StatsPrinter());
211 s.CreatePrinter("return.stats.txt", TimeDelta::ms(100), return_printers);
212
213 s.RunFor(TimeDelta::ms(kRunTimeMs));
214}
215
216INSTANTIATE_TEST_CASE_P(Selected,
217 BbrScenarioTest,
218 Values(make_tuple("rs:1,bw:150,dl:100,ct:100", "bbr")));
219
220INSTANTIATE_TEST_CASE_P(
221 OneWayTuning,
222 BbrScenarioTest,
223 Values(make_tuple("bw:150,dl:100", "bbr,iw:,eg:100%,notr"),
224 make_tuple("bw:150,dl:100", "bbr,iw:8000,eg:100%,notr"),
225 make_tuple("bw:150,dl:100", "bbr,iw:8000,eg:100%"),
226 make_tuple("bw:150,dl:100", "bbr,iw:8000,eg:80%")));
227
228INSTANTIATE_TEST_CASE_P(OneWayTuned,
229 BbrScenarioTest,
230 Values(make_tuple("bw:150,dl:100", "bbr"),
231 make_tuple("bw:150,dl:100", ""),
232 make_tuple("bw:800,dl:100", "bbr"),
233 make_tuple("bw:800,dl:100", "")));
234
235INSTANTIATE_TEST_CASE_P(OneWayDegraded,
236 BbrScenarioTest,
237 Values(make_tuple("bw:150,dl:100,dn:30,pl:5%", "bbr"),
238 make_tuple("bw:150,dl:100,dn:30,pl:5%", ""),
239
240 make_tuple("bw:150,ct:100,dl:100", "bbr"),
241 make_tuple("bw:150,ct:100,dl:100", ""),
242
243 make_tuple("bw:800,dl:100,dn:30,pl:5%", "bbr"),
244 make_tuple("bw:800,dl:100,dn:30,pl:5%", ""),
245
246 make_tuple("bw:800,ct:600,dl:100", "bbr"),
247 make_tuple("bw:800,ct:600,dl:100", "")));
248
249INSTANTIATE_TEST_CASE_P(TwoWay,
250 BbrScenarioTest,
251 Values(make_tuple("ret,bw:150,dl:100", "bbr"),
252 make_tuple("ret,bw:150,dl:100", ""),
253 make_tuple("ret,bw:800,dl:100", "bbr"),
254 make_tuple("ret,bw:800,dl:100", ""),
255 make_tuple("ret,bw:150,dl:50", "bbr"),
256 make_tuple("ret,bw:150,dl:50", "")));
257} // namespace test
258} // namespace webrtc