mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 06:40:43 +01:00

This cl/ implements configuring of encode resolution in the video_stream_encoder (webrtc_video_engine) in a way that is independent of frame resolution (i.e not using scale_resolution_down_by). The cl/ reuses the VideoAdapter as is, and hence the output resolution will be the same as it is today. Anticipated further patches 3) Hook up resource adaptation 4) Let VideoSource do adaption if possible Bug: webrtc:14451 Change-Id: I881b031c5b23be26cacfe138730154f1cb1b66a8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/276742 Reviewed-by: Artem Titov <titovartem@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38245}
740 lines
27 KiB
C++
740 lines
27 KiB
C++
/*
|
|
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "call/rampup_tests.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "absl/flags/flag.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "api/rtc_event_log/rtc_event_log_factory.h"
|
|
#include "api/rtc_event_log_output_file.h"
|
|
#include "api/task_queue/default_task_queue_factory.h"
|
|
#include "api/task_queue/task_queue_base.h"
|
|
#include "api/task_queue/task_queue_factory.h"
|
|
#include "api/test/metrics/global_metrics_logger_and_exporter.h"
|
|
#include "api/test/metrics/metric.h"
|
|
#include "call/fake_network_pipe.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/platform_thread.h"
|
|
#include "rtc_base/string_encode.h"
|
|
#include "rtc_base/task_queue_for_test.h"
|
|
#include "rtc_base/time_utils.h"
|
|
#include "test/encoder_settings.h"
|
|
#include "test/gtest.h"
|
|
|
|
ABSL_FLAG(std::string,
|
|
ramp_dump_name,
|
|
"",
|
|
"Filename for dumped received RTP stream.");
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
using ::webrtc::test::GetGlobalMetricsLogger;
|
|
using ::webrtc::test::ImprovementDirection;
|
|
using ::webrtc::test::Unit;
|
|
|
|
constexpr TimeDelta kPollInterval = TimeDelta::Millis(20);
|
|
static const int kExpectedHighVideoBitrateBps = 80000;
|
|
static const int kExpectedHighAudioBitrateBps = 30000;
|
|
static const int kLowBandwidthLimitBps = 20000;
|
|
// Set target detected bitrate to slightly larger than the target bitrate to
|
|
// avoid flakiness.
|
|
static const int kLowBitrateMarginBps = 2000;
|
|
|
|
std::vector<uint32_t> GenerateSsrcs(size_t num_streams, uint32_t ssrc_offset) {
|
|
std::vector<uint32_t> ssrcs;
|
|
for (size_t i = 0; i != num_streams; ++i)
|
|
ssrcs.push_back(static_cast<uint32_t>(ssrc_offset + i));
|
|
return ssrcs;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
RampUpTester::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)
|
|
: EndToEndTest(test::CallTest::kLongTimeout),
|
|
clock_(Clock::GetRealTimeClock()),
|
|
num_video_streams_(num_video_streams),
|
|
num_audio_streams_(num_audio_streams),
|
|
num_flexfec_streams_(num_flexfec_streams),
|
|
rtx_(rtx),
|
|
red_(red),
|
|
report_perf_stats_(report_perf_stats),
|
|
sender_call_(nullptr),
|
|
send_stream_(nullptr),
|
|
send_transport_(nullptr),
|
|
send_simulated_network_(nullptr),
|
|
start_bitrate_bps_(start_bitrate_bps),
|
|
min_run_time_ms_(min_run_time_ms),
|
|
expected_bitrate_bps_(0),
|
|
test_start_ms_(-1),
|
|
ramp_up_finished_ms_(-1),
|
|
extension_type_(extension_type),
|
|
video_ssrcs_(GenerateSsrcs(num_video_streams_, 100)),
|
|
video_rtx_ssrcs_(GenerateSsrcs(num_video_streams_, 200)),
|
|
audio_ssrcs_(GenerateSsrcs(num_audio_streams_, 300)),
|
|
task_queue_(task_queue) {
|
|
if (red_)
|
|
EXPECT_EQ(0u, num_flexfec_streams_);
|
|
EXPECT_LE(num_audio_streams_, 1u);
|
|
}
|
|
|
|
RampUpTester::~RampUpTester() = default;
|
|
|
|
void RampUpTester::ModifySenderBitrateConfig(
|
|
BitrateConstraints* bitrate_config) {
|
|
if (start_bitrate_bps_ != 0) {
|
|
bitrate_config->start_bitrate_bps = start_bitrate_bps_;
|
|
}
|
|
bitrate_config->min_bitrate_bps = 10000;
|
|
}
|
|
|
|
void RampUpTester::OnVideoStreamsCreated(
|
|
VideoSendStream* send_stream,
|
|
const std::vector<VideoReceiveStreamInterface*>& receive_streams) {
|
|
send_stream_ = send_stream;
|
|
}
|
|
|
|
std::unique_ptr<test::PacketTransport> RampUpTester::CreateSendTransport(
|
|
TaskQueueBase* task_queue,
|
|
Call* sender_call) {
|
|
auto network = std::make_unique<SimulatedNetwork>(forward_transport_config_);
|
|
send_simulated_network_ = network.get();
|
|
auto send_transport = std::make_unique<test::PacketTransport>(
|
|
task_queue, sender_call, this, test::PacketTransport::kSender,
|
|
test::CallTest::payload_type_map_,
|
|
std::make_unique<FakeNetworkPipe>(Clock::GetRealTimeClock(),
|
|
std::move(network)));
|
|
send_transport_ = send_transport.get();
|
|
return send_transport;
|
|
}
|
|
|
|
size_t RampUpTester::GetNumVideoStreams() const {
|
|
return num_video_streams_;
|
|
}
|
|
|
|
size_t RampUpTester::GetNumAudioStreams() const {
|
|
return num_audio_streams_;
|
|
}
|
|
|
|
size_t RampUpTester::GetNumFlexfecStreams() const {
|
|
return num_flexfec_streams_;
|
|
}
|
|
|
|
class RampUpTester::VideoStreamFactory
|
|
: public VideoEncoderConfig::VideoStreamFactoryInterface {
|
|
public:
|
|
VideoStreamFactory() {}
|
|
|
|
private:
|
|
std::vector<VideoStream> CreateEncoderStreams(
|
|
int frame_width,
|
|
int frame_height,
|
|
const VideoEncoderConfig& encoder_config) override {
|
|
std::vector<VideoStream> streams =
|
|
test::CreateVideoStreams(frame_width, frame_height, encoder_config);
|
|
if (encoder_config.number_of_streams == 1) {
|
|
streams[0].target_bitrate_bps = streams[0].max_bitrate_bps = 2000000;
|
|
}
|
|
return streams;
|
|
}
|
|
};
|
|
|
|
void RampUpTester::ModifyVideoConfigs(
|
|
VideoSendStream::Config* send_config,
|
|
std::vector<VideoReceiveStreamInterface::Config>* receive_configs,
|
|
VideoEncoderConfig* encoder_config) {
|
|
send_config->suspend_below_min_bitrate = true;
|
|
encoder_config->number_of_streams = num_video_streams_;
|
|
encoder_config->max_bitrate_bps = 2000000;
|
|
encoder_config->video_stream_factory =
|
|
rtc::make_ref_counted<RampUpTester::VideoStreamFactory>();
|
|
if (num_video_streams_ == 1) {
|
|
// For single stream rampup until 1mbps
|
|
expected_bitrate_bps_ = kSingleStreamTargetBps;
|
|
} else {
|
|
// To ensure simulcast rate allocation.
|
|
send_config->rtp.payload_name = "VP8";
|
|
encoder_config->codec_type = kVideoCodecVP8;
|
|
std::vector<VideoStream> streams = test::CreateVideoStreams(
|
|
test::CallTest::kDefaultWidth, test::CallTest::kDefaultHeight,
|
|
*encoder_config);
|
|
// For multi stream rampup until all streams are being sent. That means
|
|
// enough bitrate to send all the target streams plus the min bitrate of
|
|
// the last one.
|
|
expected_bitrate_bps_ = streams.back().min_bitrate_bps;
|
|
for (size_t i = 0; i < streams.size() - 1; ++i) {
|
|
expected_bitrate_bps_ += streams[i].target_bitrate_bps;
|
|
}
|
|
}
|
|
|
|
send_config->rtp.extensions.clear();
|
|
|
|
bool transport_cc;
|
|
if (extension_type_ == RtpExtension::kAbsSendTimeUri) {
|
|
transport_cc = false;
|
|
send_config->rtp.extensions.push_back(
|
|
RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
|
|
} else if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
|
|
transport_cc = true;
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
extension_type_.c_str(), kTransportSequenceNumberExtensionId));
|
|
} else {
|
|
transport_cc = false;
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
extension_type_.c_str(), kTransmissionTimeOffsetExtensionId));
|
|
}
|
|
|
|
send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
|
|
send_config->rtp.ssrcs = video_ssrcs_;
|
|
if (rtx_) {
|
|
send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
|
|
send_config->rtp.rtx.ssrcs = video_rtx_ssrcs_;
|
|
}
|
|
if (red_) {
|
|
send_config->rtp.ulpfec.ulpfec_payload_type =
|
|
test::CallTest::kUlpfecPayloadType;
|
|
send_config->rtp.ulpfec.red_payload_type = test::CallTest::kRedPayloadType;
|
|
if (rtx_) {
|
|
send_config->rtp.ulpfec.red_rtx_payload_type =
|
|
test::CallTest::kRtxRedPayloadType;
|
|
}
|
|
}
|
|
|
|
size_t i = 0;
|
|
for (VideoReceiveStreamInterface::Config& recv_config : *receive_configs) {
|
|
recv_config.rtp.transport_cc = transport_cc;
|
|
recv_config.rtp.extensions = send_config->rtp.extensions;
|
|
recv_config.decoders.reserve(1);
|
|
recv_config.decoders[0].payload_type = send_config->rtp.payload_type;
|
|
recv_config.decoders[0].video_format =
|
|
SdpVideoFormat(send_config->rtp.payload_name);
|
|
|
|
recv_config.rtp.remote_ssrc = video_ssrcs_[i];
|
|
recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms;
|
|
|
|
if (red_) {
|
|
recv_config.rtp.red_payload_type =
|
|
send_config->rtp.ulpfec.red_payload_type;
|
|
recv_config.rtp.ulpfec_payload_type =
|
|
send_config->rtp.ulpfec.ulpfec_payload_type;
|
|
if (rtx_) {
|
|
recv_config.rtp.rtx_associated_payload_types
|
|
[send_config->rtp.ulpfec.red_rtx_payload_type] =
|
|
send_config->rtp.ulpfec.red_payload_type;
|
|
}
|
|
}
|
|
|
|
if (rtx_) {
|
|
recv_config.rtp.rtx_ssrc = video_rtx_ssrcs_[i];
|
|
recv_config.rtp
|
|
.rtx_associated_payload_types[send_config->rtp.rtx.payload_type] =
|
|
send_config->rtp.payload_type;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
RTC_DCHECK_LE(num_flexfec_streams_, 1);
|
|
if (num_flexfec_streams_ == 1) {
|
|
send_config->rtp.flexfec.payload_type = test::CallTest::kFlexfecPayloadType;
|
|
send_config->rtp.flexfec.ssrc = test::CallTest::kFlexfecSendSsrc;
|
|
send_config->rtp.flexfec.protected_media_ssrcs = {video_ssrcs_[0]};
|
|
}
|
|
}
|
|
|
|
void RampUpTester::ModifyAudioConfigs(
|
|
AudioSendStream::Config* send_config,
|
|
std::vector<AudioReceiveStreamInterface::Config>* receive_configs) {
|
|
if (num_audio_streams_ == 0)
|
|
return;
|
|
|
|
EXPECT_NE(RtpExtension::kTimestampOffsetUri, extension_type_)
|
|
<< "Audio BWE not supported with toffset.";
|
|
EXPECT_NE(RtpExtension::kAbsSendTimeUri, extension_type_)
|
|
<< "Audio BWE not supported with abs-send-time.";
|
|
|
|
send_config->rtp.ssrc = audio_ssrcs_[0];
|
|
send_config->rtp.extensions.clear();
|
|
|
|
send_config->min_bitrate_bps = 6000;
|
|
send_config->max_bitrate_bps = 60000;
|
|
|
|
bool transport_cc = false;
|
|
if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
|
|
transport_cc = true;
|
|
send_config->rtp.extensions.push_back(RtpExtension(
|
|
extension_type_.c_str(), kTransportSequenceNumberExtensionId));
|
|
}
|
|
|
|
for (AudioReceiveStreamInterface::Config& recv_config : *receive_configs) {
|
|
recv_config.rtp.transport_cc = transport_cc;
|
|
recv_config.rtp.extensions = send_config->rtp.extensions;
|
|
recv_config.rtp.remote_ssrc = send_config->rtp.ssrc;
|
|
}
|
|
}
|
|
|
|
void RampUpTester::ModifyFlexfecConfigs(
|
|
std::vector<FlexfecReceiveStream::Config>* receive_configs) {
|
|
if (num_flexfec_streams_ == 0)
|
|
return;
|
|
RTC_DCHECK_EQ(1, num_flexfec_streams_);
|
|
(*receive_configs)[0].payload_type = test::CallTest::kFlexfecPayloadType;
|
|
(*receive_configs)[0].rtp.remote_ssrc = test::CallTest::kFlexfecSendSsrc;
|
|
(*receive_configs)[0].protected_media_ssrcs = {video_ssrcs_[0]};
|
|
(*receive_configs)[0].rtp.local_ssrc = video_ssrcs_[0];
|
|
if (extension_type_ == RtpExtension::kAbsSendTimeUri) {
|
|
(*receive_configs)[0].rtp.transport_cc = false;
|
|
(*receive_configs)[0].rtp.extensions.push_back(
|
|
RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
|
|
} else if (extension_type_ == RtpExtension::kTransportSequenceNumberUri) {
|
|
(*receive_configs)[0].rtp.transport_cc = true;
|
|
(*receive_configs)[0].rtp.extensions.push_back(RtpExtension(
|
|
extension_type_.c_str(), kTransportSequenceNumberExtensionId));
|
|
}
|
|
}
|
|
|
|
void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) {
|
|
RTC_DCHECK(sender_call);
|
|
sender_call_ = sender_call;
|
|
pending_task_ = RepeatingTaskHandle::Start(task_queue_, [this] {
|
|
PollStats();
|
|
return kPollInterval;
|
|
});
|
|
}
|
|
|
|
void RampUpTester::PollStats() {
|
|
RTC_DCHECK_RUN_ON(task_queue_);
|
|
|
|
Call::Stats stats = sender_call_->GetStats();
|
|
EXPECT_GE(expected_bitrate_bps_, 0);
|
|
|
|
if (stats.send_bandwidth_bps >= expected_bitrate_bps_ &&
|
|
(min_run_time_ms_ == -1 ||
|
|
clock_->TimeInMilliseconds() - test_start_ms_ >= min_run_time_ms_)) {
|
|
ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
|
|
observation_complete_.Set();
|
|
pending_task_.Stop();
|
|
}
|
|
}
|
|
|
|
void RampUpTester::ReportResult(
|
|
absl::string_view measurement,
|
|
size_t value,
|
|
Unit unit,
|
|
ImprovementDirection improvement_direction) const {
|
|
GetGlobalMetricsLogger()->LogSingleValueMetric(
|
|
measurement,
|
|
::testing::UnitTest::GetInstance()->current_test_info()->name(), value,
|
|
unit, improvement_direction);
|
|
}
|
|
|
|
void RampUpTester::AccumulateStats(const VideoSendStream::StreamStats& stream,
|
|
size_t* total_packets_sent,
|
|
size_t* total_sent,
|
|
size_t* padding_sent,
|
|
size_t* media_sent) const {
|
|
*total_packets_sent += stream.rtp_stats.transmitted.packets +
|
|
stream.rtp_stats.retransmitted.packets +
|
|
stream.rtp_stats.fec.packets;
|
|
*total_sent += stream.rtp_stats.transmitted.TotalBytes() +
|
|
stream.rtp_stats.retransmitted.TotalBytes() +
|
|
stream.rtp_stats.fec.TotalBytes();
|
|
*padding_sent += stream.rtp_stats.transmitted.padding_bytes +
|
|
stream.rtp_stats.retransmitted.padding_bytes +
|
|
stream.rtp_stats.fec.padding_bytes;
|
|
*media_sent += stream.rtp_stats.MediaPayloadBytes();
|
|
}
|
|
|
|
void RampUpTester::TriggerTestDone() {
|
|
RTC_DCHECK_GE(test_start_ms_, 0);
|
|
|
|
// Stop polling stats.
|
|
// Corner case for field_trials=WebRTC-QuickPerfTest/Enabled/
|
|
SendTask(task_queue_, [this] { pending_task_.Stop(); });
|
|
|
|
// TODO(holmer): Add audio send stats here too when those APIs are available.
|
|
if (!send_stream_)
|
|
return;
|
|
|
|
VideoSendStream::Stats send_stats;
|
|
SendTask(task_queue_, [&] { send_stats = send_stream_->GetStats(); });
|
|
|
|
send_stream_ = nullptr; // To avoid dereferencing a bad pointer.
|
|
|
|
size_t total_packets_sent = 0;
|
|
size_t total_sent = 0;
|
|
size_t padding_sent = 0;
|
|
size_t media_sent = 0;
|
|
for (uint32_t ssrc : video_ssrcs_) {
|
|
AccumulateStats(send_stats.substreams[ssrc], &total_packets_sent,
|
|
&total_sent, &padding_sent, &media_sent);
|
|
}
|
|
|
|
size_t rtx_total_packets_sent = 0;
|
|
size_t rtx_total_sent = 0;
|
|
size_t rtx_padding_sent = 0;
|
|
size_t rtx_media_sent = 0;
|
|
for (uint32_t rtx_ssrc : video_rtx_ssrcs_) {
|
|
AccumulateStats(send_stats.substreams[rtx_ssrc], &rtx_total_packets_sent,
|
|
&rtx_total_sent, &rtx_padding_sent, &rtx_media_sent);
|
|
}
|
|
|
|
if (report_perf_stats_) {
|
|
ReportResult("ramp-up-media-sent", media_sent, Unit::kBytes,
|
|
ImprovementDirection::kBiggerIsBetter);
|
|
ReportResult("ramp-up-padding-sent", padding_sent, Unit::kBytes,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, Unit::kBytes,
|
|
ImprovementDirection::kBiggerIsBetter);
|
|
ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, Unit::kBytes,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
if (ramp_up_finished_ms_ >= 0) {
|
|
ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_,
|
|
Unit::kMilliseconds, ImprovementDirection::kSmallerIsBetter);
|
|
}
|
|
ReportResult("ramp-up-average-network-latency",
|
|
send_transport_->GetAverageDelayMs(), Unit::kMilliseconds,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
}
|
|
}
|
|
|
|
void RampUpTester::PerformTest() {
|
|
test_start_ms_ = clock_->TimeInMilliseconds();
|
|
EXPECT_TRUE(Wait()) << "Timed out while waiting for ramp-up to complete.";
|
|
TriggerTestDone();
|
|
}
|
|
|
|
RampUpDownUpTester::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)
|
|
: RampUpTester(num_video_streams,
|
|
num_audio_streams,
|
|
num_flexfec_streams,
|
|
start_bitrate_bps,
|
|
0,
|
|
extension_type,
|
|
rtx,
|
|
red,
|
|
report_perf_stats,
|
|
task_queue),
|
|
link_rates_({4 * GetExpectedHighBitrate() / (3 * 1000),
|
|
kLowBandwidthLimitBps / 1000,
|
|
4 * GetExpectedHighBitrate() / (3 * 1000), 0}),
|
|
test_state_(kFirstRampup),
|
|
next_state_(kTransitionToNextState),
|
|
state_start_ms_(clock_->TimeInMilliseconds()),
|
|
interval_start_ms_(clock_->TimeInMilliseconds()),
|
|
sent_bytes_(0),
|
|
loss_rates_(loss_rates) {
|
|
forward_transport_config_.link_capacity_kbps = link_rates_[test_state_];
|
|
forward_transport_config_.queue_delay_ms = 100;
|
|
forward_transport_config_.loss_percent = loss_rates_[test_state_];
|
|
}
|
|
|
|
RampUpDownUpTester::~RampUpDownUpTester() {}
|
|
|
|
void RampUpDownUpTester::PollStats() {
|
|
if (test_state_ == kTestEnd) {
|
|
pending_task_.Stop();
|
|
}
|
|
|
|
int transmit_bitrate_bps = 0;
|
|
bool suspended = false;
|
|
if (num_video_streams_ > 0 && send_stream_) {
|
|
webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
|
|
for (const auto& it : stats.substreams) {
|
|
transmit_bitrate_bps += it.second.total_bitrate_bps;
|
|
}
|
|
suspended = stats.suspended;
|
|
}
|
|
if (num_audio_streams_ > 0 && sender_call_) {
|
|
// An audio send stream doesn't have bitrate stats, so the call send BW is
|
|
// currently used instead.
|
|
transmit_bitrate_bps = sender_call_->GetStats().send_bandwidth_bps;
|
|
}
|
|
|
|
EvolveTestState(transmit_bitrate_bps, suspended);
|
|
}
|
|
|
|
void RampUpDownUpTester::ModifyReceiverBitrateConfig(
|
|
BitrateConstraints* bitrate_config) {
|
|
bitrate_config->min_bitrate_bps = 10000;
|
|
}
|
|
|
|
std::string RampUpDownUpTester::GetModifierString() const {
|
|
std::string str("_");
|
|
if (num_video_streams_ > 0) {
|
|
str += rtc::ToString(num_video_streams_);
|
|
str += "stream";
|
|
str += (num_video_streams_ > 1 ? "s" : "");
|
|
str += "_";
|
|
}
|
|
if (num_audio_streams_ > 0) {
|
|
str += rtc::ToString(num_audio_streams_);
|
|
str += "stream";
|
|
str += (num_audio_streams_ > 1 ? "s" : "");
|
|
str += "_";
|
|
}
|
|
str += (rtx_ ? "" : "no");
|
|
str += "rtx_";
|
|
str += (red_ ? "" : "no");
|
|
str += "red";
|
|
return str;
|
|
}
|
|
|
|
int RampUpDownUpTester::GetExpectedHighBitrate() const {
|
|
int expected_bitrate_bps = 0;
|
|
if (num_audio_streams_ > 0)
|
|
expected_bitrate_bps += kExpectedHighAudioBitrateBps;
|
|
if (num_video_streams_ > 0)
|
|
expected_bitrate_bps += kExpectedHighVideoBitrateBps;
|
|
return expected_bitrate_bps;
|
|
}
|
|
|
|
size_t RampUpDownUpTester::GetFecBytes() const {
|
|
size_t flex_fec_bytes = 0;
|
|
if (num_flexfec_streams_ > 0) {
|
|
webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
|
|
for (const auto& kv : stats.substreams)
|
|
flex_fec_bytes += kv.second.rtp_stats.fec.TotalBytes();
|
|
}
|
|
return flex_fec_bytes;
|
|
}
|
|
|
|
bool RampUpDownUpTester::ExpectingFec() const {
|
|
return num_flexfec_streams_ > 0 && forward_transport_config_.loss_percent > 0;
|
|
}
|
|
|
|
void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) {
|
|
int64_t now = clock_->TimeInMilliseconds();
|
|
switch (test_state_) {
|
|
case kFirstRampup:
|
|
EXPECT_FALSE(suspended);
|
|
if (bitrate_bps >= GetExpectedHighBitrate()) {
|
|
if (report_perf_stats_) {
|
|
GetGlobalMetricsLogger()->LogSingleValueMetric(
|
|
"ramp_up_down_up" + GetModifierString(), "first_rampup",
|
|
now - state_start_ms_, Unit::kMilliseconds,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
}
|
|
// Apply loss during the transition between states if FEC is enabled.
|
|
forward_transport_config_.loss_percent = loss_rates_[test_state_];
|
|
test_state_ = kTransitionToNextState;
|
|
next_state_ = kLowRate;
|
|
}
|
|
break;
|
|
case kLowRate: {
|
|
// Audio streams are never suspended.
|
|
bool check_suspend_state = num_video_streams_ > 0;
|
|
if (bitrate_bps < kLowBandwidthLimitBps + kLowBitrateMarginBps &&
|
|
suspended == check_suspend_state) {
|
|
if (report_perf_stats_) {
|
|
GetGlobalMetricsLogger()->LogSingleValueMetric(
|
|
"ramp_up_down_up" + GetModifierString(), "rampdown",
|
|
now - state_start_ms_, Unit::kMilliseconds,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
}
|
|
// Apply loss during the transition between states if FEC is enabled.
|
|
forward_transport_config_.loss_percent = loss_rates_[test_state_];
|
|
test_state_ = kTransitionToNextState;
|
|
next_state_ = kSecondRampup;
|
|
}
|
|
break;
|
|
}
|
|
case kSecondRampup:
|
|
if (bitrate_bps >= GetExpectedHighBitrate() && !suspended) {
|
|
if (report_perf_stats_) {
|
|
GetGlobalMetricsLogger()->LogSingleValueMetric(
|
|
"ramp_up_down_up" + GetModifierString(), "second_rampup",
|
|
now - state_start_ms_, Unit::kMilliseconds,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
ReportResult("ramp-up-down-up-average-network-latency",
|
|
send_transport_->GetAverageDelayMs(),
|
|
Unit::kMilliseconds,
|
|
ImprovementDirection::kSmallerIsBetter);
|
|
}
|
|
// Apply loss during the transition between states if FEC is enabled.
|
|
forward_transport_config_.loss_percent = loss_rates_[test_state_];
|
|
test_state_ = kTransitionToNextState;
|
|
next_state_ = kTestEnd;
|
|
}
|
|
break;
|
|
case kTestEnd:
|
|
observation_complete_.Set();
|
|
break;
|
|
case kTransitionToNextState:
|
|
if (!ExpectingFec() || GetFecBytes() > 0) {
|
|
test_state_ = next_state_;
|
|
forward_transport_config_.link_capacity_kbps = link_rates_[test_state_];
|
|
// No loss while ramping up and down as it may affect the BWE
|
|
// negatively, making the test flaky.
|
|
forward_transport_config_.loss_percent = 0;
|
|
state_start_ms_ = now;
|
|
interval_start_ms_ = now;
|
|
sent_bytes_ = 0;
|
|
send_simulated_network_->SetConfig(forward_transport_config_);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
class RampUpTest : public test::CallTest {
|
|
public:
|
|
RampUpTest()
|
|
: task_queue_factory_(CreateDefaultTaskQueueFactory()),
|
|
rtc_event_log_factory_(task_queue_factory_.get()) {
|
|
std::string dump_name(absl::GetFlag(FLAGS_ramp_dump_name));
|
|
if (!dump_name.empty()) {
|
|
send_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
|
|
RtcEventLog::EncodingType::Legacy);
|
|
recv_event_log_ = rtc_event_log_factory_.CreateRtcEventLog(
|
|
RtcEventLog::EncodingType::Legacy);
|
|
bool event_log_started =
|
|
send_event_log_->StartLogging(
|
|
std::make_unique<RtcEventLogOutputFile>(
|
|
dump_name + ".send.rtc.dat", RtcEventLog::kUnlimitedOutput),
|
|
RtcEventLog::kImmediateOutput) &&
|
|
recv_event_log_->StartLogging(
|
|
std::make_unique<RtcEventLogOutputFile>(
|
|
dump_name + ".recv.rtc.dat", RtcEventLog::kUnlimitedOutput),
|
|
RtcEventLog::kImmediateOutput);
|
|
RTC_DCHECK(event_log_started);
|
|
}
|
|
}
|
|
|
|
private:
|
|
const std::unique_ptr<TaskQueueFactory> task_queue_factory_;
|
|
RtcEventLogFactory rtc_event_log_factory_;
|
|
};
|
|
|
|
static const uint32_t kStartBitrateBps = 60000;
|
|
|
|
TEST_F(RampUpTest, UpDownUpAbsSendTimeSimulcastRedRtx) {
|
|
std::vector<int> loss_rates = {0, 0, 0, 0};
|
|
RampUpDownUpTester test(3, 0, 0, kStartBitrateBps,
|
|
RtpExtension::kAbsSendTimeUri, true, true, loss_rates,
|
|
true, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
// TODO(bugs.webrtc.org/8878)
|
|
#if defined(WEBRTC_MAC)
|
|
#define MAYBE_UpDownUpTransportSequenceNumberRtx \
|
|
DISABLED_UpDownUpTransportSequenceNumberRtx
|
|
#else
|
|
#define MAYBE_UpDownUpTransportSequenceNumberRtx \
|
|
UpDownUpTransportSequenceNumberRtx
|
|
#endif
|
|
TEST_F(RampUpTest, MAYBE_UpDownUpTransportSequenceNumberRtx) {
|
|
std::vector<int> loss_rates = {0, 0, 0, 0};
|
|
RampUpDownUpTester test(3, 0, 0, kStartBitrateBps,
|
|
RtpExtension::kTransportSequenceNumberUri, true,
|
|
false, loss_rates, true, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
// TODO(holmer): Tests which don't report perf stats should be moved to a
|
|
// different executable since they per definition are not perf tests.
|
|
// This test is disabled because it crashes on Linux, and is flaky on other
|
|
// platforms. See: crbug.com/webrtc/7919
|
|
TEST_F(RampUpTest, DISABLED_UpDownUpTransportSequenceNumberPacketLoss) {
|
|
std::vector<int> loss_rates = {20, 0, 0, 0};
|
|
RampUpDownUpTester test(1, 0, 1, kStartBitrateBps,
|
|
RtpExtension::kTransportSequenceNumberUri, true,
|
|
false, loss_rates, false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
// TODO(bugs.webrtc.org/8878)
|
|
#if defined(WEBRTC_MAC)
|
|
#define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \
|
|
DISABLED_UpDownUpAudioVideoTransportSequenceNumberRtx
|
|
#else
|
|
#define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \
|
|
UpDownUpAudioVideoTransportSequenceNumberRtx
|
|
#endif
|
|
TEST_F(RampUpTest, MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx) {
|
|
std::vector<int> loss_rates = {0, 0, 0, 0};
|
|
RampUpDownUpTester test(3, 1, 0, kStartBitrateBps,
|
|
RtpExtension::kTransportSequenceNumberUri, true,
|
|
false, loss_rates, false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, UpDownUpAudioTransportSequenceNumberRtx) {
|
|
std::vector<int> loss_rates = {0, 0, 0, 0};
|
|
RampUpDownUpTester test(0, 1, 0, kStartBitrateBps,
|
|
RtpExtension::kTransportSequenceNumberUri, true,
|
|
false, loss_rates, false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, TOffsetSimulcastRedRtx) {
|
|
RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTimestampOffsetUri, true,
|
|
true, true, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, AbsSendTime) {
|
|
RampUpTester test(1, 0, 0, 0, 0, RtpExtension::kAbsSendTimeUri, false, false,
|
|
false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, AbsSendTimeSimulcastRedRtx) {
|
|
RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kAbsSendTimeUri, true, true,
|
|
true, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, TransportSequenceNumber) {
|
|
RampUpTester test(1, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
|
|
false, false, false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
|
|
RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
|
|
false, false, false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, TransportSequenceNumberSimulcastRedRtx) {
|
|
RampUpTester test(3, 0, 0, 0, 0, RtpExtension::kTransportSequenceNumberUri,
|
|
true, true, true, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(RampUpTest, AudioTransportSequenceNumber) {
|
|
RampUpTester test(0, 1, 0, 300000, 10000,
|
|
RtpExtension::kTransportSequenceNumberUri, false, false,
|
|
false, task_queue());
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
} // namespace webrtc
|