• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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