1 /*
2 * Copyright (c) 2013 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
11 #include "call/rampup_tests.h"
12
13 #include <memory>
14
15 #include "absl/flags/flag.h"
16 #include "absl/strings/string_view.h"
17 #include "api/rtc_event_log/rtc_event_log_factory.h"
18 #include "api/rtc_event_log_output_file.h"
19 #include "api/task_queue/default_task_queue_factory.h"
20 #include "api/task_queue/task_queue_base.h"
21 #include "api/task_queue/task_queue_factory.h"
22 #include "api/test/metrics/global_metrics_logger_and_exporter.h"
23 #include "api/test/metrics/metric.h"
24 #include "call/fake_network_pipe.h"
25 #include "rtc_base/checks.h"
26 #include "rtc_base/logging.h"
27 #include "rtc_base/platform_thread.h"
28 #include "rtc_base/string_encode.h"
29 #include "rtc_base/task_queue_for_test.h"
30 #include "rtc_base/time_utils.h"
31 #include "test/encoder_settings.h"
32 #include "test/gtest.h"
33
34 ABSL_FLAG(std::string,
35 ramp_dump_name,
36 "",
37 "Filename for dumped received RTP stream.");
38
39 namespace webrtc {
40 namespace {
41
42 using ::webrtc::test::GetGlobalMetricsLogger;
43 using ::webrtc::test::ImprovementDirection;
44 using ::webrtc::test::Unit;
45
46 constexpr TimeDelta kPollInterval = TimeDelta::Millis(20);
47 static const int kExpectedHighVideoBitrateBps = 80000;
48 static const int kExpectedHighAudioBitrateBps = 30000;
49 static const int kLowBandwidthLimitBps = 20000;
50 // Set target detected bitrate to slightly larger than the target bitrate to
51 // avoid flakiness.
52 static const int kLowBitrateMarginBps = 2000;
53
GenerateSsrcs(size_t num_streams,uint32_t ssrc_offset)54 std::vector<uint32_t> GenerateSsrcs(size_t num_streams, uint32_t ssrc_offset) {
55 std::vector<uint32_t> ssrcs;
56 for (size_t i = 0; i != num_streams; ++i)
57 ssrcs.push_back(static_cast<uint32_t>(ssrc_offset + i));
58 return ssrcs;
59 }
60
61 } // namespace
62
RampUpTester(size_t num_video_streams,size_t num_audio_streams,size_t num_flexfec_streams,unsigned int start_bitrate_bps,int64_t min_run_time_ms,absl::string_view extension_type,bool rtx,bool red,bool report_perf_stats,TaskQueueBase * task_queue)63 RampUpTester::RampUpTester(size_t num_video_streams,
64 size_t num_audio_streams,
65 size_t num_flexfec_streams,
66 unsigned int start_bitrate_bps,
67 int64_t min_run_time_ms,
68 absl::string_view extension_type,
69 bool rtx,
70 bool red,
71 bool report_perf_stats,
72 TaskQueueBase* task_queue)
73 : EndToEndTest(test::CallTest::kLongTimeout),
74 clock_(Clock::GetRealTimeClock()),
75 num_video_streams_(num_video_streams),
76 num_audio_streams_(num_audio_streams),
77 num_flexfec_streams_(num_flexfec_streams),
78 rtx_(rtx),
79 red_(red),
80 report_perf_stats_(report_perf_stats),
81 sender_call_(nullptr),
82 send_stream_(nullptr),
83 send_transport_(nullptr),
84 send_simulated_network_(nullptr),
85 start_bitrate_bps_(start_bitrate_bps),
86 min_run_time_ms_(min_run_time_ms),
87 expected_bitrate_bps_(0),
88 test_start_ms_(-1),
89 ramp_up_finished_ms_(-1),
90 extension_type_(extension_type),
91 video_ssrcs_(GenerateSsrcs(num_video_streams_, 100)),
92 video_rtx_ssrcs_(GenerateSsrcs(num_video_streams_, 200)),
93 audio_ssrcs_(GenerateSsrcs(num_audio_streams_, 300)),
94 task_queue_(task_queue) {
95 if (red_)
96 EXPECT_EQ(0u, num_flexfec_streams_);
97 EXPECT_LE(num_audio_streams_, 1u);
98 }
99
100 RampUpTester::~RampUpTester() = default;
101
ModifySenderBitrateConfig(BitrateConstraints * bitrate_config)102 void RampUpTester::ModifySenderBitrateConfig(
103 BitrateConstraints* bitrate_config) {
104 if (start_bitrate_bps_ != 0) {
105 bitrate_config->start_bitrate_bps = start_bitrate_bps_;
106 }
107 bitrate_config->min_bitrate_bps = 10000;
108 }
109
OnVideoStreamsCreated(VideoSendStream * send_stream,const std::vector<VideoReceiveStreamInterface * > & receive_streams)110 void RampUpTester::OnVideoStreamsCreated(
111 VideoSendStream* send_stream,
112 const std::vector<VideoReceiveStreamInterface*>& receive_streams) {
113 send_stream_ = send_stream;
114 }
115
CreateSendTransport(TaskQueueBase * task_queue,Call * sender_call)116 std::unique_ptr<test::PacketTransport> RampUpTester::CreateSendTransport(
117 TaskQueueBase* task_queue,
118 Call* sender_call) {
119 auto network = std::make_unique<SimulatedNetwork>(forward_transport_config_);
120 send_simulated_network_ = network.get();
121 auto send_transport = std::make_unique<test::PacketTransport>(
122 task_queue, sender_call, this, test::PacketTransport::kSender,
123 test::CallTest::payload_type_map_,
124 std::make_unique<FakeNetworkPipe>(Clock::GetRealTimeClock(),
125 std::move(network)));
126 send_transport_ = send_transport.get();
127 return send_transport;
128 }
129
GetNumVideoStreams() const130 size_t RampUpTester::GetNumVideoStreams() const {
131 return num_video_streams_;
132 }
133
GetNumAudioStreams() const134 size_t RampUpTester::GetNumAudioStreams() const {
135 return num_audio_streams_;
136 }
137
GetNumFlexfecStreams() const138 size_t RampUpTester::GetNumFlexfecStreams() const {
139 return num_flexfec_streams_;
140 }
141
142 class RampUpTester::VideoStreamFactory
143 : public VideoEncoderConfig::VideoStreamFactoryInterface {
144 public:
VideoStreamFactory()145 VideoStreamFactory() {}
146
147 private:
CreateEncoderStreams(int frame_width,int frame_height,const VideoEncoderConfig & encoder_config)148 std::vector<VideoStream> CreateEncoderStreams(
149 int frame_width,
150 int frame_height,
151 const VideoEncoderConfig& encoder_config) override {
152 std::vector<VideoStream> streams =
153 test::CreateVideoStreams(frame_width, frame_height, encoder_config);
154 if (encoder_config.number_of_streams == 1) {
155 streams[0].target_bitrate_bps = streams[0].max_bitrate_bps = 2000000;
156 }
157 return streams;
158 }
159 };
160
ModifyVideoConfigs(VideoSendStream::Config * send_config,std::vector<VideoReceiveStreamInterface::Config> * receive_configs,VideoEncoderConfig * encoder_config)161 void RampUpTester::ModifyVideoConfigs(
162 VideoSendStream::Config* send_config,
163 std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
164 VideoEncoderConfig* encoder_config) {
165 send_config->suspend_below_min_bitrate = true;
166 encoder_config->number_of_streams = num_video_streams_;
167 encoder_config->max_bitrate_bps = 2000000;
168 encoder_config->video_stream_factory =
169 rtc::make_ref_counted<RampUpTester::VideoStreamFactory>();
170 if (num_video_streams_ == 1) {
171 // For single stream rampup until 1mbps
172 expected_bitrate_bps_ = kSingleStreamTargetBps;
173 } else {
174 // To ensure simulcast rate allocation.
175 send_config->rtp.payload_name = "VP8";
176 encoder_config->codec_type = kVideoCodecVP8;
177 std::vector<VideoStream> streams = test::CreateVideoStreams(
178 test::CallTest::kDefaultWidth, test::CallTest::kDefaultHeight,
179 *encoder_config);
180 // For multi stream rampup until all streams are being sent. That means
181 // enough bitrate to send all the target streams plus the min bitrate of
182 // the last one.
183 expected_bitrate_bps_ = streams.back().min_bitrate_bps;
184 for (size_t i = 0; i < streams.size() - 1; ++i) {
185 expected_bitrate_bps_ += streams[i].target_bitrate_bps;
186 }
187 }
188
189 send_config->rtp.extensions.clear();
190
191 bool transport_cc;
192 if (extension_type_ == RtpExtension::kAbsSendTimeUri) {
193 transport_cc = false;
194 send_config->rtp.extensions.push_back(
195 RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
196 } else if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
197 transport_cc = true;
198 send_config->rtp.extensions.push_back(RtpExtension(
199 extension_type_.c_str(), kTransportSequenceNumberExtensionId));
200 } else {
201 transport_cc = false;
202 send_config->rtp.extensions.push_back(RtpExtension(
203 extension_type_.c_str(), kTransmissionTimeOffsetExtensionId));
204 }
205
206 send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
207 send_config->rtp.ssrcs = video_ssrcs_;
208 if (rtx_) {
209 send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
210 send_config->rtp.rtx.ssrcs = video_rtx_ssrcs_;
211 }
212 if (red_) {
213 send_config->rtp.ulpfec.ulpfec_payload_type =
214 test::CallTest::kUlpfecPayloadType;
215 send_config->rtp.ulpfec.red_payload_type = test::CallTest::kRedPayloadType;
216 if (rtx_) {
217 send_config->rtp.ulpfec.red_rtx_payload_type =
218 test::CallTest::kRtxRedPayloadType;
219 }
220 }
221
222 size_t i = 0;
223 for (VideoReceiveStreamInterface::Config& recv_config : *receive_configs) {
224 recv_config.rtp.transport_cc = transport_cc;
225 recv_config.rtp.extensions = send_config->rtp.extensions;
226 recv_config.decoders.reserve(1);
227 recv_config.decoders[0].payload_type = send_config->rtp.payload_type;
228 recv_config.decoders[0].video_format =
229 SdpVideoFormat(send_config->rtp.payload_name);
230
231 recv_config.rtp.remote_ssrc = video_ssrcs_[i];
232 recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms;
233
234 if (red_) {
235 recv_config.rtp.red_payload_type =
236 send_config->rtp.ulpfec.red_payload_type;
237 recv_config.rtp.ulpfec_payload_type =
238 send_config->rtp.ulpfec.ulpfec_payload_type;
239 if (rtx_) {
240 recv_config.rtp.rtx_associated_payload_types
241 [send_config->rtp.ulpfec.red_rtx_payload_type] =
242 send_config->rtp.ulpfec.red_payload_type;
243 }
244 }
245
246 if (rtx_) {
247 recv_config.rtp.rtx_ssrc = video_rtx_ssrcs_[i];
248 recv_config.rtp
249 .rtx_associated_payload_types[send_config->rtp.rtx.payload_type] =
250 send_config->rtp.payload_type;
251 }
252 ++i;
253 }
254
255 RTC_DCHECK_LE(num_flexfec_streams_, 1);
256 if (num_flexfec_streams_ == 1) {
257 send_config->rtp.flexfec.payload_type = test::CallTest::kFlexfecPayloadType;
258 send_config->rtp.flexfec.ssrc = test::CallTest::kFlexfecSendSsrc;
259 send_config->rtp.flexfec.protected_media_ssrcs = {video_ssrcs_[0]};
260 }
261 }
262
ModifyAudioConfigs(AudioSendStream::Config * send_config,std::vector<AudioReceiveStreamInterface::Config> * receive_configs)263 void RampUpTester::ModifyAudioConfigs(
264 AudioSendStream::Config* send_config,
265 std::vector<AudioReceiveStreamInterface::Config>* receive_configs) {
266 if (num_audio_streams_ == 0)
267 return;
268
269 EXPECT_NE(RtpExtension::kTimestampOffsetUri, extension_type_)
270 << "Audio BWE not supported with toffset.";
271 EXPECT_NE(RtpExtension::kAbsSendTimeUri, extension_type_)
272 << "Audio BWE not supported with abs-send-time.";
273
274 send_config->rtp.ssrc = audio_ssrcs_[0];
275 send_config->rtp.extensions.clear();
276
277 send_config->min_bitrate_bps = 6000;
278 send_config->max_bitrate_bps = 60000;
279
280 bool transport_cc = false;
281 if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
282 transport_cc = true;
283 send_config->rtp.extensions.push_back(RtpExtension(
284 extension_type_.c_str(), kTransportSequenceNumberExtensionId));
285 }
286
287 for (AudioReceiveStreamInterface::Config& recv_config : *receive_configs) {
288 recv_config.rtp.transport_cc = transport_cc;
289 recv_config.rtp.extensions = send_config->rtp.extensions;
290 recv_config.rtp.remote_ssrc = send_config->rtp.ssrc;
291 }
292 }
293
ModifyFlexfecConfigs(std::vector<FlexfecReceiveStream::Config> * receive_configs)294 void RampUpTester::ModifyFlexfecConfigs(
295 std::vector<FlexfecReceiveStream::Config>* receive_configs) {
296 if (num_flexfec_streams_ == 0)
297 return;
298 RTC_DCHECK_EQ(1, num_flexfec_streams_);
299 (*receive_configs)[0].payload_type = test::CallTest::kFlexfecPayloadType;
300 (*receive_configs)[0].rtp.remote_ssrc = test::CallTest::kFlexfecSendSsrc;
301 (*receive_configs)[0].protected_media_ssrcs = {video_ssrcs_[0]};
302 (*receive_configs)[0].rtp.local_ssrc = video_ssrcs_[0];
303 if (extension_type_ == RtpExtension::kAbsSendTimeUri) {
304 (*receive_configs)[0].rtp.transport_cc = false;
305 (*receive_configs)[0].rtp.extensions.push_back(
306 RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
307 } else if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
308 (*receive_configs)[0].rtp.transport_cc = true;
309 (*receive_configs)[0].rtp.extensions.push_back(RtpExtension(
310 extension_type_.c_str(), kTransportSequenceNumberExtensionId));
311 }
312 }
313
OnCallsCreated(Call * sender_call,Call * receiver_call)314 void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) {
315 RTC_DCHECK(sender_call);
316 sender_call_ = sender_call;
317 pending_task_ = RepeatingTaskHandle::Start(task_queue_, [this] {
318 PollStats();
319 return kPollInterval;
320 });
321 }
322
PollStats()323 void RampUpTester::PollStats() {
324 RTC_DCHECK_RUN_ON(task_queue_);
325
326 Call::Stats stats = sender_call_->GetStats();
327 EXPECT_GE(expected_bitrate_bps_, 0);
328
329 if (stats.send_bandwidth_bps >= expected_bitrate_bps_ &&
330 (min_run_time_ms_ == -1 ||
331 clock_->TimeInMilliseconds() - test_start_ms_ >= min_run_time_ms_)) {
332 ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
333 observation_complete_.Set();
334 pending_task_.Stop();
335 }
336 }
337
ReportResult(absl::string_view measurement,size_t value,Unit unit,ImprovementDirection improvement_direction) const338 void RampUpTester::ReportResult(
339 absl::string_view measurement,
340 size_t value,
341 Unit unit,
342 ImprovementDirection improvement_direction) const {
343 GetGlobalMetricsLogger()->LogSingleValueMetric(
344 measurement,
345 ::testing::UnitTest::GetInstance()->current_test_info()->name(), value,
346 unit, improvement_direction);
347 }
348
AccumulateStats(const VideoSendStream::StreamStats & stream,size_t * total_packets_sent,size_t * total_sent,size_t * padding_sent,size_t * media_sent) const349 void RampUpTester::AccumulateStats(const VideoSendStream::StreamStats& stream,
350 size_t* total_packets_sent,
351 size_t* total_sent,
352 size_t* padding_sent,
353 size_t* media_sent) const {
354 *total_packets_sent += stream.rtp_stats.transmitted.packets +
355 stream.rtp_stats.retransmitted.packets +
356 stream.rtp_stats.fec.packets;
357 *total_sent += stream.rtp_stats.transmitted.TotalBytes() +
358 stream.rtp_stats.retransmitted.TotalBytes() +
359 stream.rtp_stats.fec.TotalBytes();
360 *padding_sent += stream.rtp_stats.transmitted.padding_bytes +
361 stream.rtp_stats.retransmitted.padding_bytes +
362 stream.rtp_stats.fec.padding_bytes;
363 *media_sent += stream.rtp_stats.MediaPayloadBytes();
364 }
365
TriggerTestDone()366 void RampUpTester::TriggerTestDone() {
367 RTC_DCHECK_GE(test_start_ms_, 0);
368
369 // Stop polling stats.
370 // Corner case for field_trials=WebRTC-QuickPerfTest/Enabled/
371 SendTask(task_queue_, [this] { pending_task_.Stop(); });
372
373 // TODO(holmer): Add audio send stats here too when those APIs are available.
374 if (!send_stream_)
375 return;
376
377 VideoSendStream::Stats send_stats;
378 SendTask(task_queue_, [&] { send_stats = send_stream_->GetStats(); });
379
380 send_stream_ = nullptr; // To avoid dereferencing a bad pointer.
381
382 size_t total_packets_sent = 0;
383 size_t total_sent = 0;
384 size_t padding_sent = 0;
385 size_t media_sent = 0;
386 for (uint32_t ssrc : video_ssrcs_) {
387 AccumulateStats(send_stats.substreams[ssrc], &total_packets_sent,
388 &total_sent, &padding_sent, &media_sent);
389 }
390
391 size_t rtx_total_packets_sent = 0;
392 size_t rtx_total_sent = 0;
393 size_t rtx_padding_sent = 0;
394 size_t rtx_media_sent = 0;
395 for (uint32_t rtx_ssrc : video_rtx_ssrcs_) {
396 AccumulateStats(send_stats.substreams[rtx_ssrc], &rtx_total_packets_sent,
397 &rtx_total_sent, &rtx_padding_sent, &rtx_media_sent);
398 }
399
400 if (report_perf_stats_) {
401 ReportResult("ramp-up-media-sent", media_sent, Unit::kBytes,
402 ImprovementDirection::kBiggerIsBetter);
403 ReportResult("ramp-up-padding-sent", padding_sent, Unit::kBytes,
404 ImprovementDirection::kSmallerIsBetter);
405 ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, Unit::kBytes,
406 ImprovementDirection::kBiggerIsBetter);
407 ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, Unit::kBytes,
408 ImprovementDirection::kSmallerIsBetter);
409 if (ramp_up_finished_ms_ >= 0) {
410 ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_,
411 Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter);
412 }
413 ReportResult("ramp-up-average-network-latency",
414 send_transport_->GetAverageDelayMs(), Unit::kMilliseconds,
415 ImprovementDirection::kSmallerIsBetter);
416 }
417 }
418
PerformTest()419 void RampUpTester::PerformTest() {
420 test_start_ms_ = clock_->TimeInMilliseconds();
421 EXPECT_TRUE(Wait()) << "Timed out while waiting for ramp-up to complete.";
422 TriggerTestDone();
423 }
424
RampUpDownUpTester(size_t num_video_streams,size_t num_audio_streams,size_t num_flexfec_streams,unsigned int start_bitrate_bps,absl::string_view extension_type,bool rtx,bool red,const std::vector<int> & loss_rates,bool report_perf_stats,TaskQueueBase * task_queue)425 RampUpDownUpTester::RampUpDownUpTester(size_t num_video_streams,
426 size_t num_audio_streams,
427 size_t num_flexfec_streams,
428 unsigned int start_bitrate_bps,
429 absl::string_view extension_type,
430 bool rtx,
431 bool red,
432 const std::vector<int>& loss_rates,
433 bool report_perf_stats,
434 TaskQueueBase* task_queue)
435 : RampUpTester(num_video_streams,
436 num_audio_streams,
437 num_flexfec_streams,
438 start_bitrate_bps,
439 0,
440 extension_type,
441 rtx,
442 red,
443 report_perf_stats,
444 task_queue),
445 link_rates_({4 * GetExpectedHighBitrate() / (3 * 1000),
446 kLowBandwidthLimitBps / 1000,
447 4 * GetExpectedHighBitrate() / (3 * 1000), 0}),
448 test_state_(kFirstRampup),
449 next_state_(kTransitionToNextState),
450 state_start_ms_(clock_->TimeInMilliseconds()),
451 interval_start_ms_(clock_->TimeInMilliseconds()),
452 sent_bytes_(0),
453 loss_rates_(loss_rates) {
454 forward_transport_config_.link_capacity_kbps = link_rates_[test_state_];
455 forward_transport_config_.queue_delay_ms = 100;
456 forward_transport_config_.loss_percent = loss_rates_[test_state_];
457 }
458
~RampUpDownUpTester()459 RampUpDownUpTester::~RampUpDownUpTester() {}
460
PollStats()461 void RampUpDownUpTester::PollStats() {
462 if (test_state_ == kTestEnd) {
463 pending_task_.Stop();
464 }
465
466 int transmit_bitrate_bps = 0;
467 bool suspended = false;
468 if (num_video_streams_ > 0 && send_stream_) {
469 webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
470 for (const auto& it : stats.substreams) {
471 transmit_bitrate_bps += it.second.total_bitrate_bps;
472 }
473 suspended = stats.suspended;
474 }
475 if (num_audio_streams_ > 0 && sender_call_) {
476 // An audio send stream doesn't have bitrate stats, so the call send BW is
477 // currently used instead.
478 transmit_bitrate_bps = sender_call_->GetStats().send_bandwidth_bps;
479 }
480
481 EvolveTestState(transmit_bitrate_bps, suspended);
482 }
483
ModifyReceiverBitrateConfig(BitrateConstraints * bitrate_config)484 void RampUpDownUpTester::ModifyReceiverBitrateConfig(
485 BitrateConstraints* bitrate_config) {
486 bitrate_config->min_bitrate_bps = 10000;
487 }
488
GetModifierString() const489 std::string RampUpDownUpTester::GetModifierString() const {
490 std::string str("_");
491 if (num_video_streams_ > 0) {
492 str += rtc::ToString(num_video_streams_);
493 str += "stream";
494 str += (num_video_streams_ > 1 ? "s" : "");
495 str += "_";
496 }
497 if (num_audio_streams_ > 0) {
498 str += rtc::ToString(num_audio_streams_);
499 str += "stream";
500 str += (num_audio_streams_ > 1 ? "s" : "");
501 str += "_";
502 }
503 str += (rtx_ ? "" : "no");
504 str += "rtx_";
505 str += (red_ ? "" : "no");
506 str += "red";
507 return str;
508 }
509
GetExpectedHighBitrate() const510 int RampUpDownUpTester::GetExpectedHighBitrate() const {
511 int expected_bitrate_bps = 0;
512 if (num_audio_streams_ > 0)
513 expected_bitrate_bps += kExpectedHighAudioBitrateBps;
514 if (num_video_streams_ > 0)
515 expected_bitrate_bps += kExpectedHighVideoBitrateBps;
516 return expected_bitrate_bps;
517 }
518
GetFecBytes() const519 size_t RampUpDownUpTester::GetFecBytes() const {
520 size_t flex_fec_bytes = 0;
521 if (num_flexfec_streams_ > 0) {
522 webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
523 for (const auto& kv : stats.substreams)
524 flex_fec_bytes += kv.second.rtp_stats.fec.TotalBytes();
525 }
526 return flex_fec_bytes;
527 }
528
ExpectingFec() const529 bool RampUpDownUpTester::ExpectingFec() const {
530 return num_flexfec_streams_ > 0 && forward_transport_config_.loss_percent > 0;
531 }
532
EvolveTestState(int bitrate_bps,bool suspended)533 void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) {
534 int64_t now = clock_->TimeInMilliseconds();
535 switch (test_state_) {
536 case kFirstRampup:
537 EXPECT_FALSE(suspended);
538 if (bitrate_bps >= GetExpectedHighBitrate()) {
539 if (report_perf_stats_) {
540 GetGlobalMetricsLogger()->LogSingleValueMetric(
541 "ramp_up_down_up" + GetModifierString(), "first_rampup",
542 now - state_start_ms_, Unit::kMilliseconds,
543 ImprovementDirection::kSmallerIsBetter);
544 }
545 // Apply loss during the transition between states if FEC is enabled.
546 forward_transport_config_.loss_percent = loss_rates_[test_state_];
547 test_state_ = kTransitionToNextState;
548 next_state_ = kLowRate;
549 }
550 break;
551 case kLowRate: {
552 // Audio streams are never suspended.
553 bool check_suspend_state = num_video_streams_ > 0;
554 if (bitrate_bps < kLowBandwidthLimitBps + kLowBitrateMarginBps &&
555 suspended == check_suspend_state) {
556 if (report_perf_stats_) {
557 GetGlobalMetricsLogger()->LogSingleValueMetric(
558 "ramp_up_down_up" + GetModifierString(), "rampdown",
559 now - state_start_ms_, Unit::kMilliseconds,
560 ImprovementDirection::kSmallerIsBetter);
561 }
562 // Apply loss during the transition between states if FEC is enabled.
563 forward_transport_config_.loss_percent = loss_rates_[test_state_];
564 test_state_ = kTransitionToNextState;
565 next_state_ = kSecondRampup;
566 }
567 break;
568 }
569 case kSecondRampup:
570 if (bitrate_bps >= GetExpectedHighBitrate() && !suspended) {
571 if (report_perf_stats_) {
572 GetGlobalMetricsLogger()->LogSingleValueMetric(
573 "ramp_up_down_up" + GetModifierString(), "second_rampup",
574 now - state_start_ms_, Unit::kMilliseconds,
575 ImprovementDirection::kSmallerIsBetter);
576 ReportResult("ramp-up-down-up-average-network-latency",
577 send_transport_->GetAverageDelayMs(),
578 Unit::kMilliseconds,
579 ImprovementDirection::kSmallerIsBetter);
580 }
581 // Apply loss during the transition between states if FEC is enabled.
582 forward_transport_config_.loss_percent = loss_rates_[test_state_];
583 test_state_ = kTransitionToNextState;
584 next_state_ = kTestEnd;
585 }
586 break;
587 case kTestEnd:
588 observation_complete_.Set();
589 break;
590 case kTransitionToNextState:
591 if (!ExpectingFec() || GetFecBytes() > 0) {
592 test_state_ = next_state_;
593 forward_transport_config_.link_capacity_kbps = link_rates_[test_state_];
594 // No loss while ramping up and down as it may affect the BWE
595 // negatively, making the test flaky.
596 forward_transport_config_.loss_percent = 0;
597 state_start_ms_ = now;
598 interval_start_ms_ = now;
599 sent_bytes_ = 0;
600 send_simulated_network_->SetConfig(forward_transport_config_);
601 }
602 break;
603 }
604 }
605
606 class RampUpTest : public test::CallTest {
607 public:
RampUpTest()608 RampUpTest()
609 : task_queue_factory_(CreateDefaultTaskQueueFactory()),
610 rtc_event_log_factory_(task_queue_factory_.get()) {
611 std::string dump_name(absl::GetFlag(FLAGS_ramp_dump_name));
612 if (!dump_name.empty()) {
613 send_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
614 RtcEventLog::EncodingType::Legacy);
615 recv_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
616 RtcEventLog::EncodingType::Legacy);
617 bool event_log_started =
618 send_event_log_->StartLogging(
619 std::make_unique<RtcEventLogOutputFile>(
620 dump_name + ".send.rtc.dat", RtcEventLog::kUnlimitedOutput),
621 RtcEventLog::kImmediateOutput) &&
622 recv_event_log_->StartLogging(
623 std::make_unique<RtcEventLogOutputFile>(
624 dump_name + ".recv.rtc.dat", RtcEventLog::kUnlimitedOutput),
625 RtcEventLog::kImmediateOutput);
626 RTC_DCHECK(event_log_started);
627 }
628 }
629
630 private:
631 const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
632 RtcEventLogFactory rtc_event_log_factory_;
633 };
634
635 static const uint32_t kStartBitrateBps = 60000;
636
TEST_F(RampUpTest,UpDownUpAbsSendTimeSimulcastRedRtx)637 TEST_F(RampUpTest, UpDownUpAbsSendTimeSimulcastRedRtx) {
638 std::vector<int> loss_rates = {0, 0, 0, 0};
639 RampUpDownUpTester test(3, 0, 0, kStartBitrateBps,
640 RtpExtension::kAbsSendTimeUri, true, true, loss_rates,
641 true, task_queue());
642 RunBaseTest(&test);
643 }
644
645 // TODO(bugs.webrtc.org/8878)
646 #if defined(WEBRTC_MAC)
647 #define MAYBE_UpDownUpTransportSequenceNumberRtx \
648 DISABLED_UpDownUpTransportSequenceNumberRtx
649 #else
650 #define MAYBE_UpDownUpTransportSequenceNumberRtx \
651 UpDownUpTransportSequenceNumberRtx
652 #endif
TEST_F(RampUpTest,MAYBE_UpDownUpTransportSequenceNumberRtx)653 TEST_F(RampUpTest, MAYBE_UpDownUpTransportSequenceNumberRtx) {
654 std::vector<int> loss_rates = {0, 0, 0, 0};
655 RampUpDownUpTester test(3, 0, 0, kStartBitrateBps,
656 RtpExtension::kTransportSequenceNumberUri, true,
657 false, loss_rates, true, task_queue());
658 RunBaseTest(&test);
659 }
660
661 // TODO(holmer): Tests which don't report perf stats should be moved to a
662 // different executable since they per definition are not perf tests.
663 // This test is disabled because it crashes on Linux, and is flaky on other
664 // platforms. See: crbug.com/webrtc/7919
TEST_F(RampUpTest,DISABLED_UpDownUpTransportSequenceNumberPacketLoss)665 TEST_F(RampUpTest, DISABLED_UpDownUpTransportSequenceNumberPacketLoss) {
666 std::vector<int> loss_rates = {20, 0, 0, 0};
667 RampUpDownUpTester test(1, 0, 1, kStartBitrateBps,
668 RtpExtension::kTransportSequenceNumberUri, true,
669 false, loss_rates, false, task_queue());
670 RunBaseTest(&test);
671 }
672
673 // TODO(bugs.webrtc.org/8878)
674 #if defined(WEBRTC_MAC)
675 #define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \
676 DISABLED_UpDownUpAudioVideoTransportSequenceNumberRtx
677 #else
678 #define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \
679 UpDownUpAudioVideoTransportSequenceNumberRtx
680 #endif
TEST_F(RampUpTest,MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx)681 TEST_F(RampUpTest, MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx) {
682 std::vector<int> loss_rates = {0, 0, 0, 0};
683 RampUpDownUpTester test(3, 1, 0, kStartBitrateBps,
684 RtpExtension::kTransportSequenceNumberUri, true,
685 false, loss_rates, false, task_queue());
686 RunBaseTest(&test);
687 }
688
TEST_F(RampUpTest,UpDownUpAudioTransportSequenceNumberRtx)689 TEST_F(RampUpTest, UpDownUpAudioTransportSequenceNumberRtx) {
690 std::vector<int> loss_rates = {0, 0, 0, 0};
691 RampUpDownUpTester test(0, 1, 0, kStartBitrateBps,
692 RtpExtension::kTransportSequenceNumberUri, true,
693 false, loss_rates, false, task_queue());
694 RunBaseTest(&test);
695 }
696
TEST_F(RampUpTest,TOffsetSimulcastRedRtx)697 TEST_F(RampUpTest, TOffsetSimulcastRedRtx) {
698 RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTimestampOffsetUri, true,
699 true, true, task_queue());
700 RunBaseTest(&test);
701 }
702
TEST_F(RampUpTest,AbsSendTime)703 TEST_F(RampUpTest, AbsSendTime) {
704 RampUpTester test(1, 0, 0, 0, 0, RtpExtension::kAbsSendTimeUri, false, false,
705 false, task_queue());
706 RunBaseTest(&test);
707 }
708
TEST_F(RampUpTest,AbsSendTimeSimulcastRedRtx)709 TEST_F(RampUpTest, AbsSendTimeSimulcastRedRtx) {
710 RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kAbsSendTimeUri, true, true,
711 true, task_queue());
712 RunBaseTest(&test);
713 }
714
TEST_F(RampUpTest,TransportSequenceNumber)715 TEST_F(RampUpTest, TransportSequenceNumber) {
716 RampUpTester test(1, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
717 false, false, false, task_queue());
718 RunBaseTest(&test);
719 }
720
TEST_F(RampUpTest,TransportSequenceNumberSimulcast)721 TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
722 RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
723 false, false, false, task_queue());
724 RunBaseTest(&test);
725 }
726
TEST_F(RampUpTest,TransportSequenceNumberSimulcastRedRtx)727 TEST_F(RampUpTest, TransportSequenceNumberSimulcastRedRtx) {
728 RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
729 true, true, true, task_queue());
730 RunBaseTest(&test);
731 }
732
TEST_F(RampUpTest,AudioTransportSequenceNumber)733 TEST_F(RampUpTest, AudioTransportSequenceNumber) {
734 RampUpTester test(0, 1, 0, 300000, 10000,
735 RtpExtension::kTransportSequenceNumberUri, false, false,
736 false, task_queue());
737 RunBaseTest(&test);
738 }
739
740 } // namespace webrtc
741