1 /*
2 * Copyright 2019 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 <atomic>
11
12 #include "api/test/network_emulation/create_cross_traffic.h"
13 #include "api/test/network_emulation/cross_traffic.h"
14 #include "test/field_trial.h"
15 #include "test/gtest.h"
16 #include "test/scenario/scenario.h"
17
18 namespace webrtc {
19 namespace test {
20 namespace {
21 using Capture = VideoStreamConfig::Source::Capture;
22 using ContentType = VideoStreamConfig::Encoder::ContentType;
23 using Codec = VideoStreamConfig::Encoder::Codec;
24 using CodecImpl = VideoStreamConfig::Encoder::Implementation;
25 } // namespace
26
TEST(VideoStreamTest,ReceivesFramesFromFileBasedStreams)27 TEST(VideoStreamTest, ReceivesFramesFromFileBasedStreams) {
28 TimeDelta kRunTime = TimeDelta::Millis(500);
29 std::vector<int> kFrameRates = {15, 30};
30 std::deque<std::atomic<int>> frame_counts(2);
31 frame_counts[0] = 0;
32 frame_counts[1] = 0;
33 {
34 Scenario s;
35 auto route =
36 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
37 {s.CreateSimulationNode(NetworkSimulationConfig())},
38 s.CreateClient("callee", CallClientConfig()),
39 {s.CreateSimulationNode(NetworkSimulationConfig())});
40
41 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
42 c->hooks.frame_pair_handlers = {
43 [&](const VideoFramePair&) { frame_counts[0]++; }};
44 c->source.capture = Capture::kVideoFile;
45 c->source.video_file.name = "foreman_cif";
46 c->source.video_file.width = 352;
47 c->source.video_file.height = 288;
48 c->source.framerate = kFrameRates[0];
49 c->encoder.implementation = CodecImpl::kSoftware;
50 c->encoder.codec = Codec::kVideoCodecVP8;
51 });
52 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
53 c->hooks.frame_pair_handlers = {
54 [&](const VideoFramePair&) { frame_counts[1]++; }};
55 c->source.capture = Capture::kImageSlides;
56 c->source.slides.images.crop.width = 320;
57 c->source.slides.images.crop.height = 240;
58 c->source.framerate = kFrameRates[1];
59 c->encoder.implementation = CodecImpl::kSoftware;
60 c->encoder.codec = Codec::kVideoCodecVP9;
61 });
62 s.RunFor(kRunTime);
63 }
64 std::vector<int> expected_counts;
65 for (int fps : kFrameRates)
66 expected_counts.push_back(
67 static_cast<int>(kRunTime.seconds<double>() * fps * 0.8));
68
69 EXPECT_GE(frame_counts[0], expected_counts[0]);
70 EXPECT_GE(frame_counts[1], expected_counts[1]);
71 }
72
TEST(VideoStreamTest,ReceivesVp8SimulcastFrames)73 TEST(VideoStreamTest, ReceivesVp8SimulcastFrames) {
74 TimeDelta kRunTime = TimeDelta::Millis(500);
75 int kFrameRate = 30;
76
77 std::deque<std::atomic<int>> frame_counts(3);
78 frame_counts[0] = 0;
79 frame_counts[1] = 0;
80 frame_counts[2] = 0;
81 {
82 Scenario s;
83 auto route =
84 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
85 {s.CreateSimulationNode(NetworkSimulationConfig())},
86 s.CreateClient("callee", CallClientConfig()),
87 {s.CreateSimulationNode(NetworkSimulationConfig())});
88 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
89 // TODO(srte): Replace with code checking for all simulcast streams when
90 // there's a hook available for that.
91 c->hooks.frame_pair_handlers = {[&](const VideoFramePair& info) {
92 frame_counts[info.layer_id]++;
93 RTC_DCHECK(info.decoded);
94 printf("%i: [%3i->%3i, %i], %i->%i, \n", info.layer_id, info.capture_id,
95 info.decode_id, info.repeated, info.captured->width(),
96 info.decoded->width());
97 }};
98 c->source.framerate = kFrameRate;
99 // The resolution must be high enough to allow smaller layers to be
100 // created.
101 c->source.generator.width = 1024;
102 c->source.generator.height = 768;
103 c->encoder.implementation = CodecImpl::kSoftware;
104 c->encoder.codec = Codec::kVideoCodecVP8;
105 // Enable simulcast.
106 c->encoder.simulcast_streams = {webrtc::ScalabilityMode::kL1T1,
107 webrtc::ScalabilityMode::kL1T1,
108 webrtc::ScalabilityMode::kL1T1};
109
110 });
111 s.RunFor(kRunTime);
112 }
113
114 // Using high error margin to avoid flakyness.
115 const int kExpectedCount =
116 static_cast<int>(kRunTime.seconds<double>() * kFrameRate * 0.5);
117
118 EXPECT_GE(frame_counts[0], kExpectedCount);
119 EXPECT_GE(frame_counts[1], kExpectedCount);
120 EXPECT_GE(frame_counts[2], kExpectedCount);
121 }
122
TEST(VideoStreamTest,SendsNacksOnLoss)123 TEST(VideoStreamTest, SendsNacksOnLoss) {
124 Scenario s;
125 auto route =
126 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
127 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
128 c->loss_rate = 0.2;
129 })},
130 s.CreateClient("callee", CallClientConfig()),
131 {s.CreateSimulationNode(NetworkSimulationConfig())});
132 // NACK retransmissions are enabled by default.
133 auto video = s.CreateVideoStream(route->forward(), VideoStreamConfig());
134 s.RunFor(TimeDelta::Seconds(1));
135 int retransmit_packets = 0;
136 VideoSendStream::Stats stats;
137 route->first()->SendTask([&]() { stats = video->send()->GetStats(); });
138 for (const auto& substream : stats.substreams) {
139 retransmit_packets += substream.second.rtp_stats.retransmitted.packets;
140 }
141 EXPECT_GT(retransmit_packets, 0);
142 }
143
TEST(VideoStreamTest,SendsFecWithUlpFec)144 TEST(VideoStreamTest, SendsFecWithUlpFec) {
145 Scenario s;
146 auto route =
147 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
148 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
149 c->loss_rate = 0.1;
150 c->delay = TimeDelta::Millis(100);
151 })},
152 s.CreateClient("callee", CallClientConfig()),
153 {s.CreateSimulationNode(NetworkSimulationConfig())});
154 auto video = s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
155 // We do not allow NACK+ULPFEC for generic codec, using VP8.
156 c->encoder.codec = VideoStreamConfig::Encoder::Codec::kVideoCodecVP8;
157 c->stream.use_ulpfec = true;
158 });
159 s.RunFor(TimeDelta::Seconds(5));
160 VideoSendStream::Stats video_stats;
161 route->first()->SendTask([&]() { video_stats = video->send()->GetStats(); });
162 EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u);
163 }
TEST(VideoStreamTest,SendsFecWithFlexFec)164 TEST(VideoStreamTest, SendsFecWithFlexFec) {
165 Scenario s;
166 auto route =
167 s.CreateRoutes(s.CreateClient("caller", CallClientConfig()),
168 {s.CreateSimulationNode([](NetworkSimulationConfig* c) {
169 c->loss_rate = 0.1;
170 c->delay = TimeDelta::Millis(100);
171 })},
172 s.CreateClient("callee", CallClientConfig()),
173 {s.CreateSimulationNode(NetworkSimulationConfig())});
174 auto video = s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
175 c->stream.use_flexfec = true;
176 });
177 s.RunFor(TimeDelta::Seconds(5));
178 VideoSendStream::Stats video_stats;
179 route->first()->SendTask([&]() { video_stats = video->send()->GetStats(); });
180 EXPECT_GT(video_stats.substreams.begin()->second.rtp_stats.fec.packets, 0u);
181 }
182
TEST(VideoStreamTest,ResolutionAdaptsToAvailableBandwidth)183 TEST(VideoStreamTest, ResolutionAdaptsToAvailableBandwidth) {
184 // Declared before scenario to avoid use after free.
185 std::atomic<size_t> num_qvga_frames_(0);
186 std::atomic<size_t> num_vga_frames_(0);
187
188 Scenario s;
189 // Link has enough capacity for VGA.
190 NetworkSimulationConfig net_conf;
191 net_conf.bandwidth = DataRate::KilobitsPerSec(800);
192 net_conf.delay = TimeDelta::Millis(50);
193 auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
194 c->transport.rates.start_rate = DataRate::KilobitsPerSec(800);
195 });
196 auto send_net = {s.CreateSimulationNode(net_conf)};
197 auto ret_net = {s.CreateSimulationNode(net_conf)};
198 auto* route = s.CreateRoutes(
199 client, send_net, s.CreateClient("return", CallClientConfig()), ret_net);
200
201 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
202 c->hooks.frame_pair_handlers = {[&](const VideoFramePair& info) {
203 if (info.decoded->width() == 640) {
204 ++num_vga_frames_;
205 } else if (info.decoded->width() == 320) {
206 ++num_qvga_frames_;
207 } else {
208 ADD_FAILURE() << "Unexpected resolution: " << info.decoded->width();
209 }
210 }};
211 c->source.framerate = 30;
212 // The resolution must be high enough to allow smaller layers to be
213 // created.
214 c->source.generator.width = 640;
215 c->source.generator.height = 480;
216 c->encoder.implementation = CodecImpl::kSoftware;
217 c->encoder.codec = Codec::kVideoCodecVP9;
218 // Enable SVC.
219 c->encoder.simulcast_streams = {webrtc::ScalabilityMode::kL2T1};
220 });
221
222 // Run for a few seconds, until streams have stabilized,
223 // check that we are sending VGA.
224 s.RunFor(TimeDelta::Seconds(5));
225 EXPECT_GT(num_vga_frames_, 0u);
226
227 // Trigger cross traffic, run until we have seen 3 consecutive
228 // seconds with no VGA frames due to reduced available bandwidth.
229 auto cross_traffic = s.net()->StartCrossTraffic(CreateFakeTcpCrossTraffic(
230 s.net()->CreateRoute(send_net), s.net()->CreateRoute(ret_net),
231 FakeTcpConfig()));
232
233 int num_seconds_without_vga = 0;
234 int num_iterations = 0;
235 do {
236 ASSERT_LE(++num_iterations, 100);
237 num_qvga_frames_ = 0;
238 num_vga_frames_ = 0;
239 s.RunFor(TimeDelta::Seconds(1));
240 if (num_qvga_frames_ > 0 && num_vga_frames_ == 0) {
241 ++num_seconds_without_vga;
242 } else {
243 num_seconds_without_vga = 0;
244 }
245 } while (num_seconds_without_vga < 3);
246
247 // Stop cross traffic, make sure we recover and get VGA frames agian.
248 s.net()->StopCrossTraffic(cross_traffic);
249 num_qvga_frames_ = 0;
250 num_vga_frames_ = 0;
251
252 s.RunFor(TimeDelta::Seconds(40));
253 EXPECT_GT(num_qvga_frames_, 0u);
254 EXPECT_GT(num_vga_frames_, 0u);
255 }
256
TEST(VideoStreamTest,SuspendsBelowMinBitrate)257 TEST(VideoStreamTest, SuspendsBelowMinBitrate) {
258 const DataRate kMinVideoBitrate = DataRate::KilobitsPerSec(30);
259
260 // Declared before scenario to avoid use after free.
261 std::atomic<Timestamp> last_frame_timestamp(Timestamp::MinusInfinity());
262
263 Scenario s;
264 NetworkSimulationConfig net_config;
265 net_config.bandwidth = kMinVideoBitrate * 4;
266 net_config.delay = TimeDelta::Millis(10);
267 auto* client = s.CreateClient("send", [&](CallClientConfig* c) {
268 // Min transmit rate needs to be lower than kMinVideoBitrate for this test
269 // to make sense.
270 c->transport.rates.min_rate = kMinVideoBitrate / 2;
271 c->transport.rates.start_rate = kMinVideoBitrate;
272 c->transport.rates.max_rate = kMinVideoBitrate * 2;
273 });
274 auto send_net = s.CreateMutableSimulationNode(
275 [&](NetworkSimulationConfig* c) { *c = net_config; });
276 auto ret_net = {s.CreateSimulationNode(net_config)};
277 auto* route =
278 s.CreateRoutes(client, {send_net->node()},
279 s.CreateClient("return", CallClientConfig()), ret_net);
280
281 s.CreateVideoStream(route->forward(), [&](VideoStreamConfig* c) {
282 c->hooks.frame_pair_handlers = {[&](const VideoFramePair& pair) {
283 if (pair.repeated == 0) {
284 last_frame_timestamp = pair.capture_time;
285 }
286 }};
287 c->source.framerate = 30;
288 c->source.generator.width = 320;
289 c->source.generator.height = 180;
290 c->encoder.implementation = CodecImpl::kFake;
291 c->encoder.codec = Codec::kVideoCodecVP8;
292 c->encoder.min_data_rate = kMinVideoBitrate;
293 c->encoder.suspend_below_min_bitrate = true;
294 c->stream.pad_to_rate = kMinVideoBitrate;
295 });
296
297 // Run for a few seconds, check we have received at least one frame.
298 s.RunFor(TimeDelta::Seconds(2));
299 EXPECT_TRUE(last_frame_timestamp.load().IsFinite());
300
301 // Degrade network to below min bitrate.
302 send_net->UpdateConfig([&](NetworkSimulationConfig* c) {
303 c->bandwidth = kMinVideoBitrate * 0.9;
304 });
305
306 // Run for 20s, verify that no frames arrive that were captured after the
307 // first five seconds, allowing some margin for BWE backoff to trigger and
308 // packets already in the pipeline to potentially arrive.
309 s.RunFor(TimeDelta::Seconds(20));
310 EXPECT_GT(s.Now() - last_frame_timestamp, TimeDelta::Seconds(15));
311
312 // Relax the network constraints and run for a while more, verify that we
313 // start receiving frames again.
314 send_net->UpdateConfig(
315 [&](NetworkSimulationConfig* c) { c->bandwidth = kMinVideoBitrate * 4; });
316 last_frame_timestamp = Timestamp::MinusInfinity();
317 s.RunFor(TimeDelta::Seconds(15));
318 EXPECT_TRUE(last_frame_timestamp.load().IsFinite());
319 }
320
321 } // namespace test
322 } // namespace webrtc
323